array('name' => 'bool', 'enum' => 'Boolean', 'idlname' => 'Boolean', 'phpname' => 'bool'), Int32 => array('name' => 'int', 'enum' => 'Int32', 'idlname' => 'Int32', 'phpname' => 'int'), Int64 => array('name' => 'int64_t', 'enum' => 'Int64', 'idlname' => 'Int64', 'phpname' => 'int'), Double => array('name' => 'double', 'enum' => 'Double', 'idlname' => 'Double', 'phpname' => 'float'), String => array('name' => 'String', 'enum' => 'String', 'idlname' => 'String', 'phpname' => 'string'), Int64Vec => array('name' => 'Array', 'enum' => 'Array', 'idlname' => 'Int64Vec', 'phpname' => 'vector'), StringVec => array('name' => 'Array', 'enum' => 'Array', 'idlname' => 'StringVec', 'phpname' => 'vector'), VariantVec => array('name' => 'Array', 'enum' => 'Array', 'idlname' => 'VariantVec', 'phpname' => 'vector'), Int64Map => array('name' => 'Array', 'enum' => 'Array', 'idlname' => 'Int64Map', 'phpname' => 'map'), StringMap => array('name' => 'Array', 'enum' => 'Array', 'idlname' => 'StringMap', 'phpname' => 'map'), VariantMap => array('name' => 'Array', 'enum' => 'Array', 'idlname' => 'VariantMap', 'phpname' => 'map'), Object => array('name' => 'Object', 'enum' => 'Object', 'idlname' => 'Object', 'phpname' => 'object'), Resource => array('name' => 'Object', 'enum' => 'Object', 'idlname' => 'Resource', 'phpname' => 'resource'), Variant => array('name' => 'Variant', 'enum' => 'Variant', 'idlname' => 'Variant', 'phpname' => 'mixed'), Numeric => array('name' => 'Numeric', 'enum' => 'Numeric', 'idlname' => 'Numeric', 'phpname' => 'number'), Primitive => array('name' => 'Primitive', 'enum' => 'Primitive', 'idlname' => 'Primitive', 'phpname' => 'num|string'), PlusOperand => array('name' => 'PlusOperand', 'enum' => 'PlusOperand', 'idlname' => 'PlusOperand','phpname' => 'num|array'), Sequence => array('name' => 'Sequence', 'enum' => 'Sequence', 'idlname' => 'Sequence', 'phpname' => 'string|array'), Any => array('name' => 'Variant', 'enum' => 'Some', 'idlname' => 'Any', 'phpname' => 'mixed'), ); $REFNAMES = array('String' => 'CStrRef', 'Array' => 'CArrRef', 'Object' => 'CObjRef', 'Variant' => 'CVarRef', 'Numeric' => 'CVarRef', 'Primitive' => 'CVarRef', 'PlusOperand' => 'CVarRef', 'Sequence' => 'CVarRef', ); $MAGIC_METHODS = array('__get' => 'ObjectData::UseGet', '__set' => 'ObjectData::UseSet', '__isset' => 'ObjectData::UseIsset', '__unset' => 'ObjectData::UseUnset', '__call' => 'ObjectData::HasCall', '__callStatic' => 'ObjectData::HasCallStatic'); function get_idl_name($type, $null = '') { global $TYPENAMES; if ($type === null) { return $null; } if (is_string($type)) { return "'$type'"; } if ($type & Reference) { return $TYPENAMES[$type & ~Reference]['idlname'] . ' | Reference'; } return $TYPENAMES[$type]['idlname']; } function get_php_name($type, $null = 'mixed') { global $TYPENAMES; if ($type === null) { return $null; } if (is_string($type)) { return $type; } if ($type & Reference) { return $TYPENAMES[$type & ~Reference]['phpname']; } return $TYPENAMES[$type]['phpname']; } /////////////////////////////////////////////////////////////////////////////// // flags // ClassInfo attributes, and these numbers need to be consistent with them! define('ZendParamMode', 1 << 0); define('IsAbstract', 1 << 4); define('IsFinal', 1 << 5); define('IsPublic', 1 << 6); define('IsProtected', 1 << 7); define('IsPrivate', 1 << 8); define('AllowOverride', 1 << 8); define('IsStatic', 1 << 9); // FIXME (#2163116): IsInherited = (1 << 10) in base_class.h define('IsCppAbstract', 1 << 10); define('IsReference', 1 << 11); define('IsConstructor', 1 << 12); define('IsNothing', 1 << 13); define('HasDocComment', 1 << 14); define('HipHopSpecific', 1 << 16); define('VariableArguments', 1 << 17); define('RefVariableArguments', 1 << 18); define('MixedVariableArguments', 1 << 19); define('FunctionIsFoldable', 1 << 20); define('NoEffect', 1 << 21); define('NoInjection', 1 << 22); define('HasOptFunction', 1 << 23); define('AllowIntercept', 1 << 24); define('NoProfile', 1 << 25); define('ContextSensitive', 1 << 26); define('NoDefaultSweep', 1 << 27); define('IsSystem', 1 << 28); define('IsTrait', 1 << 29); define('NeedsActRec', 1 << 31); // Mask for checking the flags related to variable arguments define('VarArgsMask', (VariableArguments | RefVariableArguments | MixedVariableArguments)); function get_flag_names($arr, $name, $global_func) { $flag = 0; if (!empty($arr[$name])) { $flag |= $arr[$name]; } if ($flag == 0) return ''; $ret = ''; if ($flag & IsAbstract ) $ret .= ' | IsAbstract' ; if ($flag & IsFinal ) $ret .= ' | IsFinal' ; if ($flag & IsPublic ) $ret .= ' | IsPublic' ; if ($flag & IsProtected ) $ret .= ' | IsProtected' ; if ($global_func) { if ($flag & AllowOverride ) $ret .= ' | AllowOverride' ; } else { if ($flag & IsPrivate ) $ret .= ' | IsPrivate' ; } if ($flag & IsStatic ) $ret .= ' | IsStatic' ; if ($flag & HasDocComment ) $ret .= ' | HasDocComment' ; if ($flag & HipHopSpecific ) $ret .= ' | HipHopSpecific' ; if ($flag & VariableArguments ) $ret .= ' | VariableArguments' ; if ($flag & RefVariableArguments ) $ret .= ' | RefVariableArguments' ; if ($flag & MixedVariableArguments) $ret .= ' | MixedVariableArguments'; if ($flag & FunctionIsFoldable ) $ret .= ' | FunctionIsFoldable' ; if ($flag & NoEffect ) $ret .= ' | NoEffect' ; if ($flag & NoInjection ) $ret .= ' | NoInjection' ; if ($flag & HasOptFunction ) $ret .= ' | HasOptFunction' ; if ($flag & AllowIntercept ) $ret .= ' | AllowIntercept' ; if ($flag & NoProfile ) $ret .= ' | NoProfile' ; if ($flag & ContextSensitive ) $ret .= ' | ContextSensitive' ; if ($flag & NoDefaultSweep ) $ret .= ' | NoDefaultSweep' ; if ($flag & IsTrait ) $ret .= ' | IsTrait' ; if ($flag & NeedsActRec ) $ret .= ' | NeedsActRec' ; if ($ret == '') { throw new Exception("invalid flag $flag"); } return substr($ret, 2); } function read_array_of_constant_names($flag_arr) { if (!is_array($flag_arr)) { return 0; } $flag = 0; foreach ($flag_arr as $constname) { $flag |= constant($constname); } return $flag; } /////////////////////////////////////////////////////////////////////////////// // schema functions that will be used (and only used) by schemas function ResetSchema() { global $current_class, $preamble, $funcs, $classes, $constants; $current_class = ''; $preamble = ''; $funcs = array(); $classes = array(); $constants = array(); } ResetSchema(); function BeginClass($class) { global $classes, $current_class; $current_class = $class['name']; if (!isset($class['parent'])) $class['parent'] = null; if (!isset($class['ifaces'])) $class['ifaces'] = array(); if (!isset($class['bases'])) $class['bases'] = array(); $class['methods'] = array(); $class['properties'] = array(); $class['consts'] = array(); $class['flags'] = read_array_of_constant_names($class['flags']); $doc = get_class_doc_comments($class); if (!empty($doc)) { $class['flags'] |= HasDocComment; $class['doc'] = $doc; } else { $class['flags'] &= ~HasDocComment; $class['doc'] = null; } $classes[$current_class] = $class; } function EndClass() { global $classes, $current_class; $have_ctor = false; foreach ($classes[$current_class]['methods'] as $method) { if ($method['name'] == '__construct') $have_ctor = true; } // We don't have the information to autogenerate a ctor def, // so make the user do it. if (!$have_ctor) { throw new Exception("No constructor defined for class $current_class"); } $current_class = ''; } function idl_parse_type($t) { if (defined($t) && ($v = constant($t)) && is_integer($v) && ($v > 0) && ($v < TypeMask)) { return $v; } error_log("Undefined type: $t", E_USER_WARNING); return $t; } function idl_infer_type($v) { switch(gettype($v)) { case 'boolean': return Boolean; case 'integer': return Int64; case 'double': return Double; case 'string': return String; case 'array': return VariantMap; case 'object': return Object; case 'resource': return Resource; default: return Any; } } function DefineConstant($const) { global $constants, $classes, $current_class; if (!isset($const['type']) && array_key_exists('value', $const)) { $const['type'] = idl_infer_type($const['value']); } else { $const['type'] = idl_parse_type($const['type']); } if (empty($current_class)) { $constants[] = $const; } else { $classes[$current_class]['consts'][] = $const; } } function DefineFunction($func) { global $classes, $current_class; if (empty($func['flags'])) { $func['flags'] = 0; } else { $func['flags'] = read_array_of_constant_names($func['flags']); if ($current_class && $classes[$current_class]['flags'] & HipHopSpecific) { $func['flags'] |= HipHopSpecific; } } if (!isset($func['return'])) $func['return'] = array(); $func['ret_desc'] = idx($func['return'], 'desc'); $func['ret_hint'] = idx($func['return'], 'hint'); if (isset($func['return']['type'])) { if (idx($func['return'], 'ref')) { $func['return'] = Variant; } else { $func['return'] = idl_parse_type($func['return']['type']); } } else { $func['return'] = null; } $args = array(); if (!empty($func['args'])) { foreach ($func['args'] as $arg) { if (array_key_exists('value', $arg)) { if (!is_string($arg['value']) || $arg['value'] === '') { throw new Exception('default value has to be non-empty string for '. $func['name'].'(..'.$arg['name'].'..)'); } if (preg_match('/^q_([A-Za-z]+)_(\w+)$/', $arg['value'], $m)) { $class = $m[1]; $constant = $m[2]; $arg['default'] = "q_${class}_${constant}"; } else { $arg['default'] = $arg['value']; } $arg['defaultSerialized'] = get_serialized_default($arg['value']); $arg['defaultText'] = get_default_text($arg['value']); } if (idx($arg, 'ref')) { $arg['type'] = Variant; } else { $arg['type'] = idl_parse_type($arg['type']); } $args[] = $arg; } $func['args'] = $args; } else { $func['args'] = array(); } $doc = get_function_doc_comments($func, $current_class); if (!empty($doc)) { $func['flags'] |= HasDocComment; $func['doc'] = $doc; } else { $func['flags'] &= ~HasDocComment; $func['doc'] = null; } global $funcs, $classes, $current_class; if (empty($current_class)) { $funcs[] = $func; } else { $classes[$current_class]['methods'][] = $func; } } /////////////////////////////////////////////////////////////////////////////// // Read an IDL file into the 'funcs', 'classes' and 'consts' globals function ReadIDLFile($path) { $entries = json_decode(file_get_contents($path), /* use arrays */ true); if (!$entries) { throw new Exception("Unable to parse json from $path"); } if (!empty($entries['funcs'])) { foreach ($entries['funcs'] as $func) { DefineFunction($func); } } if (!empty($entries['consts'])) { foreach ($entries['consts'] as $const) { DefineConstant($const); } } foreach ($entries['classes'] as $class) { $methods = isset($class['funcs']) ? $class['funcs'] : array(); $consts = isset($class['consts']) ? $class['consts'] : array(); unset($class['funcs']); unset($class['consts']); BeginClass($class); foreach ($methods as $method) { DefineFunction($method); } foreach ($consts as $const) { DefineConstant($const); } EndClass(); } } /////////////////////////////////////////////////////////////////////////////// // code generation function typename($type, $prefix = true) { if (is_string($type)) { if ($prefix) return 'p_' . $type; return $type; } global $TYPENAMES; $type = $type & TypeMask; if ($type !== 0) { if (!isset($TYPENAMES[$type])) { exit("Unknown type $type\n"); } return $TYPENAMES[$type]['name']; } return 'void'; } function typeidlname($type, $null = '') { global $TYPENAMES; if ($type === null) { return $null; } if (is_string($type)) { return "'$type'"; } if ($type & Reference) { return $TYPENAMES[$type & ~Reference]['idlname']; } return $TYPENAMES[$type]['idlname']; } function param_typename($arg, $forceRef = false) { $type = $arg['type']; if (is_string($type)) { return 'p_' . $type; } global $REFNAMES; $name = typename($type); $ref = idx($arg, 'ref'); if (idx($arg, 'ref')) { return ($name === "Variant") ? "VRefParam" : $name; } if ($forceRef) { return $name; } return isset($REFNAMES[$name]) ? $REFNAMES[$name] : $name; } function typeenum($type) { if (is_string($type)) { return 'Void'; } global $TYPENAMES; $type = $type & TypeMask; if ($type !== 0) { return $TYPENAMES[$type]['enum']; } return 'Void'; } function fprintType($f, $type) { if (is_string($type)) { fprintf($f, 'S(999), "%s"', $type); } else { fprintf($f, 'T(%s)', typeenum($type)); } } function get_serialized_default($s) { // These values are special and cannot be returned by // ReflectionParameter::getDefaultValue(). if ($s == 'TimeStamp::Current()' || preg_match('/^k_SQLITE3_/', $s)) { return "\x01"; } if (preg_match('/^".*"$/', $s) || preg_match('/^[\-0-9.]+$/', $s) || preg_match('/^0x[0-9a-fA-F]+$/', $s) || preg_match('/^(true|false|null)$/', $s)) { return serialize(eval("return $s;")); } if ($s == "empty_array") return serialize(array()); if (preg_match('/^null_(string|array|object|variant)$/', $s)) { return serialize(null); } if (preg_match('/^k_\w+( ?\| ?k_\w+)*$/', $s, $m)) { $s = preg_replace('/k_/', '', $s); return serialize(eval("return $s;")); } if (preg_match('/^q_([A-Za-z]+)\$\$(\w+)$/', $s, $m)) { $class = $m[1]; $constant = $m[2]; return serialize(eval("return $class::$constant;")); } if ($s == 'RAND_MAX') { return serialize(getrandmax()); } if ($s == 'INT_MAX') { return serialize((1 << 31) - 1); } throw new Exception("Unable to serialize default value: [$s]"); } function get_default_text($s) { if (preg_match('/^null_(string|array|object|variant)$/', $s)) { return 'null'; } if (preg_match('/^k_\w+( ?\| ?k_\w+)*$/', $s, $m)) { return preg_replace('/k_/', '', $s); } if (preg_match('/^q_([A-Za-z]+)_(\w+)$/', $s, $m)) { $class = $m[1]; $constant = $m[2]; return "$class::$constant"; } return $s; } function generateFuncCPPInclude($func, $f, $newline = true) { fprintf($f, '"%s", ', $func['name']); fprintType($f, $func['return']); fprintf($f, ', S(%d), ', idx($func, 'ref') ? 1 : 0); for ($i = 0; $i < count($func['args']); $i++) { $arg = $func['args'][$i]; fprintf($f, '"%s", ', $arg['name']); fprintType($f, $arg['type']); fprintf($f, ', '); if (isset($arg['default'])) { $serialized = escape_cpp($arg['defaultSerialized']); fprintf($f, '"%s", S(%d), ', $serialized, strlen($arg['defaultSerialized'])); fprintf($f, '"%s", ', escape_cpp($arg['defaultText'])); } else { fprintf($f, 'NULL, S(0), NULL, '); } fprintf($f, 'S(%d), ', idx($arg, 'ref') ? 1 : 0); } fprintf($f, "NULL, "); fprintf($f, 'S(%d), ', $func['flags']); if (!empty($func['doc'])) { fprintf($f, '"%s", ', escape_cpp($func['doc'])); } if (!empty($func['opt'])) { fprintf($f, 'S(%s), ', $func['opt']); } if ($newline) fprintf($f, "\n"); } function generateFuncOptDecls($func, $f) { if ($func['opt']) { fprintf($f, "extern ExpressionPtr ". "%s(CodeGenerator *cg, AnalysisResultConstPtr ar, ". "SimpleFunctionCallPtr call, int mode);\n", $func['opt']); } } function generateConstCPPInclude($const, $f) { fprintf($f, '"%s", T(%s),'. "\n", $const['name'], typeenum($const['type'])); } function generateClassCPPInclude($class, $f) { fprintf($f, '"%s", "%s", ', $class['name'], strtolower($class['parent'])); foreach ($class['ifaces'] as $if) { fprintf($f, '"%s",', strtolower($if)); } fprintf($f, 'NULL, '); foreach ($class['methods'] as $m) { generateMethodCPPInclude($m, $f); fprintf($f, ","); } fprintf($f, "NULL,"); foreach ($class['properties'] as $p) { generatePropertyCPPInclude($p, $f); fprintf($f, ","); } fprintf($f, "NULL,"); foreach ($class['consts'] as $k) { fprintf($f, '"%s", T(%s),', $k['name'], typeenum($k['type'])); } fprintf($f, "NULL,\n"); fprintf($f, 'S(%d), ', $class['flags']); if (!empty($class['doc'])) { fprintf($f, '"%s", ', escape_cpp($class['doc'])); } } function generateMethodCPPInclude($method, $f) { generateFuncCPPInclude($method, $f, false, 'G'); fprintf($f, "S(%d)", $method['flags']); } function generatePropertyCPPInclude($property, $f) { fprintf($f, "S(%d), \"%s\", ", $property['flags'], $property['name']); fprintType($f, $property['type']); } function generateFuncArgsCPPHeader($func, $f, $forceRef = false, $static = false) { $var_arg = ($func['flags'] & VarArgsMask); $args = $func['args']; fprintf($f, "("); if ($var_arg) fprintf($f, 'int _argc'); if ($var_arg && count($args) > 0) fprintf($f, ', '); for ($i = 0; $i < count($args); $i++) { $arg = $args[$i]; if ($i > 0) fprintf($f, ', '); fprintf($f, '%s %s', param_typename($arg, $forceRef), $arg['name']); if (isset($arg['default'])) { fprintf($f, ' = %s', $arg['default']); } } if ($var_arg) { fprintf($f, ', CArrRef _argv = null_array'); } fprintf($f, ")"); } function generateFuncArgsCall($func, $f) { $var_arg = ($func['flags'] & VarArgsMask); $args = $func['args']; if ($var_arg) fprintf($f, '_argc'); if ($var_arg && count($args) > 0) fprintf($f, ', '); for ($i = 0; $i < count($args); $i++) { $arg = $args[$i]; fprintf($f, ', '); fprintf($f, '%s', $arg['name']); } if ($var_arg) { fprintf($f, ', _argv'); } } function generateFuncCPPForwardDeclarations($func, $f) { if (is_string($func['return'])) { fprintf($f, "FORWARD_DECLARE_CLASS_BUILTIN(%s);\n", typename($func['return'], false)); } foreach ($func['args'] as $arg) { if (is_string($arg['type'])) { fprintf($f, "FORWARD_DECLARE_CLASS_BUILTIN(%s);\n", typename($arg['type'], false)); } } } function generateFuncCPPHeader($func, $f, $method = false, $forceRef = false, $static = false, $class = false) { if ($method) { fprintf($f, '%s%s %s_%s', $static ? 'static ' : '', typename($func['return']), $static ? "ti" : "t", strtolower($func['name'])); } else { generateFuncCPPForwardDeclarations($func, $f); fprintf($f, '%s f_%s', typename($func['return']), $func['name']); } generateFuncArgsCPPHeader($func, $f, $forceRef, $static); fprintf($f, ";\n"); } function generateConstCPPHeader($const, $f) { $name = typename($const['type']); if ($name == 'String') { $name = 'StaticString'; } fprintf($f, "extern const %s k_%s;\n", $name, $const['name']); } function generateConstCPPImplementation($const, $f, $prefix = 'k_') { $name = typename($const['type']); if ($name == 'String') { $name = 'StaticString'; } $def = ''; if (isset($const['value'])) { if ($name == 'StaticString') { $def = '"' . addslashes($const['value']) . '"'; } else if ($name == 'bool') { $def = $const['value'] ? 'true' : 'false'; } else { $def = $const['value']; } $def = " = $def"; } fprintf($f, "const %s %s%s%s;\n", $name, $prefix, $const['name'], $def); } function generateClassCPPHeader($class, $f) { global $MAGIC_METHODS; $clsname = $class['name']; foreach ($class['consts'] as $k) { $name = typename($k['type']); if ($name == 'String') { $name = 'StaticString'; } fprintf($f, "extern const %s q_%s\$\$%s;\n", $name, $clsname, $k['name']); } fprintf($f, <<", implode('|', $flags)); $flags = false; } } foreach ($class['bases'] as $p) { fprintf($f, ", public $p"); } $parents = array(); fprintf($f, " {\n public:\n"); fprintf($f, " DECLARE_CLASS(%s, %s, %s)\n", $clsname, $clsname, $class['parent'] ? $class['parent'] : 'ObjectData'); fprintf($f, "\n"); if (!empty($class['properties'])) { fprintf($f, " // properties\n"); foreach ($class['properties'] as $p) { generatePropertyCPPHeader($p, $f); } fprintf($f, "\n"); } fprintf($f, " // need to implement\n"); if ($flags) { fprintf($f, " // constructor must call setAttributes(%s)\n", implode('|', $flags)); } fprintf($f, " public: c_%s(Class* cls = c_%s::s_cls);\n", $class['name'], $class['name']); fprintf($f, " public: ~c_%s();\n", $class['name']); foreach ($class['methods'] as $m) { generateMethodCPPHeader($m, $class, $f); } fprintf($f, "\n"); fprintf($f, " // implemented by HPHP\n"); foreach ($class['methods'] as $m) { generatePreImplemented($m, $class, $f); } if (!empty($class['footer'])) { fprintf($f, $class['footer']); } fprintf($f, "\n};\n"); } function generateClassCPPImplementation($class, $f) { foreach ($class['consts'] as $k) { generateConstCPPImplementation($k, $f, "q_{$class['name']}$$"); } foreach ($class['methods'] as $m) { generateMethodCPPImplementation($m, $class, $f); } } function generateMethodCPPHeader($method, $class, $f) { global $MAGIC_METHODS; fprintf($f, " public: "); generateFuncCPPHeader($method, $f, true, isset($MAGIC_METHODS[$method['name']]), $method['flags'] & IsStatic, $class); } function generateMethodCPPImplementation($method, $class, $f) { if ($method['flags'] & IsStatic) { $prefix = "c_{$class['name']}::ti_"; } else { $prefix = "c_{$class['name']}::t_"; } generateFuncCPPImplementation($method, $f, $prefix); } function generatePropertyCPPHeader($property, $f) { fprintf($f, " public: "); fprintf($f, "%s m_%s;\n", typename($property['type']), $property['name']); } function generatePropertyCPPForwardDeclarations($property, $f) { if (is_string($property['type'])) { fprintf($f, "FORWARD_DECLARE_CLASS_BUILTIN(%s);\n", typename($property['type'], false)); } } function generatePreImplemented($method, $class, $f) { if ($method['name'] == '__construct') { fprintf($f, " public: c_%s *create", $class['name']); generateFuncArgsCPPHeader($method, $f, true); fprintf($f, ";\n"); } } function generateFuncCPPImplementation($func, $f, $prefix = 'f_') { $schema = ""; $schema_no = 0; if ($func['return'] == Object || $func['return'] == Resource) { $schema .= '.set(' . ($schema_no++) . ', -1, "OO")'; } $output = ''; $need_ret = false; fprintf($f, '%s %s%s(', typename($func['return']), $prefix, strtolower($func['name'])); $var_arg = ($func['flags'] & VarArgsMask); if ($var_arg) fprintf($f, 'int _argc'); if ($var_arg && count($func['args']) > 0) fprintf($f, ', '); $params = ""; $params_no = 0; for ($i = 0; $i < count($func['args']); $i++) { $arg = $func['args'][$i]; if ($i > 0) fprintf($f, ', '); fprintf($f, '%s %s', param_typename($arg), $arg['name']); if (isset($arg['default'])) { fprintf($f, ' /* = %s */', $arg['default']); } if ($arg['type'] == Object || $arg['type'] == Resource) { $params .= '.set(' . ($params_no++) . ', (OpaqueObject::GetIndex(' . $arg['name'] . '))'; } else { $params .= '.set(' . ($params_no++) . ', ' . $arg['name'] . ')'; } if ($arg['type'] == Object || $arg['type'] == Resource) { if (idx($arg, 'ref')) { $schema .= '.set(' . ($schema_no++) . ', ' . $i . ', "OO")'; } else { $schema .= '.set(' . ($schema_no++) . ', ' . $i . ', "O")'; } } else if (idx($arg, 'ref')) { $schema .= '.set(' . ($schema_no++) . ', ' . $i . ', "R")'; } if (idx($arg, 'ref')) { $need_ret = true; $output .= ' '.$arg['name'].' = ((Variant)_ret[1])['.$i.'];'."\n"; } } if ($var_arg) { fprintf($f, ', CArrRef _argv /* = null_array */'); } fprintf($f, ") {\n"); fprintf($f, " throw NotImplementedException(__func__);\n"); fprintf($f, "}\n\n"); } function replaceParams($filename, $header) { global $funcs; $orig = $file = file_get_contents($filename); foreach ($funcs as &$func) { $var_arg = ($func['flags'] & VarArgsMask); $args = $func['args']; $search = '(?!return\s)\b\w+\s+f_'.$func['name'].'\s*\(\s*'; if ($var_arg) $search .= '\w+\s+\w+'; if ($var_arg && count($args) > 0) $search .= ',\s*'; for ($i = 0; $i < count($args); $i++) { $arg = $args[$i]; $search .= '\w+\s+\w+\s*'; if (isset($arg['default'])) { if ($header) { $search .= '=\s*(?:'.preg_quote($arg['default'], '/').'|\d+)\s*'; } else { $search .= '(?:\/\*\s*=\s*(?:'.preg_quote($arg['default'], '/'). '|\d+)\s*\*\/\s*)?'; } } if ($i < count($args) - 1) { $search .= ',(\s*)'; } } if ($var_arg) { if ($header) { $search .= ',\s*\w+\s+\w+\s*=\s*null_array\s*'; } else { $search .= ',(\s*)\w+\s+\w+\s*(?:\/\*\s*=\s*null_array\s*\*\/\s*)?'; } } $search .= '\)'; $replace = typename($func['return']).' f_'.$func['name'].'('; if ($var_arg) $replace .= 'int _argc, '; for ($i = 0; $i < count($args); $i++) { $arg = $args[$i]; $replace .= param_typename($arg).' '.$arg['name']; if (isset($arg['default'])) { if ($header) { $replace .= ' = '.addcslashes($arg['default'], '\\'); } else { $replace .= ' /* = '.addcslashes($arg['default'], '\\').' */'; } } if ($i < count($args) - 1) { $replace .= ',${'.($i+1).'}'; } } if ($var_arg) { if ($header) { $replace .= ', CArrRef _argv = null_array'; } else { $replace .= ',${'.($i).'}'; $replace .= 'CArrRef _argv /* = null_array */'; } } $replace .= ')'; if ($header && preg_match("/inline\s+$search/ms", $file)) { $func['inlined'] = true; } //var_dump($search, $replace); $count = preg_match_all("/$search/ms", $file, $m); if ($count == 0) { if ($header || !isset($func['inlined'])) { var_dump($search, $replace); print $func['name']." not found in $filename\n"; } } else if ($count == 1) { $file = preg_replace("/$search/ms", $replace, $file); } else { print "skipped ".$func['name']." in $filename\n"; } } if ($orig != $file) { file_put_contents($filename, $file); } } /////////////////////////////////////////////////////////////////////////////// // helpers function php_escape_val($val) { if (is_string($val)) { return '"'.escape_cpp($val).'"'; } else if ($val === true) { return 'true'; } else if ($val === false) { return 'false'; } else if ($val === null) { return 'uninit_null()'; } else { return var_export($val, true); } } function escape_php($val) { $val = preg_replace("/\\\\/", "\\\\\\\\", $val); $val = preg_replace("/\\\"/", "\\\\\"", $val); $val = preg_replace("/\\$/", "\\\\$", $val); $val = preg_replace("/\n/", "\\\\n", $val); // optional return $val; } function escape_cpp($val) { $len = strlen($val); $ret = ''; for ($i = 0; $i < $len; $i++) { $ch = $val[$i]; switch ($ch) { case "\n": $ret .= "\\n"; break; case "\r": $ret .= "\\r"; break; case "\t": $ret .= "\\t"; break; case "\a": $ret .= "\\a"; break; case "\b": $ret .= "\\b"; break; case "\f": $ret .= "\\f"; break; case "\v": $ret .= "\\v"; break; case "\0": $ret .= "\\000";break; case "\"": $ret .= "\\\""; break; case "\\": $ret .= "\\\\"; break; case "?": $ret .= "\\?"; break; // avoiding trigraph errors default: if (ord($ch) >= 0x20 && ord($ch) <= 0x7F) { $ret .= $ch; } else { $ret .= sprintf("\\%03o", ord($ch)); } break; } } return $ret; } function idx($arr, $idx, $default=null) { if ($idx === null) { return $default; } if (isset($arr[$idx])) { return $arr[$idx]; } return $default; } function format_doc_desc($arr, $clsname) { if (isset($arr['flags']) && $arr['flags'] & HipHopSpecific) { $desc = "( HipHop specific )\n"; } else { $clsname = preg_replace('#_#', '-', strtolower($clsname)); $name = preg_replace('#_#', '-', strtolower($arr['name'])); $name = preg_replace('#^--#', '', $name); $url = "http://php.net/manual/en/$clsname.$name.php"; $desc = "( excerpt from $url )\n"; } $details = idx($arr, 'desc', ''); if ($details) { $desc .= "\n$details"; } return wordwrap($desc, 72)."\n\n"; } function format_doc_arg($name, $type, $desc) { $width1 = 12; $width2 = 8; if (!$desc) $desc = ' '; $lines = explode("\n", wordwrap($desc, 72 - $width1 - $width2)); $col = str_pad('@'.$name, $width1 - 1); $ret = $col; if (strlen($col) >= $width1) { $ret .= "\n".str_repeat(' ', $width1 - 1); } $col = str_pad(get_php_name($type), $width2 - 1); $ret .= ' '.$col; if (strlen($col) >= $width2) { $ret .= "\n".str_repeat(' ', $width1 + $width2 - 1); } $ret .= ' '.$lines[0]."\n"; for ($i = 1; $i < count($lines); $i++) { $ret .= rtrim(str_repeat(' ', $width1 + $width2) . $lines[$i])."\n"; } return $ret; } function format_doc_comment($text, $indent_spaces = 0) { $lines = explode("\n", $text); $indent = str_repeat(' ', $indent_spaces); $ret = "$indent/**\n"; for ($i = 0; $i < count($lines) - 1; $i++) { $line = $lines[$i]; $ret .= rtrim("$indent * $line")."\n"; } $ret .= "$indent */"; return $ret; } function get_function_doc_comments($func, $clsname) { $text = format_doc_desc($func, empty($clsname) ? 'function' : $clsname); if ($func['args']) { foreach ($func['args'] as $arg) { $desc = idx($arg, 'desc', ''); if (idx($func, 'ref')) { $desc = '(output) ' . $desc; } $text .= format_doc_arg($arg['name'], idx($arg, 'type'), $desc); } } $ret = ($func['return'] !== null || !empty($func['ret_desc'])); if ($func['args'] && $ret) { $text .= "\n"; } if ($ret) { $text .= format_doc_arg('return', $func['return'], $func['ret_desc']); } return format_doc_comment($text, empty($clsname) ? 0 : 2); } function get_class_doc_comments($class) { return format_doc_comment(format_doc_desc($class, 'class')); } /////////////////////////////////////////////////////////////////////////////// // phpnet function phpnet_clean($text) { $text = preg_replace('##s', '', $text); $text = preg_replace('#
.*?
#s', '<>', $text); $text = preg_replace('#

