Objectify and clean up bootstrap programs.
Refactor a lot of idl.h/idl.cpp to be more generic and make them easier for other bootstrap apps to build on. This is a precursor for building infotabs/class_map generators in cpp to remove the need for PHP during bootstrapping. I'll also be git mving this to hphp/tools/bootstrap in a follow-up move-only commit.
Esse commit está contido em:
@@ -30,6 +30,8 @@
|
||||
#include "hphp/tools/gen-ext-hhvm/idl.h"
|
||||
|
||||
using folly::fbstring;
|
||||
using namespace HPHP::IDL;
|
||||
using namespace HPHP;
|
||||
|
||||
std::unordered_map<fbstring, const PhpFunc*> g_mangleMap;
|
||||
std::unordered_map<fbstring, const PhpClass*> g_classMap;
|
||||
@@ -75,22 +77,24 @@ void emitRemappedFuncDecl(const PhpFunc& func,
|
||||
const fbstring& mangled,
|
||||
const fbstring& prefix,
|
||||
std::ostream& out) {
|
||||
if (isTypeCppIndirectPass(func.returnCppType)) {
|
||||
if (func.returnCppType == "HPHP::Variant") {
|
||||
int returnKindOf = func.returnKindOf();
|
||||
bool indirectReturn = func.isIndirectReturn();
|
||||
if (indirectReturn) {
|
||||
if (returnKindOf == KindOfAny) {
|
||||
out << "TypedValue* ";
|
||||
} else {
|
||||
out << "Value* ";
|
||||
}
|
||||
} else {
|
||||
out << func.returnCppType << ' ';
|
||||
out << func.returnCppType() << ' ';
|
||||
}
|
||||
|
||||
out << prefix << func.getUniqueName() << '(';
|
||||
|
||||
bool isFirstParam = true;
|
||||
|
||||
if (!g_armMode && isTypeCppIndirectPass(func.returnCppType)) {
|
||||
if (func.returnCppType == "HPHP::Variant") {
|
||||
if (!g_armMode && indirectReturn) {
|
||||
if (func.returnKindOf() == KindOfAny) {
|
||||
out << "TypedValue* _rv";
|
||||
} else {
|
||||
out << "Value* _rv";
|
||||
@@ -98,7 +102,7 @@ void emitRemappedFuncDecl(const PhpFunc& func,
|
||||
isFirstParam = false;
|
||||
}
|
||||
|
||||
if (!func.className.empty() && !func.isStatic) {
|
||||
if (func.usesThis()) {
|
||||
if (!isFirstParam) {
|
||||
out << ", ";
|
||||
}
|
||||
@@ -106,7 +110,7 @@ void emitRemappedFuncDecl(const PhpFunc& func,
|
||||
isFirstParam = false;
|
||||
}
|
||||
|
||||
if (func.isVarargs) {
|
||||
if (func.isVarArgs()) {
|
||||
if (!isFirstParam) {
|
||||
out << ", ";
|
||||
}
|
||||
@@ -114,26 +118,25 @@ void emitRemappedFuncDecl(const PhpFunc& func,
|
||||
isFirstParam = false;
|
||||
}
|
||||
|
||||
for (auto const& param : func.params) {
|
||||
for (auto const& param : func.params()) {
|
||||
if (!isFirstParam) {
|
||||
out << ", ";
|
||||
}
|
||||
if (isTypeCppIndirectPass(param.cppType)) {
|
||||
if (param.cppType == "HPHP::Variant" ||
|
||||
param.cppType == "HPHP::Variant const&" ||
|
||||
param.cppType == "HPHP::VRefParamValue const&") {
|
||||
auto kindof = param.kindOf();
|
||||
if (param.isIndirectPass()) {
|
||||
if (kindof == KindOfAny || kindof == KindOfRef) {
|
||||
out << "TypedValue*";
|
||||
} else {
|
||||
out << "Value*";
|
||||
}
|
||||
} else {
|
||||
out << param.cppType;
|
||||
out << param.getCppType();
|
||||
}
|
||||
out << ' ' << param.name;
|
||||
out << ' ' << param.name();
|
||||
isFirstParam = false;
|
||||
}
|
||||
|
||||
if (func.isVarargs) {
|
||||
if (func.isVarArgs()) {
|
||||
assert(!isFirstParam);
|
||||
out << ", Value* _argv";
|
||||
}
|
||||
@@ -147,41 +150,20 @@ void emitCast(const PhpParam& param, int32_t index, std::ostream& out,
|
||||
const char* ind, bool doCheck) {
|
||||
if (doCheck) {
|
||||
out << ind << "if (";
|
||||
if (param.cppType == "HPHP::String const&") {
|
||||
if (param.kindOf() == KindOfString) {
|
||||
out << "!IS_STRING_TYPE((args-" << index << ")->m_type)";
|
||||
} else {
|
||||
out << "(args-" << index << ")->m_type != ";
|
||||
if (param.cppType == "bool") {
|
||||
out << "KindOfBoolean";
|
||||
} else if (param.cppType == "int" || param.cppType == "long") {
|
||||
out << "KindOfInt64";
|
||||
} else if (param.cppType == "double") {
|
||||
out << "KindOfDouble";
|
||||
} else if (param.cppType == "HPHP::Array const&") {
|
||||
out << "KindOfArray";
|
||||
} else if (param.cppType == "HPHP::Object const&") {
|
||||
out << "KindOfObject";
|
||||
}
|
||||
out << "(args-" << index << ")->m_type != KindOf"
|
||||
<< kindOfString(param.kindOf());
|
||||
}
|
||||
out << ") {\n";
|
||||
ind -= 2;
|
||||
}
|
||||
|
||||
out << ind << "tvCastTo";
|
||||
if (param.cppType == "bool") {
|
||||
out << "Boolean";
|
||||
} else if (param.cppType == "int" || param.cppType == "long") {
|
||||
out << "Int64";
|
||||
} else if (param.cppType == "double") {
|
||||
out << "Double";
|
||||
} else if (param.cppType == "HPHP::String const&") {
|
||||
out << "String";
|
||||
} else if (param.cppType == "HPHP::Array const&") {
|
||||
out << "Array";
|
||||
} else if (param.cppType == "HPHP::Object const&") {
|
||||
out << "Object";
|
||||
if (param.kindOf() != KindOfAny) {
|
||||
out << ind << "tvCastTo" << kindOfString(param.kindOf())
|
||||
<< "InPlace(args-" << index << ");\n";
|
||||
}
|
||||
out << "InPlace(args-" << index << ");\n";
|
||||
|
||||
if (doCheck) {
|
||||
ind += 2;
|
||||
@@ -195,11 +177,10 @@ void emitCast(const PhpParam& param, int32_t index, std::ostream& out,
|
||||
*/
|
||||
void emitTypechecks(const PhpFunc& func, std::ostream& out, const char* ind) {
|
||||
bool isFirstParam = true;
|
||||
for (int k = func.maxNumParams - 1; k >= 0; --k) {
|
||||
auto const& param = func.params[k];
|
||||
if (param.cppType == "HPHP::Variant" ||
|
||||
param.cppType == "HPHP::Variant const&" ||
|
||||
param.cppType == "HPHP::VRefParamValue const&") {
|
||||
for (int k = func.numParams() - 1; k >= 0; --k) {
|
||||
auto const& param = func.param(k);
|
||||
auto kindof = param.kindOf();
|
||||
if (kindof == KindOfAny || kindof == KindOfRef) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -208,25 +189,14 @@ void emitTypechecks(const PhpFunc& func, std::ostream& out, const char* ind) {
|
||||
}
|
||||
isFirstParam = false;
|
||||
|
||||
bool isOptional = (k >= func.minNumParams);
|
||||
bool isOptional = (k >= func.minNumParams());
|
||||
if (isOptional) {
|
||||
out << "(count <= " << k << " || ";
|
||||
}
|
||||
if (param.cppType == "HPHP::String const&") {
|
||||
if (kindof == KindOfString) {
|
||||
out << "IS_STRING_TYPE((args - " << k << ")->m_type)";
|
||||
} else {
|
||||
out << "(args - " << k << ")->m_type == ";
|
||||
if (param.cppType == "bool") {
|
||||
out << "KindOfBoolean";
|
||||
} else if (param.cppType == "int" || param.cppType == "long") {
|
||||
out << "KindOfInt64";
|
||||
} else if (param.cppType == "double") {
|
||||
out << "KindOfDouble";
|
||||
} else if (param.cppType == "HPHP::Array const&") {
|
||||
out << "KindOfArray";
|
||||
} else if (param.cppType == "HPHP::Object const&") {
|
||||
out << "KindOfObject";
|
||||
}
|
||||
out << "(args - " << k << ")->m_type == KindOf" << kindOfString(kindof);
|
||||
}
|
||||
|
||||
if (isOptional) {
|
||||
@@ -258,7 +228,7 @@ void emitBuildExtraArgs(const PhpFunc& func, std::ostream& out,
|
||||
{0}}}
|
||||
)",
|
||||
ind,
|
||||
func.maxNumParams
|
||||
func.numParams()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -268,16 +238,16 @@ void emitCallExpression(const PhpFunc& func, const fbstring& prefix,
|
||||
out << prefix << func.getUniqueName() << '(';
|
||||
|
||||
bool isFirstParam = true;
|
||||
if (!g_armMode && isTypeCppIndirectPass(func.returnCppType)) {
|
||||
if (!g_armMode && func.isIndirectReturn()) {
|
||||
isFirstParam = false;
|
||||
if (func.returnCppType == "HPHP::Variant") {
|
||||
if (func.returnKindOf() == KindOfAny) {
|
||||
out << "rv";
|
||||
} else {
|
||||
out << "&(rv->m_data)";
|
||||
}
|
||||
}
|
||||
|
||||
if (!func.className.empty() && !func.isStatic) {
|
||||
if (func.usesThis()) {
|
||||
if (!isFirstParam) {
|
||||
out << ", ";
|
||||
}
|
||||
@@ -285,7 +255,7 @@ void emitCallExpression(const PhpFunc& func, const fbstring& prefix,
|
||||
out << "(this_)";
|
||||
}
|
||||
|
||||
if (func.isVarargs) {
|
||||
if (func.isVarArgs()) {
|
||||
if (!isFirstParam) {
|
||||
out << ", ";
|
||||
}
|
||||
@@ -293,58 +263,54 @@ void emitCallExpression(const PhpFunc& func, const fbstring& prefix,
|
||||
out << "count";
|
||||
}
|
||||
|
||||
for (auto k = 0; k < func.params.size(); ++k) {
|
||||
auto const& param = func.params[k];
|
||||
for (auto k = 0; k < func.numParams(); ++k) {
|
||||
auto const& param = func.param(k);
|
||||
if (!isFirstParam) {
|
||||
out << ", ";
|
||||
}
|
||||
isFirstParam = false;
|
||||
|
||||
if (!param.defVal.empty()) {
|
||||
if (param.hasDefault()) {
|
||||
out << "(count > " << k << ") ? ";
|
||||
}
|
||||
|
||||
if (isTypeCppIndirectPass(param.cppType)) {
|
||||
if (param.cppType == "HPHP::Variant" ||
|
||||
param.cppType == "HPHP::Variant const&" ||
|
||||
param.cppType == "HPHP::VRefParamValue const&") {
|
||||
if (param.isIndirectPass()) {
|
||||
auto kindof = param.kindOf();
|
||||
if (kindof == KindOfAny || kindof == KindOfRef) {
|
||||
out << "(args-" << k << ')';
|
||||
} else {
|
||||
out << "&args[-" << k << "].m_data";
|
||||
}
|
||||
} else {
|
||||
if (param.cppType == "double") {
|
||||
if (param.kindOf() == KindOfDouble) {
|
||||
out << "(args[-" << k << "].m_data.dbl)";
|
||||
} else {
|
||||
out << '(' << param.cppType << ")(args[-" << k << "].m_data.num)";
|
||||
out << '(' << param.getCppType() << ")(args[-" << k << "].m_data.num)";
|
||||
}
|
||||
}
|
||||
|
||||
if (!param.defVal.empty()) {
|
||||
if (param.hasDefault()) {
|
||||
out << " : ";
|
||||
if (param.defValNeedsVariable()) {
|
||||
if (param.cppType == "HPHP::Variant" ||
|
||||
param.cppType == "HPHP::Variant const&" ||
|
||||
param.cppType == "HPHP::VRefParamValue const&") {
|
||||
auto kindof = param.kindOf();
|
||||
if (param.defValueNeedsVariable()) {
|
||||
if (kindof == KindOfAny || kindof == KindOfRef) {
|
||||
out << "(TypedValue*)(&defVal" << k << ')';
|
||||
} else {
|
||||
out << "(Value*)(&defVal" << k << ')';
|
||||
}
|
||||
} else if (isTypeCppIndirectPass(param.cppType)) {
|
||||
if (param.cppType == "HPHP::Variant" ||
|
||||
param.cppType == "HPHP::Variant const&" ||
|
||||
param.cppType == "HPHP::VRefParamValue const&") {
|
||||
out << "(TypedValue*)(&" << param.defVal << ')';
|
||||
} else if (param.isIndirectPass()) {
|
||||
if (kindof == KindOfAny || kindof == KindOfRef) {
|
||||
out << "(TypedValue*)(&" << param.getDefault() << ')';
|
||||
} else {
|
||||
out << "(Value*)(&" << param.defVal << ')';
|
||||
out << "(Value*)(&" << param.getDefault() << ')';
|
||||
}
|
||||
} else {
|
||||
out << '(' << param.cppType << ")(" << param.defVal << ')';
|
||||
out << '(' << param.getCppType() << ")(" << param.getDefault() << ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (func.isVarargs) {
|
||||
if (func.isVarArgs()) {
|
||||
assert(!isFirstParam);
|
||||
out << ", (Value*)(&extraArgs)";
|
||||
}
|
||||
@@ -364,60 +330,56 @@ void emitExtCall(const PhpFunc& func, std::ostream& out, const char* ind) {
|
||||
|
||||
// Set up the type of the return value, and emit post-call code to normalize
|
||||
// return types and values
|
||||
if (func.returnCppType == "bool") {
|
||||
auto returnKindOf = func.returnKindOf();
|
||||
if (returnKindOf == KindOfBoolean) {
|
||||
out << ind << "rv->m_type = KindOfBoolean;\n";
|
||||
call_prefix = "rv->m_data.num = (";
|
||||
call_suffix = ") ? 1LL : 0LL;\n";
|
||||
} else if (func.returnCppType == "int" || func.returnCppType == "long") {
|
||||
} else if (returnKindOf == KindOfInt64) {
|
||||
out << ind << "rv->m_type = KindOfInt64;\n";
|
||||
call_prefix = "rv->m_data.num = (int64_t)";
|
||||
call_suffix = ";\n";
|
||||
} else if (func.returnCppType == "double") {
|
||||
} else if (returnKindOf == KindOfDouble) {
|
||||
out << ind << "rv->m_type = KindOfDouble;\n";
|
||||
call_prefix = "rv->m_data.dbl = ";
|
||||
call_suffix = ";\n";
|
||||
} else if (func.returnCppType == "void") {
|
||||
} else if (returnKindOf == KindOfInvalid || returnKindOf == KindOfNull) {
|
||||
out << ind << "rv->m_type = KindOfNull;\n";
|
||||
call_suffix = ";\n";
|
||||
} else if (func.returnCppType == "HPHP::String") {
|
||||
} else if (returnKindOf == KindOfString) {
|
||||
out << ind << "rv->m_type = KindOfString;\n";
|
||||
call_suffix = (fbstring(";\n") + ind +
|
||||
"if (rv->m_data.num == 0LL) rv->m_type = KindOfNull;\n");
|
||||
} else if (func.returnCppType == "HPHP::Array") {
|
||||
} else if (returnKindOf == KindOfArray) {
|
||||
out << ind << "rv->m_type = KindOfArray;\n";
|
||||
call_suffix = (fbstring(";\n") + ind +
|
||||
"if (rv->m_data.num == 0LL) rv->m_type = KindOfNull;\n");
|
||||
} else if (func.returnCppType == "HPHP::Object") {
|
||||
} else if (returnKindOf == KindOfObject) {
|
||||
out << ind << "rv->m_type = KindOfObject;\n";
|
||||
call_suffix = (fbstring(";\n") + ind +
|
||||
"if (rv->m_data.num == 0LL) rv->m_type = KindOfNull;\n");
|
||||
} else if (func.returnCppType == "HPHP::Variant") {
|
||||
} else {
|
||||
call_suffix = (fbstring(";\n") + ind +
|
||||
"if (rv->m_type == KindOfUninit) "
|
||||
"rv->m_type = KindOfNull;\n");
|
||||
}
|
||||
|
||||
if (func.isVarargs) {
|
||||
if (func.isVarArgs()) {
|
||||
emitBuildExtraArgs(func, out, ind);
|
||||
}
|
||||
|
||||
// If any default values need variables (because they have nontrivial values),
|
||||
// declare and initialize those
|
||||
for (auto k = 0; k < func.params.size(); ++k) {
|
||||
auto const& param = func.params[k];
|
||||
if (param.defValNeedsVariable()) {
|
||||
auto type = param.cppType;
|
||||
if (type.compare(type.length() - 7, 7, " const&") == 0) {
|
||||
type = type.substr(0, type.length() - 7);
|
||||
}
|
||||
if (type.compare(0, 6, "HPHP::") == 0) {
|
||||
type = type.substr(6);
|
||||
}
|
||||
out << ind << type << " defVal" << k;
|
||||
if (type != "Variant" ||
|
||||
(param.defVal != "null" && param.defVal != "null_variant")) {
|
||||
for (auto k = 0; k < func.numParams(); ++k) {
|
||||
auto const& param = func.param(k);
|
||||
if (param.defValueNeedsVariable()) {
|
||||
DataType kindof = param.kindOf();
|
||||
out << ind << param.getStrippedCppType() << " defVal" << k;
|
||||
fbstring defVal = param.getDefault();
|
||||
if (kindof != KindOfAny ||
|
||||
(defVal != "null" && defVal != "null_variant")) {
|
||||
out << " = ";
|
||||
out << (param.defVal == "null" ? "uninit_null()" : param.defVal);
|
||||
out << (defVal == "null" ? "uninit_null()" : defVal);
|
||||
}
|
||||
out << ";\n";
|
||||
}
|
||||
@@ -426,7 +388,7 @@ void emitExtCall(const PhpFunc& func, std::ostream& out, const char* ind) {
|
||||
// Put the return-value-space pointer into x8
|
||||
if (g_armMode) {
|
||||
out << ind << "asm volatile (\"mov x8, %0\\n\" : : \"r\"(";
|
||||
if (func.returnCppType == "HPHP::Variant") {
|
||||
if (func.returnKindOf() == KindOfAny) {
|
||||
out << "rv";
|
||||
} else {
|
||||
out << "&(rv->m_data)";
|
||||
@@ -435,29 +397,29 @@ void emitExtCall(const PhpFunc& func, std::ostream& out, const char* ind) {
|
||||
}
|
||||
|
||||
out << ind << call_prefix;
|
||||
emitCallExpression(func, func.className.empty() ? "fh_" : "th_", out);
|
||||
emitCallExpression(func, func.isMethod() ? "th_" : "fh_", out);
|
||||
out << call_suffix;
|
||||
}
|
||||
|
||||
void emitCasts(const PhpFunc& func, std::ostream& out, const char* ind) {
|
||||
assert(func.numTypeChecks > 0);
|
||||
assert(func.numTypeChecks() > 0);
|
||||
|
||||
if (func.numTypeChecks == 1) {
|
||||
for (auto i = func.maxNumParams - 1; i >= 0; --i) {
|
||||
if (func.params[i].isCheckedType()) {
|
||||
emitCast(func.params[i], i, out, ind, false);
|
||||
if (func.numTypeChecks() == 1) {
|
||||
for (auto i = func.numParams() - 1; i >= 0; --i) {
|
||||
if (func.param(i).isCheckedType()) {
|
||||
emitCast(func.param(i), i, out, ind, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(false); // not reached
|
||||
}
|
||||
|
||||
if (func.minNumParams != func.maxNumParams) {
|
||||
if (func.minNumParams() != func.numParams()) {
|
||||
out << ind << "switch (count) {\n";
|
||||
for (auto i = func.maxNumParams - 1; i >= func.minNumParams; --i) {
|
||||
auto const& param = func.params[i];
|
||||
if (i == func.maxNumParams - 1) {
|
||||
out << ind << "default: // count >= " << func.maxNumParams << '\n';
|
||||
for (auto i = func.numParams() - 1; i >= func.minNumParams(); --i) {
|
||||
auto const& param = func.param(i);
|
||||
if (i == func.numParams() - 1) {
|
||||
out << ind << "default: // count >= " << func.numParams() << '\n';
|
||||
} else {
|
||||
out << ind << "case " << (i + 1) << ":\n";
|
||||
}
|
||||
@@ -465,12 +427,12 @@ void emitCasts(const PhpFunc& func, std::ostream& out, const char* ind) {
|
||||
emitCast(param, i, out, ind - 2, true);
|
||||
}
|
||||
}
|
||||
out << ind << "case " << func.minNumParams << ":\n";
|
||||
out << ind << "case " << func.minNumParams() << ":\n";
|
||||
out << ind << " break;\n";
|
||||
out << ind << "}\n";
|
||||
}
|
||||
for (auto i = func.minNumParams - 1; i >= 0; --i) {
|
||||
auto const& param = func.params[i];
|
||||
for (auto i = func.minNumParams() - 1; i >= 0; --i) {
|
||||
auto const& param = func.param(i);
|
||||
if (param.isCheckedType()) {
|
||||
emitCast(param, i, out, ind, true);
|
||||
}
|
||||
@@ -487,14 +449,14 @@ void emitSlowPathHelper(const PhpFunc& func, const fbstring& prefix,
|
||||
std::ostream& out) {
|
||||
out << "void " << prefix << func.getUniqueName()
|
||||
<< "(TypedValue* rv, ActRec* ar, int32_t count";
|
||||
if (func.isMethod() && !func.isStatic) {
|
||||
if (func.usesThis()) {
|
||||
out << ", ObjectData* this_";
|
||||
}
|
||||
out << ") __attribute__((noinline,cold));\n";
|
||||
|
||||
out << "void " << prefix << func.getUniqueName()
|
||||
<< "(TypedValue* rv, ActRec* ar, int32_t count";
|
||||
if (func.isMethod() && !func.isStatic) {
|
||||
if (func.usesThis()) {
|
||||
out << ", ObjectData* this_";
|
||||
}
|
||||
out << ") {\n";
|
||||
@@ -539,22 +501,19 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
|
||||
}
|
||||
|
||||
auto& func = *idlIt->second;
|
||||
bool isMethod = !func.className.empty();
|
||||
bool isMethod = func.isMethod();
|
||||
|
||||
auto classIt = g_classMap.find(func.className);
|
||||
if (isMethod && func.name == "__construct" &&
|
||||
classIt != g_classMap.end()) {
|
||||
auto classIt = g_classMap.find(func.className());
|
||||
if (func.isCtor() && classIt != g_classMap.end()) {
|
||||
auto& klass = *classIt->second;
|
||||
auto& flags = klass.flags;
|
||||
|
||||
if (std::find(flags.begin(), flags.end(), "IsCppAbstract") == flags.end()) {
|
||||
emitCtorHelper(klass.name, cpp);
|
||||
if (!(klass.flags() & IsCppAbstract)) {
|
||||
emitCtorHelper(klass.name(), cpp);
|
||||
}
|
||||
if (std::find(flags.begin(), flags.end(), "NoDefaultSweep")
|
||||
!= flags.end()) {
|
||||
cpp << "IMPLEMENT_CLASS_NO_DEFAULT_SWEEP(" << klass.name << ");\n";
|
||||
if (klass.flags() & NoDefaultSweep) {
|
||||
cpp << "IMPLEMENT_CLASS_NO_DEFAULT_SWEEP(" << klass.name() << ");\n";
|
||||
} else {
|
||||
cpp << "IMPLEMENT_CLASS(" << klass.name << ");\n";
|
||||
cpp << "IMPLEMENT_CLASS(" << klass.name() << ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,7 +528,7 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
|
||||
}
|
||||
cpp << decl.str();
|
||||
|
||||
if (func.numTypeChecks > 0) {
|
||||
if (func.numTypeChecks() > 0) {
|
||||
emitSlowPathHelper(func, slowPathPrefix, cpp);
|
||||
}
|
||||
|
||||
@@ -584,7 +543,7 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
|
||||
cpp << in << "int32_t count = ar->numArgs();\n";
|
||||
cpp << in << "TypedValue* args UNUSED = ((TypedValue*)ar) - 1;\n";
|
||||
|
||||
if (func.isMethod() && !func.isStatic) {
|
||||
if (func.usesThis()) {
|
||||
cpp << in
|
||||
<< "ObjectData* this_ = (ar->hasThis() ? ar->getThis() : nullptr);\n";
|
||||
cpp << in << "if (this_) {\n";
|
||||
@@ -593,27 +552,27 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
|
||||
|
||||
// Check the arg count
|
||||
bool needArgMiscountClause = false;
|
||||
if (func.isVarargs) {
|
||||
if (func.minNumParams > 0) {
|
||||
cpp << in << "if (count >= " << func.minNumParams << ") {\n";
|
||||
if (func.isVarArgs()) {
|
||||
if (func.minNumParams() > 0) {
|
||||
cpp << in << "if (count >= " << func.minNumParams() << ") {\n";
|
||||
needArgMiscountClause = true;
|
||||
in -= 2;
|
||||
}
|
||||
} else {
|
||||
if (func.minNumParams == func.maxNumParams) {
|
||||
cpp << in << "if (count == " << func.minNumParams << ") {\n";
|
||||
} else if (func.minNumParams == 0) {
|
||||
cpp << in << "if (count <= " << func.maxNumParams << ") {\n";
|
||||
if (func.minNumParams() == func.numParams()) {
|
||||
cpp << in << "if (count == " << func.minNumParams() << ") {\n";
|
||||
} else if (func.minNumParams() == 0) {
|
||||
cpp << in << "if (count <= " << func.numParams() << ") {\n";
|
||||
} else {
|
||||
cpp << in << "if (count >= " << func.minNumParams
|
||||
<< " && count <= "<< func.maxNumParams << ") {\n";
|
||||
cpp << in << "if (count >= " << func.minNumParams()
|
||||
<< " && count <= "<< func.numParams() << ") {\n";
|
||||
}
|
||||
needArgMiscountClause = true;
|
||||
in -= 2;
|
||||
}
|
||||
|
||||
// Count is OK. Check arg types
|
||||
if (func.numTypeChecks > 0) {
|
||||
if (func.numTypeChecks() > 0) {
|
||||
cpp << in << "if (";
|
||||
emitTypechecks(func, cpp, in);
|
||||
cpp << ") {\n";
|
||||
@@ -624,10 +583,10 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
|
||||
emitExtCall(func, cpp, in);
|
||||
|
||||
// Deal with type mismatches: punt to fg1_
|
||||
if (func.numTypeChecks > 0) {
|
||||
if (func.numTypeChecks() > 0) {
|
||||
cpp << in + 2 << "} else {\n";
|
||||
cpp << in << slowPathPrefix << func.getUniqueName() << "(rv, ar, count";
|
||||
if (func.isMethod() && !func.isStatic) {
|
||||
if (func.usesThis()) {
|
||||
cpp << ", this_";
|
||||
}
|
||||
cpp << ");\n";
|
||||
@@ -637,17 +596,17 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
|
||||
|
||||
if (needArgMiscountClause) {
|
||||
cpp << in + 2 << "} else {\n";
|
||||
if (func.isVarargs) {
|
||||
if (func.isVarArgs()) {
|
||||
cpp << in << "throw_missing_arguments_nr(\"" << func.getPrettyName()
|
||||
<< "\", " << func.minNumParams << ", count, 1);\n";
|
||||
<< "\", " << func.minNumParams() << ", count, 1);\n";
|
||||
} else {
|
||||
if (func.minNumParams == 0) {
|
||||
if (func.minNumParams() == 0) {
|
||||
cpp << in << "throw_toomany_arguments_nr(\"" << func.getPrettyName()
|
||||
<< "\", " << func.maxNumParams << ", 1);\n";
|
||||
<< "\", " << func.numParams() << ", 1);\n";
|
||||
} else {
|
||||
cpp << in << "throw_wrong_arguments_nr(\"" << func.getPrettyName()
|
||||
<< "\", count, " << func.minNumParams << ", "
|
||||
<< func.maxNumParams << ", 1);\n";
|
||||
<< "\", count, " << func.minNumParams() << ", "
|
||||
<< func.numParams() << ", 1);\n";
|
||||
}
|
||||
}
|
||||
cpp << in << "rv->m_data.num = 0LL;\n";
|
||||
@@ -656,18 +615,17 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
|
||||
cpp << in << "}\n";
|
||||
}
|
||||
|
||||
if (func.isMethod() && !func.isStatic) {
|
||||
if (func.isMethod() && !func.isStatic()) {
|
||||
cpp << in + 2 << "} else {\n";
|
||||
cpp << in << "throw_instance_method_fatal(\"" << func.className
|
||||
<< "::" << func.name << "\");\n";
|
||||
cpp << in << "throw_instance_method_fatal(\"" << func.className()
|
||||
<< "::" << func.name() << "\");\n";
|
||||
in += 2;
|
||||
cpp << in << "}\n";
|
||||
}
|
||||
|
||||
auto numLocals = func.maxNumParams;
|
||||
bool noThis = (func.className.empty() || func.isStatic);
|
||||
auto numLocals = func.numParams();
|
||||
auto frameFree =
|
||||
(noThis ? "frame_free_locals_no_this_inl" : "frame_free_locals_inl");
|
||||
func.usesThis() ? "frame_free_locals_inl" : "frame_free_locals_no_this_inl";
|
||||
cpp << in << frameFree << "(ar, " << numLocals << ");\n";
|
||||
cpp << in << "memcpy(&ar->m_r, rv, sizeof(TypedValue));\n";
|
||||
cpp << in << "return &ar->m_r;\n";
|
||||
@@ -703,8 +661,8 @@ int main(int argc, const char* argv[]) {
|
||||
g_mangleMap[func.getCppSig()] = &func;
|
||||
}
|
||||
for (auto const& klass : classes) {
|
||||
g_classMap[klass.name] = &klass;
|
||||
for (auto const& func : klass.methods) {
|
||||
g_classMap[klass.name()] = &klass;
|
||||
for (auto const& func : klass.methods()) {
|
||||
g_mangleMap[func.getCppSig()] = &func;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
using folly::fbstring;
|
||||
using folly::fbvector;
|
||||
|
||||
using namespace HPHP::IDL;
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
if (argc < 3) {
|
||||
@@ -64,16 +64,15 @@ int main(int argc, const char* argv[]) {
|
||||
// Declare the fg_ and tg_ stubs
|
||||
|
||||
for (auto const& func : funcs) {
|
||||
cpp << "TypedValue* fg_" << func.name << "(ActRec* ar);\n";
|
||||
cpp << "TypedValue* fg_" << func.name() << "(ActRec* ar);\n";
|
||||
}
|
||||
|
||||
for (auto const& klass : classes) {
|
||||
if (std::find(klass.flags.begin(), klass.flags.end(), "IsCppAbstract")
|
||||
== klass.flags.end()) {
|
||||
cpp << "Instance* new_" << klass.name << "_Instance(Class*);\n";
|
||||
classesWithCtors.insert(klass.name);
|
||||
if (!(klass.flags() & IsCppAbstract)) {
|
||||
cpp << "Instance* new_" << klass.name() << "_Instance(Class*);\n";
|
||||
classesWithCtors.insert(klass.name());
|
||||
}
|
||||
for (auto const& func : klass.methods) {
|
||||
for (auto const& func : klass.methods()) {
|
||||
cpp << "TypedValue* tg_" << func.getUniqueName()
|
||||
<< "(ActRec* ar);\n";
|
||||
}
|
||||
@@ -89,7 +88,7 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
bool first = true;
|
||||
for (auto const& func : funcs) {
|
||||
if (!func.className.empty()) {
|
||||
if (func.isMethod()) {
|
||||
continue;
|
||||
}
|
||||
if (!first) {
|
||||
@@ -97,24 +96,24 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
first = false;
|
||||
|
||||
cpp << "{ \"" << func.name << "\", fg_" << func.name
|
||||
<< ", (void *)&fh_" << func.name << " }";
|
||||
cpp << "{ \"" << func.name() << "\", fg_" << func.name()
|
||||
<< ", (void *)&fh_" << func.name() << " }";
|
||||
}
|
||||
cpp << "\n};\n\n";
|
||||
|
||||
for (auto const& klass : classes) {
|
||||
cpp << "static const long long hhbc_ext_method_count_" << klass.name
|
||||
<< " = " << klass.methods.size() << ";\n";
|
||||
cpp << "static const HhbcExtMethodInfo hhbc_ext_methods_" << klass.name
|
||||
cpp << "static const long long hhbc_ext_method_count_" << klass.name()
|
||||
<< " = " << klass.numMethods() << ";\n";
|
||||
cpp << "static const HhbcExtMethodInfo hhbc_ext_methods_" << klass.name()
|
||||
<< "[] = {\n ";
|
||||
first = true;
|
||||
for (auto const& method : klass.methods) {
|
||||
for (auto const& method : klass.methods()) {
|
||||
if (!first) {
|
||||
cpp << ",\n ";
|
||||
}
|
||||
first = false;
|
||||
|
||||
cpp << "{ \"" << method.name << "\", tg_" << method.getUniqueName()
|
||||
cpp << "{ \"" << method.name() << "\", tg_" << method.getUniqueName()
|
||||
<< " }";
|
||||
}
|
||||
cpp << "\n};\n\n";
|
||||
@@ -129,15 +128,15 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
first = false;
|
||||
|
||||
auto ctor = (classesWithCtors.count(klass.name) > 0
|
||||
? fbstring("new_") + klass.name + "_Instance"
|
||||
auto ctor = (classesWithCtors.count(klass.name()) > 0
|
||||
? fbstring("new_") + klass.name() + "_Instance"
|
||||
: fbstring("nullptr"));
|
||||
|
||||
cpp << "{ \"" << klass.name << "\", " << ctor
|
||||
<< ", sizeof(c_" << klass.name << ')'
|
||||
<< ", hhbc_ext_method_count_" << klass.name
|
||||
<< ", hhbc_ext_methods_" << klass.name
|
||||
<< ", &c_" << klass.name << "::s_cls }";
|
||||
cpp << "{ \"" << klass.name() << "\", " << ctor
|
||||
<< ", sizeof(c_" << klass.name() << ')'
|
||||
<< ", hhbc_ext_method_count_" << klass.name()
|
||||
<< ", hhbc_ext_methods_" << klass.name()
|
||||
<< ", &c_" << klass.name() << "::s_cls }";
|
||||
}
|
||||
cpp << "\n};\n\n";
|
||||
cpp << "} // namespace HPHP\n";
|
||||
|
||||
+205
-148
@@ -23,187 +23,248 @@
|
||||
#include "folly/Format.h"
|
||||
#include "folly/json.h"
|
||||
|
||||
namespace HPHP { namespace IDL {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const std::unordered_map<fbstring, fbstring> g_typeMap =
|
||||
static const std::unordered_map<fbstring, DataType> g_kindOfMap =
|
||||
{
|
||||
{"Boolean", "bool"},
|
||||
{"Int32", "int"},
|
||||
{"Int64", "long"},
|
||||
{"Double", "double"},
|
||||
{"String", "HPHP::String"},
|
||||
{"Int64Vec", "HPHP::Array"},
|
||||
{"StringVec", "HPHP::Array"},
|
||||
{"VariantVec", "HPHP::Array"},
|
||||
{"Int64Map", "HPHP::Array"},
|
||||
{"StringMap", "HPHP::Array"},
|
||||
{"VariantMap", "HPHP::Array"},
|
||||
{"Object", "HPHP::Object"},
|
||||
{"Resource", "HPHP::Object"},
|
||||
{"Variant", "HPHP::Variant"},
|
||||
{"Numeric", "HPHP::Variant"},
|
||||
{"Primitive", "HPHP::Variant"},
|
||||
{"PlusOperand", "HPHP::Variant"},
|
||||
{"Sequence", "HPHP::Variant"},
|
||||
{"Any", "HPHP::Variant"},
|
||||
{"Boolean", KindOfBoolean},
|
||||
{"Int32", KindOfInt64},
|
||||
{"Int64", KindOfInt64},
|
||||
{"Double", KindOfDouble},
|
||||
{"String", KindOfString},
|
||||
{"Int64Vec", KindOfArray},
|
||||
{"StringVec", KindOfArray},
|
||||
{"VariantVec", KindOfArray},
|
||||
{"Int64Map", KindOfArray},
|
||||
{"StringMap", KindOfArray},
|
||||
{"VariantMap", KindOfArray},
|
||||
{"Object", KindOfObject},
|
||||
{"Resource", KindOfObject},
|
||||
{"Variant", KindOfAny},
|
||||
{"Numeric", KindOfAny},
|
||||
{"Primitive", KindOfAny},
|
||||
{"PlusOperand", KindOfAny},
|
||||
{"Sequence", KindOfAny},
|
||||
{"Any", KindOfAny},
|
||||
};
|
||||
|
||||
const std::unordered_set<fbstring> g_knownStringConstants =
|
||||
static const std::unordered_map<int, fbstring> g_typeMap =
|
||||
{
|
||||
{(int)KindOfInvalid, "void"},
|
||||
{(int)KindOfBoolean, "bool"},
|
||||
{(int)KindOfInt64, "long"},
|
||||
{(int)KindOfDouble, "double"},
|
||||
{(int)KindOfString, "HPHP::String"},
|
||||
{(int)KindOfArray, "HPHP::Array"},
|
||||
{(int)KindOfObject, "HPHP::Object"},
|
||||
{(int)KindOfAny, "HPHP::Variant"},
|
||||
};
|
||||
|
||||
static const std::unordered_map<fbstring, FuncFlags> g_flagsMap =
|
||||
{
|
||||
{"IsAbstract", IsAbstract},
|
||||
{"IsFinal", IsFinal},
|
||||
{"IsPublic", IsPublic},
|
||||
{"IsProtected", IsProtected},
|
||||
{"IsPrivate", IsPrivate},
|
||||
{"IgnoreRedefinition", IgnoreRedefinition},
|
||||
{"IsStatic", IsStatic},
|
||||
{"IsCppAbstract", IsCppAbstract},
|
||||
{"IsReference", IsReference},
|
||||
{"IsConstructor", IsConstructor},
|
||||
{"IsNothing", IsNothing},
|
||||
{"HasDocComment", HasDocComment},
|
||||
{"HipHopSpecific", HipHopSpecific},
|
||||
{"VariableArguments", VariableArguments},
|
||||
{"RefVariableArguments", RefVariableArguments},
|
||||
{"MixedVariableArguments", MixedVariableArguments},
|
||||
{"FunctionIsFoldable", FunctionIsFoldable},
|
||||
{"NoEffect", NoEffect},
|
||||
{"NoInjection", NoInjection},
|
||||
{"HasOptFunction", HasOptFunction},
|
||||
{"AllowIntercept", AllowIntercept},
|
||||
{"NoProfile", NoProfile},
|
||||
{"ContextSensitive", ContextSensitive},
|
||||
{"NoDefaultSweep", NoDefaultSweep},
|
||||
{"IsSystem", IsSystem},
|
||||
{"IsTrait", IsTrait},
|
||||
{"NeedsActRec", NeedsActRec},
|
||||
};
|
||||
|
||||
static const std::unordered_set<fbstring> g_knownStringConstants =
|
||||
{ "k_HPHP_TRIM_CHARLIST" };
|
||||
|
||||
|
||||
bool isTypeCppIndirectPass(const fbstring& type) {
|
||||
return (type != "bool" &&
|
||||
type != "int" &&
|
||||
type != "long" &&
|
||||
type != "double" &&
|
||||
type != "void");
|
||||
bool isKindOfIndirect(DataType kindof) {
|
||||
return (kindof != KindOfBoolean) &&
|
||||
(kindof != KindOfInt64) &&
|
||||
(kindof != KindOfDouble) &&
|
||||
(kindof != KindOfInvalid);
|
||||
}
|
||||
|
||||
fbstring typeString(const folly::dynamic& typeNode, bool isReturnType) {
|
||||
if (!typeNode.isString()) {
|
||||
return "void";
|
||||
static DataType kindOfFromDynamic(const folly::dynamic& t) {
|
||||
if (!t.isString()) {
|
||||
return KindOfInvalid;
|
||||
}
|
||||
auto it = g_kindOfMap.find(t.asString());
|
||||
if (it == g_kindOfMap.end()) {
|
||||
return KindOfObject;
|
||||
}
|
||||
|
||||
auto typeIt = g_typeMap.find(typeNode.asString());
|
||||
if (typeIt == g_typeMap.end()) {
|
||||
return (isReturnType ? "HPHP::Object" : "HPHP::Object const&");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
static fbstring typeString(const folly::dynamic& typeNode, bool isReturnType) {
|
||||
if (typeNode == "Int32") {
|
||||
return "int";
|
||||
}
|
||||
|
||||
auto& type = typeIt->second;
|
||||
if (!isReturnType && isTypeCppIndirectPass(type)) {
|
||||
DataType kindof = kindOfFromDynamic(typeNode);
|
||||
auto it = g_typeMap.find((int)kindof);
|
||||
assert(it != g_typeMap.end());
|
||||
|
||||
auto& type = it->second;
|
||||
if (!isReturnType && isKindOfIndirect(kindof)) {
|
||||
return type + " const&";
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
bool PhpParam::defValNeedsVariable() const {
|
||||
if (defVal.empty() || !isTypeCppIndirectPass(cppType)) {
|
||||
static unsigned long parseFlags(const folly::dynamic &flags) {
|
||||
if (flags.isNull()) {
|
||||
return 0;
|
||||
}
|
||||
if (!flags.isArray()) {
|
||||
throw std::logic_error("'flags' field must be an array");
|
||||
}
|
||||
|
||||
unsigned long ret = 0;
|
||||
for (auto &flag : flags) {
|
||||
auto f = g_flagsMap.find(flag.asString());
|
||||
if (f == g_flagsMap.end()) {
|
||||
continue;
|
||||
}
|
||||
ret |= f->second;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// PhpParam
|
||||
|
||||
PhpParam::PhpParam(const folly::dynamic& param,
|
||||
bool isMagicMethod /*= false */) :
|
||||
m_name(param["name"].asString()),
|
||||
m_param(param) {
|
||||
if (isMagicMethod) {
|
||||
m_kindOf = KindOfAny;
|
||||
m_cppType = "HPHP::Variant";
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRef()) {
|
||||
m_kindOf = KindOfRef;
|
||||
m_cppType = "HPHP::VRefParamValue const&";
|
||||
} else {
|
||||
m_kindOf = kindOfFromDynamic(param["type"]);
|
||||
m_cppType = typeString(param["type"], false);
|
||||
}
|
||||
}
|
||||
|
||||
bool PhpParam::defValueNeedsVariable() const {
|
||||
DataType cppKindOf = kindOf();
|
||||
|
||||
if (!hasDefault() || !isIndirectPass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cppType == "HPHP::String const&" && (defVal == "empty_string" ||
|
||||
defVal == "null_string")) {
|
||||
return false;
|
||||
} else if (cppType == "HPHP::String const&" &&
|
||||
g_knownStringConstants.count(defVal) > 0) {
|
||||
return false;
|
||||
} else if (cppType == "HPHP::Array const&" && defVal == "null_array") {
|
||||
return false;
|
||||
} else if (cppType == "HPHP::Object const&" && defVal == "null_object") {
|
||||
return false;
|
||||
} else if (cppType == "HPHP::Variant const&" && defVal == "null_variant") {
|
||||
fbstring defVal = getDefault();
|
||||
|
||||
if (cppKindOf == KindOfString &&
|
||||
((defVal == "empty_string") ||
|
||||
(defVal == "null_string") ||
|
||||
(g_knownStringConstants.count(defVal) > 0))) {
|
||||
return false;
|
||||
}
|
||||
if ((cppKindOf == KindOfArray) && (defVal == "null_array")) {
|
||||
return false;
|
||||
}
|
||||
if ((cppKindOf == KindOfObject) && (defVal == "null_object")) {
|
||||
return false;
|
||||
}
|
||||
if ((cppKindOf == KindOfAny) && (defVal == "null_variant")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PhpFunc PhpFunc::fromDynamic(const folly::dynamic& d,
|
||||
const fbstring& className) {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// PhpFunc
|
||||
|
||||
PhpFunc::PhpFunc(const folly::dynamic& d,
|
||||
const fbstring& className) :
|
||||
m_name(d["name"].asString()),
|
||||
m_className(className),
|
||||
m_func(d),
|
||||
m_returnRef(d.getDefault("ref", "false") == "true"),
|
||||
m_returnKindOf(m_returnRef ? KindOfRef :
|
||||
kindOfFromDynamic(d["return"]["type"])),
|
||||
m_returnCppType(typeString(d["return"]["type"], true)),
|
||||
m_minNumParams(0),
|
||||
m_numTypeChecks(0) {
|
||||
// Better at least have a name
|
||||
auto name = d["name"].asString();
|
||||
auto args = d.find("args");
|
||||
auto flags = d.find("flags");
|
||||
auto ret = d.find("return");
|
||||
if (args == d.items().end() || !args->second.isArray()) {
|
||||
throw std::logic_error(
|
||||
folly::format("'{0}' must have an array field 'args'", name).str()
|
||||
);
|
||||
}
|
||||
if (flags == d.items().end() || !flags->second.isArray()) {
|
||||
throw std::logic_error(
|
||||
folly::format("'{0}' must have an array field 'flags'", name).str()
|
||||
folly::format("'{0}' must have an array field 'args'", name()).str()
|
||||
);
|
||||
}
|
||||
auto ret = d.find("return");
|
||||
if (ret == d.items().end() || !ret->second.isObject() ||
|
||||
ret->second.find("type") == ret->second.items().end()) {
|
||||
throw std::logic_error(
|
||||
folly::format("'{0}' must have an array field 'return', which must have "
|
||||
"a string field 'type'", name).str()
|
||||
"a string field 'type'", name()).str()
|
||||
);
|
||||
}
|
||||
|
||||
auto areVarargs = [](const fbstring& str) {
|
||||
return (str == "VariableArguments" ||
|
||||
str == "RefVariableArguments" ||
|
||||
str == "MixedVariableArguments");
|
||||
};
|
||||
|
||||
fbvector<PhpParam> params;
|
||||
try {
|
||||
params = std::move(folly::convertTo<fbvector<PhpParam>>(args->second));
|
||||
} catch (const std::exception& exc) {
|
||||
throw std::logic_error(
|
||||
folly::format("'{0}' has an arg with either 'name' or 'type' field "
|
||||
"missing", name).str()
|
||||
);
|
||||
}
|
||||
if (name == "__get" ||
|
||||
name == "__set" ||
|
||||
name == "__isset" ||
|
||||
name == "__unset" ||
|
||||
name == "__call") {
|
||||
for (auto& param : params) {
|
||||
param.cppType = "HPHP::Variant";
|
||||
}
|
||||
}
|
||||
|
||||
auto refIt = d.find("ref");
|
||||
bool ref = (refIt != d.items().end() && refIt->second.asString() == "true");
|
||||
|
||||
PhpFunc retval;
|
||||
retval.name = name;
|
||||
retval.className = className;
|
||||
retval.returnCppType = typeString(ret->second["type"], true);
|
||||
retval.returnByRef = ref;
|
||||
retval.params = params;
|
||||
retval.isVarargs = anyFlags(areVarargs, flags->second);
|
||||
retval.isStatic = false;
|
||||
|
||||
if (!className.empty()) {
|
||||
auto areStatic = [](const fbstring& str) {
|
||||
return str == "IsStatic";
|
||||
};
|
||||
|
||||
retval.isStatic = anyFlags(areStatic, flags->second);
|
||||
}
|
||||
retval.initComputedProps();
|
||||
return retval;
|
||||
}
|
||||
|
||||
void PhpFunc::initComputedProps() {
|
||||
maxNumParams = params.size();
|
||||
minNumParams = params.size();
|
||||
numTypeChecks = 0;
|
||||
for (auto const& param : params) {
|
||||
if (!param.defVal.empty()) {
|
||||
--minNumParams;
|
||||
bool magic = isMagicMethod();
|
||||
for (auto &p : args->second) {
|
||||
PhpParam param(p, magic);
|
||||
m_params.push_back(param);
|
||||
if (!param.hasDefault()) {
|
||||
++m_minNumParams;
|
||||
}
|
||||
if (param.isCheckedType()) {
|
||||
++numTypeChecks;
|
||||
++m_numTypeChecks;
|
||||
}
|
||||
}
|
||||
|
||||
m_flags = parseFlags(m_func["flags"]);
|
||||
}
|
||||
|
||||
fbstring PhpFunc::getCppSig() const {
|
||||
std::ostringstream out;
|
||||
|
||||
auto lowername = name;
|
||||
std::transform(name.begin(), name.end(), lowername.begin(),
|
||||
fbstring nm = name();
|
||||
fbstring lowername = nm;
|
||||
std::transform(nm.begin(), nm.end(), lowername.begin(),
|
||||
std::ptr_fun<int, int>(std::tolower));
|
||||
|
||||
if (className.empty()) {
|
||||
if (!isMethod()) {
|
||||
out << "HPHP::f_" << lowername << "(";
|
||||
} else {
|
||||
if (isStatic) {
|
||||
out << "HPHP::c_" << className << "::ti_" << lowername << "(";
|
||||
if (isStatic()) {
|
||||
out << "HPHP::c_" << className() << "::ti_" << lowername << "(";
|
||||
} else {
|
||||
out << "HPHP::c_" << className << "::t_" << lowername << "(";
|
||||
out << "HPHP::c_" << className() << "::t_" << lowername << "(";
|
||||
}
|
||||
}
|
||||
|
||||
bool firstParam = true;
|
||||
if (isVarargs) {
|
||||
if (isVarArgs()) {
|
||||
if (!firstParam) {
|
||||
out << ", ";
|
||||
}
|
||||
@@ -211,15 +272,15 @@ fbstring PhpFunc::getCppSig() const {
|
||||
firstParam = false;
|
||||
}
|
||||
|
||||
for (auto const& param : params) {
|
||||
for (auto const& param : m_params) {
|
||||
if (!firstParam) {
|
||||
out << ", ";
|
||||
}
|
||||
out << param.cppType;
|
||||
out << param.getCppType();
|
||||
firstParam = false;
|
||||
}
|
||||
|
||||
if (isVarargs) {
|
||||
if (isVarArgs()) {
|
||||
assert(!firstParam);
|
||||
out << ", HPHP::Array const&";
|
||||
}
|
||||
@@ -228,20 +289,21 @@ fbstring PhpFunc::getCppSig() const {
|
||||
return out.str();
|
||||
}
|
||||
|
||||
bool anyFlags(std::function<bool(const fbstring&)> pred,
|
||||
const folly::dynamic& flagsArray) {
|
||||
if (!flagsArray.isArray()) {
|
||||
return false;
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// PhpClass
|
||||
|
||||
PhpClass::PhpClass(const folly::dynamic &c) :
|
||||
m_class(c),
|
||||
m_name(c["name"].asString()) {
|
||||
for (auto const& f : c["funcs"]) {
|
||||
PhpFunc func(f, m_name);
|
||||
m_methods.push_back(func);
|
||||
}
|
||||
for (auto const& strDyn : flagsArray) {
|
||||
auto str = strDyn.asString();
|
||||
if (pred(str)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
m_flags = parseFlags(m_class["flags"]);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void parseIDL(const char* idlFilePath,
|
||||
fbvector<PhpFunc>& funcVec,
|
||||
fbvector<PhpClass>& classVec) {
|
||||
@@ -252,19 +314,14 @@ void parseIDL(const char* idlFilePath,
|
||||
auto parsed = folly::parseJson(jsonString.str());
|
||||
|
||||
for (auto const& f : parsed["funcs"]) {
|
||||
auto func = PhpFunc::fromDynamic(f, "");
|
||||
PhpFunc func(f, "");
|
||||
funcVec.push_back(func);
|
||||
}
|
||||
for (auto const& c : parsed["classes"]) {
|
||||
PhpClass klass;
|
||||
klass.name = c["name"].asString();
|
||||
klass.flags = folly::convertTo<fbvector<fbstring>>(c["flags"]);
|
||||
|
||||
for (auto const& f : c["funcs"]) {
|
||||
auto func = PhpFunc::fromDynamic(f, c["name"].asString());
|
||||
klass.methods.push_back(func);
|
||||
}
|
||||
|
||||
PhpClass klass(c);
|
||||
classVec.push_back(klass);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
}} // namespace HPHP::IDL
|
||||
|
||||
+168
-59
@@ -22,101 +22,210 @@
|
||||
#include "folly/FBString.h"
|
||||
#include "folly/FBVector.h"
|
||||
|
||||
#include "hphp/runtime/base/datatype.h"
|
||||
|
||||
using folly::fbstring;
|
||||
using folly::fbvector;
|
||||
|
||||
namespace HPHP { namespace IDL {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool isTypeCppIndirectPass(const fbstring& type);
|
||||
enum FuncFlags {
|
||||
IsAbstract = (1 << 4),
|
||||
IsFinal = (1 << 5),
|
||||
IsPublic = (1 << 6),
|
||||
IsProtected = (1 << 7),
|
||||
IsPrivate = (1 << 8),
|
||||
IgnoreRedefinition = (1 << 8),
|
||||
IsStatic = (1 << 9),
|
||||
IsCppAbstract = (1 << 10),
|
||||
IsReference = (1 << 11),
|
||||
IsConstructor = (1 << 12),
|
||||
IsNothing = (1 << 13),
|
||||
HasDocComment = (1 << 14),
|
||||
HipHopSpecific = (1 << 16),
|
||||
VariableArguments = (1 << 17),
|
||||
RefVariableArguments = (1 << 18),
|
||||
MixedVariableArguments = (1 << 19),
|
||||
FunctionIsFoldable = (1 << 20),
|
||||
NoEffect = (1 << 21),
|
||||
NoInjection = (1 << 22),
|
||||
HasOptFunction = (1 << 23),
|
||||
AllowIntercept = (1 << 24),
|
||||
NoProfile = (1 << 25),
|
||||
ContextSensitive = (1 << 26),
|
||||
NoDefaultSweep = (1 << 27),
|
||||
IsSystem = (1 << 28),
|
||||
IsTrait = (1 << 29),
|
||||
NeedsActRec = (1 << 31),
|
||||
};
|
||||
|
||||
fbstring typeString(const folly::dynamic& typeNode, bool isReturnType);
|
||||
#define VarArgsMask (VariableArguments | \
|
||||
RefVariableArguments | \
|
||||
MixedVariableArguments)
|
||||
|
||||
struct PhpParam {
|
||||
fbstring name;
|
||||
fbstring cppType;
|
||||
fbstring defVal;
|
||||
bool byRef;
|
||||
bool isKindOfIndirect(DataType kindof);
|
||||
|
||||
static inline fbstring kindOfString(DataType t) {
|
||||
switch (t) {
|
||||
case KindOfAny: return "Any";
|
||||
case KindOfUnknown: return "Unknown";
|
||||
case KindOfNull: return "Null";
|
||||
case KindOfBoolean: return "Boolean";
|
||||
case KindOfInt64: return "Int64";
|
||||
case KindOfDouble: return "Double";
|
||||
case KindOfStaticString: return "StaticString";
|
||||
case KindOfString: return "String";
|
||||
case KindOfArray: return "Array";
|
||||
case KindOfObject: return "Object";
|
||||
case KindOfRef: return "Ref";
|
||||
default:
|
||||
// No other enums should occur in IDL parsing
|
||||
assert(false);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
class PhpParam {
|
||||
public:
|
||||
explicit PhpParam(const folly::dynamic& param, bool isMagicMethod = false);
|
||||
|
||||
fbstring name() const { return m_name; }
|
||||
fbstring getCppType() const { return m_cppType; }
|
||||
fbstring getStrippedCppType() const {
|
||||
fbstring ret = m_cppType;
|
||||
if (!ret.compare(0, 6, "HPHP::")) {
|
||||
ret = ret.substr(6);
|
||||
}
|
||||
if (!ret.compare(ret.length() - 7, 7, " const&")) {
|
||||
ret = ret.substr(0, ret.length() - 7);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
DataType kindOf() const { return m_kindOf; }
|
||||
|
||||
bool isRef() const { return m_param.getDefault("ref", false).asBool(); }
|
||||
|
||||
bool hasDefault() const {
|
||||
return m_param.find("value") != m_param.items().end();
|
||||
}
|
||||
fbstring getDefault() const {
|
||||
return hasDefault() ? m_param["value"].asString() : "";
|
||||
}
|
||||
|
||||
bool isCheckedType() const {
|
||||
return (cppType != "HPHP::Variant" &&
|
||||
cppType != "HPHP::VRefParamValue const&" &&
|
||||
cppType != "HPHP::Variant const&");
|
||||
return !isRef() && (kindOf() != KindOfAny);
|
||||
}
|
||||
bool defValueNeedsVariable() const;
|
||||
|
||||
bool defValNeedsVariable() const;
|
||||
bool isIndirectPass() const { return isKindOfIndirect(kindOf()); }
|
||||
|
||||
private:
|
||||
fbstring m_name;
|
||||
folly::dynamic m_param;
|
||||
DataType m_kindOf;
|
||||
fbstring m_cppType;
|
||||
};
|
||||
|
||||
namespace folly {
|
||||
template<>
|
||||
struct DynamicConverter<PhpParam> {
|
||||
static PhpParam convert(const dynamic& d) {
|
||||
auto refIt = d.find("ref");
|
||||
bool ref = (refIt != d.items().end() && refIt->second.asBool());
|
||||
auto valIt = d.find("value");
|
||||
auto value = (valIt != d.items().end() ? valIt->second.asString() : "");
|
||||
auto type =
|
||||
(ref ? "HPHP::VRefParamValue const&" : typeString(d["type"], false));
|
||||
class PhpFunc {
|
||||
public:
|
||||
PhpFunc(const folly::dynamic& d, const fbstring& className);
|
||||
|
||||
return {d["name"].asString(), type, value, ref};
|
||||
}
|
||||
};
|
||||
} // namespace folly
|
||||
|
||||
|
||||
struct PhpFunc {
|
||||
fbstring name;
|
||||
fbstring className;
|
||||
fbstring returnCppType;
|
||||
bool returnByRef;
|
||||
fbvector<PhpParam> params;
|
||||
bool isVarargs;
|
||||
bool isStatic;
|
||||
|
||||
// Computed properties.
|
||||
int minNumParams;
|
||||
int maxNumParams;
|
||||
int numTypeChecks;
|
||||
|
||||
static PhpFunc fromDynamic(const folly::dynamic& d,
|
||||
const fbstring& className);
|
||||
fbstring name() const { return m_name; }
|
||||
fbstring className() const { return m_className; }
|
||||
|
||||
bool isMethod() const {
|
||||
return !className.empty();
|
||||
return !m_className.empty();
|
||||
}
|
||||
|
||||
bool isMagicMethod() const {
|
||||
return (isMethod() && (
|
||||
(m_name == "__get") ||
|
||||
(m_name == "__set") ||
|
||||
(m_name == "__isset") ||
|
||||
(m_name == "__unset") ||
|
||||
(m_name == "__call")));
|
||||
}
|
||||
|
||||
fbstring getCppSig() const;
|
||||
|
||||
fbstring getPrettyName() const {
|
||||
if (className.empty()) {
|
||||
return name;
|
||||
if (isMethod()) {
|
||||
return m_className + "::" + m_name;
|
||||
} else {
|
||||
return className + "::" + name;
|
||||
return m_name;
|
||||
}
|
||||
}
|
||||
|
||||
fbstring getUniqueName() const {
|
||||
if (className.empty()) {
|
||||
return name;
|
||||
if (isMethod()) {
|
||||
return folly::to<fbstring>(m_className.length(), m_className,
|
||||
'_', m_name);
|
||||
} else {
|
||||
return folly::to<fbstring>(className.length(), className, '_', name);
|
||||
return m_name;
|
||||
}
|
||||
}
|
||||
|
||||
bool isReturnRef() const { return m_returnRef; }
|
||||
DataType returnKindOf() const { return m_returnKindOf; }
|
||||
fbstring returnCppType() const { return m_returnCppType; }
|
||||
|
||||
bool isIndirectReturn() const { return isKindOfIndirect(returnKindOf()); }
|
||||
|
||||
bool isCtor() const { return isMethod() && (m_name == "__construct"); }
|
||||
bool isStatic() const { return m_flags & IsStatic; }
|
||||
bool isVarArgs() const { return m_flags & VarArgsMask; }
|
||||
bool usesThis() const { return isMethod() && !isStatic(); }
|
||||
|
||||
int numParams() const { return m_params.size(); }
|
||||
int minNumParams() const { return m_minNumParams; }
|
||||
int numTypeChecks() const { return m_numTypeChecks; }
|
||||
|
||||
const PhpParam& param(int p) const { return m_params[p]; }
|
||||
const fbvector<PhpParam>& params() const { return m_params; }
|
||||
|
||||
private:
|
||||
PhpFunc() = default;
|
||||
void initComputedProps();
|
||||
fbstring m_name;
|
||||
fbstring m_className;
|
||||
folly::dynamic m_func;
|
||||
unsigned long m_flags;
|
||||
|
||||
// Return value
|
||||
bool m_returnRef;
|
||||
DataType m_returnKindOf;
|
||||
fbstring m_returnCppType;
|
||||
|
||||
fbvector<PhpParam> m_params;
|
||||
|
||||
// Computed properties.
|
||||
int m_minNumParams;
|
||||
int m_numTypeChecks;
|
||||
};
|
||||
|
||||
struct PhpClass {
|
||||
fbstring name;
|
||||
fbvector<fbstring> flags;
|
||||
fbvector<PhpFunc> methods;
|
||||
};
|
||||
class PhpClass {
|
||||
public:
|
||||
explicit PhpClass(const folly::dynamic &c);
|
||||
|
||||
bool anyFlags(std::function<bool(const fbstring&)> pred,
|
||||
const folly::dynamic& flagsArray);
|
||||
fbstring name() const { return m_name; }
|
||||
|
||||
int numMethods() const { return m_methods.size(); }
|
||||
const fbvector<PhpFunc>& methods() const { return m_methods; }
|
||||
|
||||
unsigned long flags() const { return m_flags; }
|
||||
|
||||
private:
|
||||
folly::dynamic m_class;
|
||||
fbstring m_name;
|
||||
fbvector<PhpFunc> m_methods;
|
||||
unsigned long m_flags;
|
||||
|
||||
void initFlagsProperty();
|
||||
};
|
||||
|
||||
void parseIDL(const char* idlFilePath,
|
||||
fbvector<PhpFunc>& funcVec,
|
||||
fbvector<PhpClass>& classVec);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
}} // namespace HPHP::IDL
|
||||
#endif
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário