84b9d9a3a2
In HHVM (and HPHPc before it) we've been piggybacking resources on the KindOfObject machinery. At the language level, resource is considered to be a different type than object, and there are a number of differences in behavior between objects and resources (ex. resources don't allow for dynamic properties, resources don't work with the clone operator, the "(object)" cast behaves differently for resources vs. objects, etc). Piggybacking resources on the KindOfObject machinery has some downsides. Code that deals with KindOfObject values often needs to check if the value is a resource and go down a different code path. This makes things harder to maintain and harder to keep parity with Zend. Also, these extra branches hurt performance a little, and they make it harder for the JIT to do a good job in some cases when its generating machine code that operates on objects. This diff prepares the code base for a new KindOfResource type by adding a new "Resource" smart pointer type (currently a typedef for the Object smart pointer type) and it updates the C++ code and the idl files appropriately. This diff is essentially a cosmetic change and should not impact run time behavior. In the next diff (part 2) we'll actually add a new KindOfResource type, detach ResourceData from the ObjectData inheritence hierarchy, and provide a real implementation for the Resource smart pointer type (instead of just aliasing the Object smart pointer type).
785 linhas
21 KiB
C++
785 linhas
21 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "hphp/tools/bootstrap/idl.h"
|
|
|
|
#include <fstream>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
|
|
#include "folly/Format.h"
|
|
#include "folly/json.h"
|
|
|
|
#ifdef __APPLE__
|
|
#define INT64_TYPE "long long"
|
|
#else
|
|
#define INT64_TYPE "long"
|
|
#endif
|
|
|
|
namespace HPHP { namespace IDL {
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
static const std::unordered_map<fbstring, DataType> g_kindOfMap =
|
|
{
|
|
{"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},
|
|
};
|
|
|
|
static const std::unordered_map<int, fbstring> g_typeMap =
|
|
{
|
|
{(int)KindOfInvalid, "void"},
|
|
{(int)KindOfNull, "HPHP::Variant"},
|
|
{(int)KindOfBoolean, "bool"},
|
|
{(int)KindOfInt64, INT64_TYPE},
|
|
{(int)KindOfDouble, "double"},
|
|
{(int)KindOfString, "HPHP::String"},
|
|
{(int)KindOfArray, "HPHP::Array"},
|
|
{(int)KindOfObject, "HPHP::Object"},
|
|
{(int)KindOfAny, "HPHP::Variant"},
|
|
};
|
|
|
|
static const std::unordered_map<int, fbstring> g_phpTypeMap =
|
|
{
|
|
{(int)KindOfInvalid, "void"},
|
|
{(int)KindOfNull, "void"},
|
|
{(int)KindOfBoolean, "bool"},
|
|
{(int)KindOfInt64, INT64_TYPE},
|
|
{(int)KindOfDouble, "double"},
|
|
{(int)KindOfString, "String"},
|
|
{(int)KindOfArray, "Array"},
|
|
{(int)KindOfObject, "Object"},
|
|
{(int)KindOfAny, "mixed"},
|
|
};
|
|
|
|
static const std::unordered_map<fbstring, FuncFlags> g_flagsMap =
|
|
{
|
|
{"ZendParamMode", ZendParamMode},
|
|
{"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 isKindOfIndirect(DataType kindof) {
|
|
return (kindof != KindOfBoolean) &&
|
|
(kindof != KindOfInt64) &&
|
|
(kindof != KindOfDouble) &&
|
|
(kindof != KindOfInvalid) &&
|
|
(kindof != KindOfNull);
|
|
}
|
|
|
|
// Parse type from a descriptive string, e.g. "int", "bool", etc...
|
|
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;
|
|
}
|
|
|
|
return it->second;
|
|
}
|
|
|
|
// Infer type from an actual value, e.g. 123, "foo", null, true, etc...
|
|
static DataType kindOfFromValue(const folly::dynamic& v) {
|
|
if (v.isNull()) {
|
|
return KindOfNull;
|
|
}
|
|
if (v.isBool()) {
|
|
return KindOfBoolean;
|
|
}
|
|
if (v.isInt()) {
|
|
return KindOfInt64;
|
|
}
|
|
if (v.isDouble()) {
|
|
return KindOfDouble;
|
|
}
|
|
if (v.isString()) {
|
|
return KindOfString;
|
|
}
|
|
if (v.isArray()) {
|
|
return KindOfArray;
|
|
}
|
|
if (v.isObject()) {
|
|
return KindOfObject;
|
|
}
|
|
return KindOfInvalid;
|
|
}
|
|
|
|
static fbstring phpTypeFromDataType(DataType dt) {
|
|
auto it = g_phpTypeMap.find((int)dt);
|
|
if (it == g_phpTypeMap.end()) {
|
|
return "mixed";
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
static fbstring typeString(const folly::dynamic& typeNode, bool isReturnType) {
|
|
if (typeNode == "Int32") {
|
|
return "int";
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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()) {
|
|
throw std::logic_error(
|
|
folly::format("Unknown flag '{0}' specified", flag.asString()).str()
|
|
);
|
|
}
|
|
ret |= f->second;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static const std::unordered_map<fbstring,fbstring> g_serializedDefaults = {
|
|
{"true", "b:1;"},
|
|
{"false", "b:0;"},
|
|
{"null", "N;"},
|
|
{"empty_array", "a:0:{}"},
|
|
{"null_string", "N;"},
|
|
{"null_array", "N;"},
|
|
{"null_object", "N;"},
|
|
{"null_resource", "N;"},
|
|
{"null_variant", "N;"},
|
|
{"INT_MAX", "i:2147483647;"}, // (1 << 31) - 1
|
|
};
|
|
|
|
static const std::unordered_map<fbstring,fbstring> g_phpDefaults = {
|
|
{"true", "true"},
|
|
{"false", "false"},
|
|
{"null", "null"},
|
|
{"empty_array", "array()"},
|
|
{"null_string", "null"},
|
|
{"null_array", "null"},
|
|
{"null_object", "null"},
|
|
{"null_resource", "null"},
|
|
{"null_variant", "null"},
|
|
{"INT_MAX", "null"},
|
|
};
|
|
|
|
static fbstring unescapeString(fbstring val) {
|
|
fbstring s = "";
|
|
for (int i = 0; i < val.size(); ) {
|
|
int ch = val[i++];
|
|
if (ch == '\\') {
|
|
if (i == val.size()) {
|
|
throw std::logic_error(
|
|
folly::format("Malformed string: '{0}'", val).str());
|
|
}
|
|
ch = val[i++];
|
|
switch (ch) {
|
|
case 'n': ch = '\n'; break;
|
|
case 'r': ch = '\r'; break;
|
|
case 't': ch = '\t'; break;
|
|
case '/':
|
|
case '"':
|
|
case '\'':
|
|
case '\\':break;
|
|
case '0':
|
|
ch = 0;
|
|
if (i == val.size() ||
|
|
(!isdigit(val[i]) && val[i] != 'x' && val[i] != 'X')) {
|
|
break;
|
|
}
|
|
// fall through
|
|
default:
|
|
throw std::logic_error(
|
|
folly::format("Malformed string: '{0}'", val).str());
|
|
break;
|
|
}
|
|
}
|
|
s += (char)ch;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/**
|
|
* From idl/base.php:get_serialized_default()
|
|
*/
|
|
fbstring PhpParam::getDefaultSerialized() const {
|
|
auto valIt = m_param.find("value");
|
|
if (valIt == m_param.items().end()) {
|
|
return ""; // No default
|
|
}
|
|
auto dval = valIt->second;
|
|
if (!dval.isString()) {
|
|
throw std::logic_error(
|
|
folly::format("Parameter '{0}' default value is non-string",
|
|
m_name).str()
|
|
);
|
|
}
|
|
auto val = dval.asString();
|
|
if (!val.size()) {
|
|
throw std::logic_error(
|
|
folly::format("Parameter '{0}' default value malformed (empty string), "
|
|
"specify \"\" as default value for actual empty string",
|
|
m_name).str()
|
|
);
|
|
}
|
|
|
|
// Function calls "foo()" or "foo::bar()" to C/C++ functions/static methods,
|
|
// a constant, or a bitmask of constants
|
|
//
|
|
// Used by ext_reflection to resolve the value at runtime or
|
|
// represent the function/method call.
|
|
if ((val.size() > 2) &&
|
|
(!strncmp(val.c_str(), "k_", 2) ||
|
|
!strncmp(val.c_str(), "q_", 2) ||
|
|
!strcmp(val.c_str() + val.size() - 2, "()"))) {
|
|
return "\x01";
|
|
}
|
|
|
|
// Fixed substitutions
|
|
auto it = g_serializedDefaults.find(val);
|
|
if (it != g_serializedDefaults.end()) {
|
|
return it->second;
|
|
}
|
|
|
|
if (val == "RAND_MAX") {
|
|
return folly::to<fbstring>("i:", RAND_MAX, ";");
|
|
}
|
|
|
|
// Quoted string: "foo"
|
|
if ((val.size() >= 2) && (val[0] == '"') && (val[val.size()-1] == '"')) {
|
|
auto s = unescapeString(val.substr(1, val.size() - 2));
|
|
return phpSerialize(s);
|
|
}
|
|
|
|
// Integers and Floats
|
|
if (strchr(val.c_str(), '.')) {
|
|
// Decimal float?
|
|
char *e = nullptr;
|
|
double dval = strtod(val.c_str(), &e);
|
|
if (e && !*e) {
|
|
return folly::to<fbstring>("d:", dval, ";");
|
|
}
|
|
}
|
|
|
|
if (val[0] == '0') {
|
|
if ((val.size() > 1) && (val[1] == 'x')) {
|
|
// Hex?
|
|
char *e = nullptr;
|
|
long lval = strtol(val.c_str() + 2, &e, 16);
|
|
if (e && !*e) {
|
|
return folly::to<fbstring>("i:", lval, ";");
|
|
}
|
|
} else {
|
|
// Octal?
|
|
char *e = nullptr;
|
|
long lval = strtol(val.c_str() + 1, &e, 8);
|
|
if (e && !*e) {
|
|
return folly::to<fbstring>("i:", lval, ";");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Decimal?
|
|
char *e = nullptr;
|
|
long lval = strtol(val.c_str(), &e, 10);
|
|
if (e && !*e) {
|
|
return folly::to<fbstring>("i:", lval, ";");
|
|
}
|
|
|
|
throw std::logic_error(
|
|
folly::format("'{0}' is not a valid default arg value", val).str()
|
|
);
|
|
}
|
|
|
|
static fbstring transformConstants(const fbstring val) {
|
|
fbstring ret = val;
|
|
int i = 0;
|
|
int len = ret.size();
|
|
|
|
while (i < len) {
|
|
while ((i < len) && (ret[i] == ' ')) i++;
|
|
if ((len - i) < 2) break;
|
|
|
|
if ((ret[i+1] == '_') &&
|
|
((ret[i] == 'k') || (ret[i] == 'q'))) {
|
|
ret[i] = ret[i+1] = ' ';
|
|
}
|
|
while ((i < len) && (ret[i] != '|')) {
|
|
if (ret[i] == '$') {
|
|
ret[i] = ':';
|
|
}
|
|
i++;
|
|
}
|
|
i++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
fbstring PhpParam::getDefaultPhp() const {
|
|
fbstring val = getDefault();
|
|
if (!val.size()) {
|
|
return "";
|
|
}
|
|
|
|
auto it = g_phpDefaults.find(val);
|
|
if (it != g_phpDefaults.end()) {
|
|
return it->second;
|
|
}
|
|
|
|
if (val == "RAND_MAX") {
|
|
return folly::to<fbstring>(RAND_MAX);
|
|
}
|
|
|
|
if ((val.size() > 2) && (val[1] == '_') &&
|
|
((val[0] == 'k') || (val[0] == 'q'))) {
|
|
return transformConstants(val);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
fbstring phpSerialize(const folly::dynamic& d) {
|
|
if (d.isNull()) {
|
|
return "N;";
|
|
}
|
|
if (d.isBool()) {
|
|
return d.asBool() ? "b:1;" : "b:0;";
|
|
}
|
|
if (d.isInt()) {
|
|
return "i:" + d.asString() + ";";
|
|
}
|
|
if (d.isDouble()) {
|
|
return "d:" + d.asString() + ";";
|
|
}
|
|
if (d.isString()) {
|
|
auto str = d.asString();
|
|
return folly::to<fbstring>("s:", str.size(), ":\"", str, "\";");
|
|
}
|
|
if (d.isArray()) {
|
|
fbstring ret = folly::to<fbstring>("a:", d.size(), ":{");
|
|
int i = 0;
|
|
for (auto &v : d) {
|
|
ret += folly::to<fbstring>("i:", i, ";", phpSerialize(v));
|
|
}
|
|
return ret + "};";
|
|
}
|
|
if (d.isObject()) {
|
|
fbstring ret = folly::to<fbstring>("a:", d.size(), ":{");
|
|
int nextindex = 0;
|
|
for (auto &k : d.keys()) {
|
|
if (k.isNull()) {
|
|
ret += "i:0;";
|
|
if (nextindex <= 0) {
|
|
nextindex = 1;
|
|
}
|
|
} else if (k.isInt() || k.isDouble()) {
|
|
int i = k.asInt();
|
|
ret += folly::to<fbstring>("i:", i, ";");
|
|
if (nextindex <= i) {
|
|
nextindex = i + 1;
|
|
}
|
|
} else if (k.isString()) {
|
|
ret += folly::to<fbstring>("s:", k.size(), ":\"",
|
|
escapeCpp(k.asString()), "\";");
|
|
} else {
|
|
/* Should never be reached, but cover it to be safe */
|
|
ret += folly::to<fbstring>("i:", nextindex++, ";");
|
|
}
|
|
ret += phpSerialize(d[k]);
|
|
}
|
|
return ret + "};";
|
|
}
|
|
throw std::logic_error("Unhandled dynamic type in php serialization");
|
|
return "N;";
|
|
}
|
|
|
|
static fbstring getFollyDynamicDefaultString(const folly::dynamic& d,
|
|
const fbstring& key,
|
|
const fbstring& def) {
|
|
auto it = d.find(key);
|
|
if (it == d.items().end()) {
|
|
return def;
|
|
}
|
|
auto val = it->second;
|
|
if (val.isNull()) {
|
|
return def;
|
|
}
|
|
return val.asString();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// PhpConst
|
|
|
|
bool PhpConst::parseType(const folly::dynamic& cns) {
|
|
auto it = cns.find("type");
|
|
if (it != cns.items().end()) {
|
|
m_kindOf = kindOfFromDynamic(it->second);
|
|
m_cppType = typeString(it->second, false);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool PhpConst::inferType(const folly::dynamic& cns) {
|
|
auto it = cns.find("value");
|
|
if (it != cns.items().end()) {
|
|
m_kindOf = kindOfFromValue(it->second);
|
|
auto typeIt = g_typeMap.find((int)m_kindOf);
|
|
if (typeIt != g_typeMap.end()) {
|
|
m_cppType = typeIt->second;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
PhpConst::PhpConst(const folly::dynamic& cns,
|
|
fbstring cls /* = "" */) :
|
|
m_constant(cns),
|
|
m_name(cns["name"].asString()),
|
|
m_className(cls) {
|
|
if (!parseType(cns) && !inferType(cns)) {
|
|
// Constant has neither explicit type nor implicit type from 'value'
|
|
assert(false);
|
|
m_kindOf = KindOfInvalid;
|
|
m_cppType = "void";
|
|
}
|
|
|
|
// Override typeString()'s selection for string values
|
|
if (m_kindOf == KindOfString) {
|
|
m_cppType = "HPHP::StaticString";
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// PhpParam
|
|
|
|
PhpParam::PhpParam(const folly::dynamic& param,
|
|
bool isMagicMethod /*= false */,
|
|
ParamMode paramMode /*= CoerceAndCall */) :
|
|
m_name(param["name"].asString()),
|
|
m_param(param),
|
|
m_desc(getFollyDynamicDefaultString(param, "desc", "")),
|
|
m_paramMode(paramMode) {
|
|
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);
|
|
}
|
|
|
|
m_phpType = phpTypeFromDataType(m_kindOf);
|
|
}
|
|
|
|
bool PhpParam::defValueNeedsVariable() const {
|
|
DataType cppKindOf = kindOf();
|
|
|
|
if (!hasDefault() || !isIndirectPass()) {
|
|
return false;
|
|
}
|
|
|
|
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" || defVal == "null_resource")) {
|
|
return false;
|
|
}
|
|
if ((cppKindOf == KindOfAny) && (defVal == "null_variant")) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// PhpFunc
|
|
|
|
PhpFunc::PhpFunc(const folly::dynamic& d,
|
|
const fbstring& className) :
|
|
m_name(d["name"].asString()),
|
|
m_className(className),
|
|
m_func(d),
|
|
m_desc(getFollyDynamicDefaultString(d, "desc", "")),
|
|
m_returnRef(d.getDefault("ref", "false") == "true"),
|
|
m_returnKindOf(KindOfNull),
|
|
m_returnCppType("void"),
|
|
m_returnPhpType("void"),
|
|
m_minNumParams(0),
|
|
m_numTypeChecks(0) {
|
|
auto returnIt = d.find("return");
|
|
if (returnIt != d.items().end()) {
|
|
auto retNode = returnIt->second;
|
|
auto typeIt = retNode.find("type");
|
|
if (typeIt != retNode.items().end()) {
|
|
auto type = typeIt->second;
|
|
if ((type.isString()) && (type != "void") && (type != "null")) {
|
|
m_returnKindOf = m_returnRef ? KindOfRef : kindOfFromDynamic(type);
|
|
m_returnCppType = typeString(type, true);
|
|
m_returnPhpType = phpTypeFromDataType(m_returnKindOf);
|
|
}
|
|
}
|
|
m_returnDesc = getFollyDynamicDefaultString(retNode, "desc", "");
|
|
}
|
|
|
|
auto args = d.find("args");
|
|
if (args == d.items().end() || !args->second.isArray()) {
|
|
throw std::logic_error(
|
|
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()
|
|
);
|
|
}
|
|
|
|
bool magic = isMagicMethod();
|
|
|
|
m_flags = parseFlags(m_func["flags"]);
|
|
|
|
ParamMode paramMode = (m_flags & ZendParamMode) ?
|
|
ParamMode::Zend : ParamMode::CoerceAndCall;
|
|
|
|
for (auto &p : args->second) {
|
|
PhpParam param(p, magic, paramMode);
|
|
m_params.push_back(param);
|
|
if (!param.hasDefault()) {
|
|
++m_minNumParams;
|
|
}
|
|
if (param.isCheckedType()) {
|
|
++m_numTypeChecks;
|
|
}
|
|
}
|
|
}
|
|
|
|
fbstring PhpFunc::getCppSig() const {
|
|
std::ostringstream out;
|
|
|
|
fbstring nm = name();
|
|
fbstring lowername = nm;
|
|
std::transform(nm.begin(), nm.end(), lowername.begin(),
|
|
std::ptr_fun<int, int>(std::tolower));
|
|
|
|
if (!isMethod()) {
|
|
out << "HPHP::f_" << lowername << "(";
|
|
} else {
|
|
if (isStatic()) {
|
|
out << "HPHP::c_" << className() << "::ti_" << lowername << "(";
|
|
} else {
|
|
out << "HPHP::c_" << className() << "::t_" << lowername << "(";
|
|
}
|
|
}
|
|
|
|
bool firstParam = true;
|
|
if (isVarArgs()) {
|
|
if (!firstParam) {
|
|
out << ", ";
|
|
}
|
|
out << "int";
|
|
firstParam = false;
|
|
}
|
|
|
|
for (auto const& param : m_params) {
|
|
if (!firstParam) {
|
|
out << ", ";
|
|
}
|
|
out << param.getCppType();
|
|
firstParam = false;
|
|
}
|
|
|
|
if (isVarArgs()) {
|
|
assert(!firstParam);
|
|
out << ", HPHP::Array const&";
|
|
}
|
|
|
|
out << ")";
|
|
return out.str();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// PhpProp
|
|
|
|
PhpProp::PhpProp(const folly::dynamic& d, fbstring cls) :
|
|
m_name(d["name"].asString()),
|
|
m_className(cls),
|
|
m_prop(d),
|
|
m_flags(parseFlags(m_prop["flags"])),
|
|
m_kindOf(kindOfFromDynamic(m_prop["type"])) {
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// PhpClass
|
|
|
|
PhpClass::PhpClass(const folly::dynamic &c) :
|
|
m_class(c),
|
|
m_name(c["name"].asString()),
|
|
m_flags(parseFlags(m_class["flags"])),
|
|
m_desc(getFollyDynamicDefaultString(c, "desc", "")) {
|
|
|
|
auto ifacesIt = m_class.find("ifaces");
|
|
if (ifacesIt != m_class.items().end()) {
|
|
auto ifaces = ifacesIt->second;
|
|
if (!ifaces.isArray()) {
|
|
throw std::logic_error(
|
|
folly::format("Class {0}.ifaces field must be an array", m_name).str()
|
|
);
|
|
}
|
|
for (auto &interface : ifaces) {
|
|
m_ifaces.push_back(interface.asString());
|
|
}
|
|
}
|
|
|
|
for (auto const& f : c["funcs"]) {
|
|
PhpFunc func(f, m_name);
|
|
m_methods.push_back(func);
|
|
}
|
|
|
|
if (c.find("consts") != c.items().end()) {
|
|
for (auto const& cns : c["consts"]) {
|
|
PhpConst cons(cns, m_name);
|
|
m_constants.push_back(cons);
|
|
}
|
|
}
|
|
|
|
if (c.find("properties") != c.items().end()) {
|
|
for (auto const& prp : c["properties"]) {
|
|
PhpProp prop(prp, m_name);
|
|
m_properties.push_back(prop);
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void parseIDL(const char* idlFilePath,
|
|
fbvector<PhpFunc>& funcVec,
|
|
fbvector<PhpClass>& classVec,
|
|
fbvector<PhpConst>& constVec,
|
|
fbvector<PhpExtension>& extVec) {
|
|
std::ostringstream jsonString;
|
|
std::ifstream infile(idlFilePath);
|
|
infile >> jsonString.rdbuf();
|
|
|
|
auto parsed = folly::parseJson(jsonString.str());
|
|
|
|
for (auto const& f : parsed["funcs"]) {
|
|
PhpFunc func(f, "");
|
|
funcVec.push_back(func);
|
|
}
|
|
for (auto const& c : parsed["classes"]) {
|
|
PhpClass klass(c);
|
|
classVec.push_back(klass);
|
|
}
|
|
for (auto const& c : parsed["consts"]) {
|
|
PhpConst cns(c);
|
|
constVec.push_back(cns);
|
|
}
|
|
auto it = parsed.find("extension");
|
|
if (it != parsed.items().end()) {
|
|
PhpExtension ext(it->second);
|
|
extVec.push_back(ext);
|
|
}
|
|
}
|
|
|
|
void parseIDL(const char* idlFilePath,
|
|
fbvector<PhpFunc>& funcVec,
|
|
fbvector<PhpClass>& classVec) {
|
|
fbvector<PhpConst> consts; // dummy
|
|
fbvector<PhpExtension> exts; // dummy
|
|
parseIDL(idlFilePath, funcVec, classVec, consts, exts);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
}} // namespace HPHP::IDL
|