#', '<>', $text); $text = preg_replace('#Note:#', '', $text); $text = preg_replace('#<.+?>#', '', $text); $text = preg_replace('#[ \t\n]+#s', ' ', $text); $text = preg_replace('# ?<> ?#', "\n\n", $text); $text = preg_replace('/'/', "'", $text); $text = trim(html_entity_decode($text)); $text = preg_replace('/[^\t\n -~]/', '', $text); $text = preg_replace('/WarningThis/', 'Warning: This', $text); return $text; } function phpnet_get_function_info($name, $clsname = 'function') { $clsname = preg_replace('#_#', '-', strtolower($clsname)); $name = preg_replace('#__#', '', strtolower($name)); $name = preg_replace('#_#', '-', $name); $doc = @file_get_contents("http://php.net/manual/en/$clsname.$name.php"); if ($doc === false) { return array(); } $ret = array(); if (preg_match('#

]*>(.*?)'. '
(.*)
#s', $desc, $m)) { $ret['desc'] = phpnet_clean($m[1]); } } if (preg_match('#
]*>(.*?)'. '
(.*?)#s', $desc, $m)) { foreach ($m[1] as $param) { $ret['param_names'][] = phpnet_clean($param); } } if (preg_match_all('#
(.*?)
#s', $desc, $m)) { foreach ($m[1] as $param) { $ret['params'][] = phpnet_clean($param); } } $desc = preg_replace('##', '', $desc); $desc = preg_replace('#
.*
#s', '', $desc); $desc = phpnet_clean($desc); if (!empty($desc)) { $ret['desc'] .= "\n$desc"; } } if (preg_match('#
]*>(.*?)'. '(
)#s', $doc, $m)) { $desc = $m[1]; $desc = preg_replace('##', '', $desc); $ret['ret'] = phpnet_clean($desc); } return $ret; } function phpnet_get_class_desc($name) { $name = preg_replace('#_#', '-', strtolower($name)); $doc = @file_get_contents("http://php.net/manual/en/class.$name.php"); if ($doc !== false && preg_match('#

Introduction

(.*?)'. '
(.*?).*?#', $doc, $m); return $m[1]; }