下面主要分析的是优化阶段和推导阶段的分析,前优化和后优化类似,所以就不具体再分析后优化;
1. preOptimize分析
1.1. preOptimize作用
1.将可以进行计算和拼接的简单的一元、二元表达式进行计算和拼接返回成为一个ScalarExpression(但变量和变量之间的是不能在preOptimize中进行合并的,这样的需要进行类型推导后才可以进行优化)
如:
$a=1+2*3+4 优化后$a=11
$a=“123”+3 优化后$a =126
$b=2;$a=$b+3 ; 优化后$a=5;
$a=“a”.”b”.”c” 优化后 $a=“abc”
2.多个连接语句进行字符串拼接
如:
$a.=“aa”;
$b=“bb”;
$a.=$b.“dd”;
优化后 $a=“aa”.”bb”.”dd”;数组优化同理
3.优化后的表达式,封装到上一级的表达式或者语句中,将语法树进行简化
1.2. preOptimize 处理流程
1.3. preOptimize 实例
例:$a=1+2*3+4
语法树:
(1)优化2*3 返回结果ScalarExpression(6),封装到上一级的BinaryOpExpression上
(2)优化1+6返回结果ScalarExpression(7),封装到上一级的BinaryOpExpression上
(3)优化1+6返回结果ScalarExpression(11),封装到上一级的AssignmentExpression上,最终把一颗大树优化为了一个赋值表达式
1.4. preOptimize代码分析
这里抽取一个一元表达式的作为例子进行分析(unary_op_expression.cpp):
/* 解析一元表达式,并进行计算,计算出结果(reslut),然后返回 一个scalarExpr(result),表达式; 如果m_exp是一元或者二元表达式则返回原表达式; */ ExpressionPtr UnaryOpExpression::preOptimize(AnalysisResultConstPtr ar) { Variant value; Variant result; if (m_exp && ar->getPhase() >= AnalysisResult::FirstPreOptimize) { //T_UNSET : unset if (m_op == T_UNSET) { if (m_exp->isScalar() || (m_exp->is(KindOfExpressionList) && static_pointer_cast<ExpressionList>(m_exp)->getCount() == 0)) { recomputeEffects(); //返回一个null return CONSTANT("null"); } return ExpressionPtr(); } } //T_ISSET :isset if (m_op == T_ISSET && m_exp->is(KindOfExpressionList) && static_pointer_cast<ExpressionList>(m_exp)->getListKind() == ExpressionList::ListKindParam) { ExpressionListPtr el(static_pointer_cast<ExpressionList>(m_exp)); result = true; int i = 0, n = el->getCount(); for (; i < n; i++) { //根据下标获取el列表下的expr ExpressionPtr e((*el)[i]); //如果e为空或e类型不是scalar 则break; if (!e || !e->isScalar() || !e->getScalarValue(value)) break; if (!isset(value)) { result = false; } } //遍历完最后一个expr时,然后返回一个result值,并且将作用域和类型保持与当前表达式一致 if (i == n) { return replaceValue(makeScalarExpression(ar, result)); } } else if (m_op != T_ARRAY && m_exp && m_exp->isScalar() && m_exp->getScalarValue(value) && preCompute(value, result)) { //非array ,并且m_exp不为空,m_exp是scalar类型, 调用preCompute返回计算后的result值 //返回result的scalar表达式,并且修改作用域和类型与当前表达式一致 return replaceValue(makeScalarExpression(ar, result)); } else if (m_op == T_BOOL_CAST) { switch (m_exp->getKindOf()) { default: break; //表达式类型为KindOfBinaryOpExpression case KindOfBinaryOpExpression: { //获取操作符 int op = static_pointer_cast<BinaryOpExpression>(m_exp)->getOp(); switch (op) { //OR case T_LOGICAL_OR: //|| case T_BOOLEAN_OR: //AND case T_LOGICAL_AND: //&& case T_BOOLEAN_AND: //XOR case T_LOGICAL_XOR: //instanceof case T_INSTANCEOF: case '<': //<= case T_IS_SMALLER_OR_EQUAL: case '>': //>= case T_IS_GREATER_OR_EQUAL: //=== case T_IS_IDENTICAL: //!== case T_IS_NOT_IDENTICAL: //== case T_IS_EQUAL: //!= <> case T_IS_NOT_EQUAL: //返回这个二元表达式 return m_exp; } break; } //m_exp是个一元表达式 case KindOfUnaryOpExpression: { int op = static_pointer_cast<UnaryOpExpression>(m_exp)->getOp(); switch (op) { //bool|boolean case T_BOOL_CAST: case '!': //isset case T_ISSET: //empty case T_EMPTY: //print case T_PRINT: //返回当前一元表达式 return m_exp; } break; } } } return ExpressionPtr(); }
2. inferType分析
2.1. inferType的作用
Infertype的主要作用是在pre-optimize的基础之上进行类型推衍,对表达式的类型、变量的类型进行推衍。并判断类型是否和上下文所期望的一致。形如$a = $b + $c ;这种形式,类型推衍将$b和$c的类型推衍成同一类型的然后再进行操作(post-optimize)。
Infertype的最基本操作包括BinaryOpExpression、AssignmentExpression、UnaryOpExpression。
2.2. inferType的流程
1)根据functionscope对文件进行划分
2)获取functionscope下的statementlist,对statementlist进行遍历获取到每条statement。
3)对statement中的expression进行类型推衍,通过调用inferTypes(ar, type, coerce);方法分析出当前的expression是哪一种( AssignmentExpression 、scalarexpression等),在通过inferAndCheck()方法对表达式进行推衍和检查,最终得到表达式的类型。
4)将分析出的最小表达式的类型返回到上一级再次进行分析,直到分析出expression或者statement的类型。
下面有3个expression中的infertype的3个关键函数的实现分析:
inferAndCheck,checkTypesImpl,setTypes;
这3个函数的关系为:inferAndCheck=> checkTypesImpl=> setTypes
inferAndCheck 推导和检查类型(检查类型实现是checkTypesImpl,设置最终类型是setTypes);
以下是3个函数的实现具体的代码分析,在expression.cpp中:
2.2.1. inferAndCheck:
/* coerce是否强制转换 */ TypePtr Expression::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope()); ASSERT(type); resetTypes(); //获取实际类型 TypePtr actualType = inferTypes(ar, type, coerce); //通过传入的type判断是执行如下语句还是执行checkTypesImpl if (type->is(Type::KindOfSome) || type->is(Type::KindOfAny)) { m_actualType = actualType; m_expectedType.reset(); return actualType; } //返回期望值 return checkTypesImpl(ar, type, actualType, coerce); }
2.2.2. checkTypesImpl:
TypePtr Expression::checkTypesImpl(AnalysisResultConstPtr ar, TypePtr expectedType, TypePtr actualType, bool coerce) { TypePtr ret; //返回实际类型 actualType = propagateTypes(ar, actualType); ASSERT(actualType); //是否强转 if (coerce) { ret = Type::Coerce(ar, expectedType, actualType); //设置实际和期望类型 setTypes(ar, actualType, expectedType); } else { //返回期望类型,返回交集 ret = Type::Intersection(ar, actualType, expectedType); setTypes(ar, actualType, ret); } ASSERT(ret); return ret; }
2.2.3. setTypes:
//设置当前表达式的类型 //设置m_actualType 和m_expectedType void Expression::setTypes(AnalysisResultConstPtr ar, TypePtr actualType, TypePtr expectedType) { ASSERT(actualType); ASSERT(expectedType); m_actualType = actualType; //如果expectedType非any和some类型,那么将expectedType设置为期望类型,否则清空m_expectedType if (!expectedType->is(Type::KindOfAny) && !expectedType->is(Type::KindOfSome)) { // store the expected type if it is not Any nor Some, // regardless of the actual type m_expectedType = expectedType; } else { m_expectedType.reset(); } // This is a special case where Type::KindOfObject means any object. //m_expectedType是一个对象类型,并不是一个特殊对象时(如m_name=a,也就是class A,这是一个特殊对象) //并且实际类型是一个特殊对象 if (m_expectedType && m_expectedType->is(Type::KindOfObject) && !m_expectedType->isSpecificObject() && m_actualType->isSpecificObject()) { m_expectedType.reset(); } //如果m_actualType 是一个特殊对象,那么将它添加到文件作用域的依赖中 if (m_actualType->isSpecificObject()) { boost::const_pointer_cast<AnalysisResult>(ar)-> addClassDependency(getFileScope(), m_actualType->getName()); } }
2.3. inferType原理
强转Type::Coerce
秉持的思想是向大的类型转,存在以下几种类型:
①当有一种类型为KindOfVariant 那么返回Type::Variant。
②当type1为KindOfVoid ,type2为KindOfString、 KindOfArray、 KindOfObject返回type2的类型
③当type1为某一具体类型,type2为KindOfSome、 KindOfAny返回type1的类型
④当type1为KindOfString, type2为KindOfArray返回Type:: Sequence。
⑤当type1唯一确定为KindOfInteger,如果type2唯一确定为KindOfInteger,返回type2,否则如果type2唯一确定为KindOfDouble,返回Type::Numeric。
⑥当type为objcet返回父类。
如下都是类型推导的具体的代码分析:
Coerce是强转类型,实际类型和期望类型之间进行转换;
Intersection 取交集类型;
IsLegalCast判断2种类型是否一致;
isStandardObject 判断是否Object类型;
isSpecificObject 是否是特定的类型,如自定义类class A这样的类型;
isNonConvertibleType 是否是Object或者Array 的类型;
isNoObjectInvolved 判断是否是非对象类型(如果是Object或者Array,则返回false)
InferredObject 推导多态的返回类型;
Inferred 推导类型;
combinedArithmeticType 数字类型推导;
php转换cpp的输出内容;
2.3.1. Type::Coerce(强转类型)
强转的函数在type.cpp中,Type::Coerce,代码如下:
//强制转换 type1是期望类型 type2 是实际类型 TypePtr Type::Coerce(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2) { //type1和type2相同返回type1 if (SameType(type1, type2)) return type1; //type1或type2是variant返回variant if (type1->m_kindOf == KindOfVariant || type2->m_kindOf == KindOfVariant) return Type::Variant; //如果type1 包含了type2 则将type1 和type2 互换,保证type1是子集 if (type1->m_kindOf > type2->m_kindOf) { TypePtr tmp = type1; type1 = type2; type2 = tmp; } //type1是void ,type2是string array object,那么返回type2 if (type1->m_kindOf == KindOfVoid && (type2->m_kindOf == KindOfString || type2->m_kindOf == KindOfArray || type2->m_kindOf == KindOfObject)) { return type2; } //type2是some any返回type1 if (type2->m_kindOf == KindOfSome || type2->m_kindOf == KindOfAny) return type1; // if (type2->m_kindOf & KindOfAuto) { //type1 必须是type2不包含auto类型 if (type1->mustBe(type2->m_kindOf & ~KindOfAuto)) { //type1不是string ,返回type1 if (!(type1->m_kindOf & Type::KindOfString)) { return type1; } if (type2->m_kindOf == KindOfAutoSequence) { return Type::Sequence; } //获取type2类型,清除auto return GetType((KindOf)(type2->m_kindOf & ~KindOfAuto)); } return Type::Variant; } // type1 type2都是integer,返回type2 //type1 是integer,type2是double 返回Numeric if (type1->mustBe(KindOfInteger)) { if (type2->mustBe(KindOfInteger)) { return type2; } else if (type2->mustBe(KindOfDouble)) { return Type::Numeric; } } //type1 和type2必须是object if (type1->mustBe(Type::KindOfObject) && type2->mustBe(Type::KindOfObject)) { //type1和type2名字为空返回本身 if (type1->m_name.empty()) return type1; if (type2->m_name.empty()) return type2; //根据名字查找类并返回type ClassScopePtr cls1 = ar->findClass(type1->m_name); //cls1不重复,并且type2是他的父类,返回type2 if (cls1 && !cls1->isRedeclaring() && cls1->derivesFrom(ar, type2->m_name, true, false)) { return type2; } //cls2不重复,并且type1是他的父类,返回type1 ClassScopePtr cls2 = ar->findClass(type2->m_name); if (cls2 && !cls2->isRedeclaring() && cls2->derivesFrom(ar, type1->m_name, true, false)) { return type1; } //cls1 和cls2存在并且都不重复查找cls1或cls2的父类,并且返回 if (cls1 && cls2 && !cls1->isRedeclaring() && !cls2->isRedeclaring()) { //返回父类 ClassScopePtr parent = ClassScope::FindCommonParent(ar, type1->m_name, type2->m_name); if (parent) { //创建父类的类型对象 return Type::CreateObjectType(parent->getName()); } } return Type::Object; } if (type1->mustBe(type2->m_kindOf)) { return type2; } CT_ASSERT(Type::KindOfString < Type::KindOfArray); if (type1->m_kindOf == Type::KindOfString && type2->m_kindOf == Type::KindOfArray) { return Type::Sequence; } return Type::Variant; }
2.3.2. Type::Intersection(取交集)
TypePtr Type::Intersection(AnalysisResultConstPtr ar, TypePtr from, TypePtr to) { // Special case: if we're casting to Some or Any, return the "from" type; // if we're casting to Variant, return Variant. //to 一般为期望值from一般为实际类型 //to为some或any时,返回from if (to->m_kindOf == KindOfSome || to->m_kindOf == KindOfAny) { return from; } else if (to->m_kindOf == KindOfVariant) { return Variant; } //获取to和from的类型交际 int resultKind = to->m_kindOf & from->m_kindOf; std::string resultName = ""; //交集为object if (resultKind & KindOfObject) { // if they're the same, or we don't know one's name, then use // the other //to 和from的类型名字一致或者from 名字为空,resultName为to的名字 if (to->m_name == from->m_name || from->m_name.empty()) { resultName = to->m_name; } else if (to->m_name.empty()) { //to 的名字为空,resultName为from的名字 resultName = from->m_name; } else { // make sure there's a subclass relation //查找from的类 ClassScopePtr cls = ar->findClass(from->m_name); if (cls) { //判断to是否是from 的父类,如果是resultName设置为to的名字 if (cls->derivesFrom(ar, to->m_name, true, false)) { resultName = to->m_name; } else { //不是则清空resultKind的KindOfObject类型 resultKind &= ~KindOfObject; } } } } TypePtr res; // If there is overlap (for instance, they were the same, or we've narrowed // down something like Sequenece to be more specific), then return the // intersection of the types. if (resultKind) { //根据类型名称返回类型 res = GetType(resultKind, resultName); } else if (from->mustBe(KindOfObject) && to->m_kindOf == KindOfPrimitive) { //from必须为对象类型,并且to的类型必须是string 或KindOfNumeric(不存在交集) // Special case Object -> Primitive: can we tostring it? //from名字不为空 if (!from->m_name.empty()) { //查找from的类,查找__tostring方法如果存在则返回ret为string ClassScopePtr cls = ar->findClass(from->m_name); if (cls && cls->findFunction(ar, "__tostring", true)) { res = Type::String; } } // Otherwise, return Int32 res = Int32; } else if (from->m_kindOf == KindOfBoolean && to->mustBe(KindOfNumeric | KindOfArray | KindOfString) && !IsExactType(to->m_kindOf)) { res = Int32; } else { res = to; } //from 是boolean ,to是string 和KindOfNumeric 返回int32 if (from->mustBe(KindOfBoolean) && to->m_kindOf == KindOfPrimitive) { res = Int32; } return res; }
2.3.3. Type::IsLegalCast
/* This new IsLegalCast returns true in a few cases where the old version * (which was basically a hardcoded truth table) returned false; it seems * like "true" is in fact the right thing to return. The cases that appear * when compiling www are: * Sequence -> Array * PlusOperand -> Array * String -> PlusOperand * Boolean -> PlusOperand */ //对比to和from类型是否相同 bool Type::IsLegalCast(AnalysisResultConstPtr ar, TypePtr from, TypePtr to) { if (!from->m_kindOf) return true; // since both 'from' and 'to' represent sets of types, we do // this by computing the set of types that we could possibly cast 'from' // to, and then determining whether that overlaps with 'to'. //给canCastTo加上boolean类型 int canCastTo = KindOfBoolean | from->m_kindOf; //判断from类型中是否有void,如果存在则canCastTo加上void if (from->m_kindOf & KindOfVoid) canCastTo |= KindOfVoid; // Boolean, Numeric, and String can all be cast among each other //判断from中是否有boolean ,数字型和字符串,如果存在给canCastTo加上数字型和字符串 if (from->m_kindOf & (KindOfBoolean | KindOfNumeric | KindOfString)) { canCastTo |= KindOfNumeric | KindOfString; } //判断from是否有对象型 if (from->m_kindOf & KindOfObject) { // Objects can only cast to string if they have __tostring //名字为空,添加上string性 if (from->m_name.empty()) { canCastTo |= KindOfString; // we don't know which class it is } else { //否则是类的对象类型,通过from名字查询cls ClassScopePtr cls = ar->findClass(from->m_name); if (!cls || cls->isRedeclaring() || cls->findFunction(ar, "__tostring", true)) { canCastTo |= KindOfString; } } // can only cast between objects if there's a subclass relation //to 的类型包含object并且类型名字不为空, //并且from类型名字不为空,并且to的m_name不等于from的m_name if ((to->m_kindOf & KindOfObject) && !to->m_name.empty() && !from->m_name.empty() && to->m_name != from->m_name) { //查找类 ClassScopePtr cls = ar->findClass(from->m_name); //类存在,并且类是重复的,将canCastTo的对象类型删除 if (cls && (cls->isRedeclaring() || !cls->derivesFrom(ar, to->m_name, true, true))) { canCastTo &= ~KindOfObject; } } } //判断to 的类型是否在canCastTo中 bool overlap = (to->m_kindOf & canCastTo); return overlap; }
2.3.4. Type::isStandardObject()
//标准的Object,不是特定的class类 bool Type::isStandardObject() const { return m_kindOf == KindOfObject && m_name.empty(); }
2.3.5. Type::isSpecificObject()
//特殊的对象,kindof类型并且名字不为空,如class A ,这样类的类型就是 bool Type::isSpecificObject() const { return m_kindOf == KindOfObject && !m_name.empty(); }
2.3.6. Type::isNonConvertibleType()
bool Type::isNonConvertibleType() const { return m_kindOf == KindOfObject || m_kindOf == KindOfArray; }
2.3.7. Type::isNoObjectInvolved()
//判断不是一个对象,如果为array或object则返回false bool Type::isNoObjectInvolved() const { if (couldBe(KindOfObject) || couldBe(KindOfArray)) return false; else return true; }
2.3.8. Type::InferredObject
//推导2个类的类型中返回类型 TypePtr Type::InferredObject(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2) { ASSERT(type1->m_kindOf == KindOfObject); ASSERT(type2->m_kindOf == KindOfObject); TypePtr resultType = Type::Object; // if they're the same, or we don't know one's name, then use // the other //type1和type2的类型名字相等或者type1的名字为空 if (type1->m_name == type2->m_name || type1->m_name.empty()) { //赋值resultType的类型为type2 resultType = type2; } else if (type2->m_name.empty()) { //type2类型名为空,将resultType的类型设置为type1 resultType = type1; } else { // take the subclass //获取2个类型的类 ClassScopePtr cls1 = ar->findClass(type1->m_name); ClassScopePtr cls2 = ar->findClass(type2->m_name); bool c1ok = cls1 && !cls1->isRedeclaring(); bool c2ok = cls2 && !cls2->isRedeclaring(); if (c1ok && cls1->derivesFrom(ar, type2->m_name, true, false)) { resultType = type1; } else if (c2ok && cls2->derivesFrom(ar, type1->m_name, true, false)) { resultType = type2; } else if (c1ok && c2ok && cls1->derivedByDynamic() && cls2->derivesFromRedeclaring()) { resultType = type2; } else { resultType = type1; } } return resultType; }
2.3.9. Type::Inferred
/* We have inferred type1 and type2 as the actual types for the same expression. Check that the types are compatible (it cant be both a string and an integer, for example), and return the combined type. If they are not compatible, return a null pointer. */ //判断2个类型是否一致 TypePtr Type::Inferred(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2) { //判断type1或type2如果其中一个为空,返回另一个类型 if (!type1) return type2; if (!type2) return type1; KindOf k1 = type1->m_kindOf; KindOf k2 = type2->m_kindOf; if (k1 == k2) { //k1 是object类型则返回推导类 return k1 == KindOfObject ? Type:::InferredObject(ar, type1, type2) : type1; } // If one set is a subset of the other, return the subset. /*判断k1和k2谁是另一个类型的子集返回 例k1 1111 k2 1011 ,那么k2是子集,k1包含k2,返回k2 */ if ((k1 & k2) == k1) return type1; if ((k1 & k2) == k2) return type2; // If one type must be numeric and the other might be, then assume numeric //type1 或type2中必须有一个是KindOfNumeric类型,并且另一个包含KindOfNumeric类型则返回某个type if (type1->mustBe(KindOfNumeric) && type2->couldBe(KindOfNumeric)) { return type1; } if (type2->mustBe(KindOfNumeric) && type1->couldBe(KindOfNumeric)) { return type2; } // Otherwise, take the intersection //如果是对象的返回对象类型 int resultKind = type1->m_kindOf & type2->m_kindOf; if (resultKind == KindOfObject) { return Type::InferredObject(ar, type1, type2); } return resultKind ? GetType(resultKind) : TypePtr(); }
2.3.10. Type::combinedArithmeticType
//数字运算的类型 /* t1 是Primitive,如果t2也是,如果t2>t1 返回t2否则t1; t1如果是double返回double否则是Numeric t2如果是double返回double否则是Numeric t1 或t2是Numeric 返回Numeric 如果kind小于KindOfInt64 ,返回KindOfInt64 否则都不符合返回空 */ TypePtr Type::combinedArithmeticType(TypePtr t1, TypePtr t2) { KindOf kind = KindOfAny; //判断是否是array类型,是则返回空 if (t1 && t1->is(Type::KindOfArray) || t2 && t2->is(Type::KindOfArray)) { return TypePtr(); } //Primitive是Numeric 和String的集合; //Numeric 是Double 和Integer的集合; //type1 是Primitive if (t1 && t1->isPrimitive()) { //t2也是Primitive if (t2 && t2->isPrimitive()) { //t2大于t1,返回t2 否则t1 /* 例: t2:variant t1:int32 ,那么返回Variant */ if (t2->getKindOf() > t1->getKindOf()) { kind = t2->getKindOf(); } else { kind = t1->getKindOf(); } } else if (t1->is(KindOfDouble)) {//t1是double返回double kind = KindOfDouble; } else {//否则返回Numeric kind = KindOfNumeric; } } else if (t2 && t2->isPrimitive()) { if (t2->is(KindOfDouble)) { kind = KindOfDouble; } else { kind = KindOfNumeric; } } else if ((t1 && t1->mustBe(KindOfNumeric)) || (t2 && t2->mustBe(KindOfNumeric))) { kind = KindOfNumeric; } if (kind < KindOfInt64) { kind = KindOfInt64; } if (kind != KindOfAny) { return GetType(kind); } return TypePtr(); }
2.3.11. 输出cpp的类型转换的推导
2.3.11.1. Type::getCPPDecl
/* 获取c++ 的输出类型*/ string Type::getCPPDecl(AnalysisResultConstPtr ar, BlockScopeRawPtr scope, CodeGenerator *cg /* = 0 */) { switch (m_kindOf) { case KindOfBoolean: return "bool"; case KindOfInt32: return "int"; case KindOfInt64: return "int64"; case KindOfDouble: return "double"; case KindOfString: return "String"; case KindOfArray: return "Array"; case KindOfObject:{ ClassScopePtr cls(getClass(ar, scope)); if (!cls) return "Object"; if (cg && cg->isFileOrClassHeader() && scope) { if (scope->getContainingClass()) { scope->getContainingClass()->addUsedClassHeader(cls); } else if (scope->getContainingFile()) { scope->getContainingFile()->addUsedClassHeader(cls); } } //Option::SmartPtrPrefix=> p_ 返回值为p_类名 return Option::SmartPtrPrefix + cls->getId(); } case KindOfNumeric: return "Numeric"; case KindOfPrimitive: return "Primitive"; case KindOfPlusOperand: return "PlusOperand"; case KindOfSequence: return "Sequence"; default: return "Variant"; } }
2.3.11.2. Type::getDataType()
获取数据类型的函数 DataType Type::getDataType() const { switch (m_kindOf) { case KindOfBoolean: return HPHP::KindOfBoolean; case KindOfInt32: case KindOfInt64: return HPHP::KindOfInt64; case KindOfDouble: return HPHP::KindOfDouble; case KindOfString: return HPHP::KindOfString; case KindOfArray: return HPHP::KindOfArray; case KindOfObject: return HPHP::KindOfObject; case KindOfNumeric: case KindOfPrimitive: case KindOfPlusOperand: case KindOfSequence: default: return HPHP::KindOfUnknown; } }
2.3.11.3. Type::outputCPPDecl
//cpp输出声明类型 void Type::outputCPPDecl(CodeGenerator &cg, AnalysisResultConstPtr ar, BlockScopeRawPtr scope) { cg_printf(getCPPDecl(ar, scope, &cg).c_str()); }
2.3.11.4. Type::outputCPPFastObjectCast
/* Php对象输出cpp类对象 p_类名 */ void Type::outputCPPFastObjectCast(CodeGenerator &cg, AnalysisResultConstPtr ar, BlockScopeRawPtr scope, bool isConst) { ASSERT(isSpecificObject()); ClassScopePtr cls(getClass(ar, scope)); ASSERT(cls); const string &cppClsName = cls->getId(); /* Option::SmartPtrPrefix const p_类名 */ cg_printf("(%s%s%s&)", isConst ? "const " : "", Option::SmartPtrPrefix, cppClsName.c_str()); }
2.3.11.5. Type::outputCPPCast
/* Php对应cpp 输出相应类型 */ void Type::outputCPPCast(CodeGenerator &cg, AnalysisResultConstPtr ar, BlockScopeRawPtr scope) { switch (m_kindOf) { case KindOfBoolean: cg_printf("toBoolean"); break; case KindOfInt32: cg_printf("toInt32"); break; case KindOfInt64: cg_printf("toInt64"); break; case KindOfDouble: cg_printf("toDouble"); break; case KindOfString: cg_printf("toString"); break; case KindOfArray: cg_printf("toArray"); break; case KindOfNumeric: cg_printf("Numeric"); break; case KindOfPrimitive: cg_printf("Primitive"); break; case KindOfPlusOperand: cg_printf("PlusOperand"); break; case KindOfSequence: cg_printf("Sequence"); break; case KindOfObject: { ClassScopePtr cls(getClass(ar, scope)); if (!cls) { cg_printf("toObject"); } else { cg_printf("%s%s", Option::SmartPtrPrefix, cls->getId().c_str()); } break; } default: cg_printf("Variant"); break; } }
2.3.11.6. Type::getCPPInitializer()
//cpp 类型初始化内容 const char *Type::getCPPInitializer() { switch (m_kindOf) { case KindOfBoolean: return "false"; case KindOfInt32: case KindOfInt64: return "0"; case KindOfNumeric: case KindOfPrimitive: case KindOfPlusOperand: return "0"; case KindOfDouble: return "0.0"; default: return NULL; } }
2.3.12. 类型推导的类型
类型在type.h中,有如下的类型: static const KindOf KindOfVoid = 0x0001; static const KindOf KindOfBoolean = 0x0002; static const KindOf KindOfInt32 = 0x0010; static const KindOf KindOfInt64 = 0x0020; static const KindOf KindOfDouble = 0x0040; static const KindOf KindOfString = 0x0080; static const KindOf KindOfArray = 0x0100; static const KindOf KindOfObject = 0x0200; // with classname static const KindOf KindOfVariant = 0xFFFF; /* This bit tells coerce that if the other type is already one of the specified types, it wont be modified. eg $a['foo'] = <whatever> If $a is already known to be string or array, it stays that way. If we coerce to Sequence, however, it would become Sequence, and hence Variant */ static const KindOf KindOfAuto = 0x0400; static const KindOf KindOfInteger = (KindOf)(KindOfInt64 | KindOfInt32); static const KindOf KindOfNumeric = (KindOf)(KindOfDouble | KindOfInteger); static const KindOf KindOfPrimitive = (KindOf)(KindOfNumeric | KindOfString); static const KindOf KindOfPlusOperand = (KindOf)(KindOfNumeric | KindOfArray); static const KindOf KindOfSequence = (KindOf)(KindOfString | KindOfArray); static const KindOf KindOfAutoSequence = (KindOf)(KindOfAuto |KindOfSequence); static const KindOf KindOfAutoObject = (KindOf)(KindOfAuto | KindOfObject); static const KindOf KindOfSome = (KindOf)0x7FFE; static const KindOf KindOfAny = (KindOf)0x7FFF; /** * Inferred types: types that a variable or a constant is sure to be. */ static TypePtr Null; static TypePtr Boolean; static TypePtr Int32; static TypePtr Int64; static TypePtr Double; static TypePtr String; static TypePtr Array; static TypePtr Object; static TypePtr Variant; static TypePtr Numeric; static TypePtr PlusOperand; static TypePtr Primitive; static TypePtr Sequence; static TypePtr AutoSequence; static TypePtr AutoObject; static TypePtr Any; static TypePtr Some;
相关推荐
hiphop无穷动
【HipHop-Step的历史与名称由来】 HipHop-Step,作为街舞文化的重要组成部分,起源于20世纪70年代末至80年代初的纽约。它的诞生源自多种舞蹈形式的融合,其中包括非洲舞蹈、Capoeira、B-Boy舞蹈、Jazz舞以及Tap舞...
语言:English (United States) 此扩展程序在每个新选项卡中都包括最佳嘻哈音乐人的高清图像! 说唱歌手包括Eminem Lil Wayne Drake等! 此扩展程序在每个新选项卡中都包括最佳嘻哈音乐人的高清图像!...
获取NF的高清图像,NF是当今最好的说唱歌手之一 可以立即访问他的官方社交网站。 您好,NF的粉丝们! 每次打开新选项卡时,获取喜欢的说唱歌手的高清壁纸。 我们授予了访问他的官方Twitter帐户的权限。...
查找流行的说唱歌手YG的高清背景 可以立即访问他的官方社交网站。 爱嘻哈吗? 喜欢YG和他的音乐吗? 如果您这样做,那么此扩展程序就是适合您的扩展程序。 每次打开新标签页,您都会获得不同的YG高清壁纸。...
通过下载并分析Hiphop-API-master这个压缩包,我们可以深入研究其内部结构,包括源代码文件、文档、示例和测试等,以全面了解Hiphop API的功能和用法。此外,社区的支持和讨论也是学习和解决问题的重要资源,可以...
Cardi B和嘻哈音乐的每个宣誓粉丝都必须拥有此扩展名。 如果您喜欢Cardi B和她的音乐,则绝对应该拥有此扩展名。 它包括流行的嘻哈艺术家的高清照片。 此外,我们添加了她的官方Twitter帐户。 因此,您将是第一个...
"Raslani Hip Hop"可能是指一种特定的字体风格,它结合了Hip Hop文化的元素,旨在为文本内容增添独特的个性和动态感。这种字体可能广泛应用于音乐制作、广告设计、游戏界面、社交媒体帖子以及各种创意项目中,以吸引...
Sa-HipHop,最新的南非音乐Mp3下载还包括SA Hip Hop,非洲之家,深层之屋,Gqom,科威特,部落,Masandi和Ampiano。 Sa-HipHop:南非的灵魂音乐在Sa-HipHop的此处下载,我们随时为您提供最好,最精彩的Sa Hip Hop和...
"HIP与NOW缺陷"是两个常见的问题,尤其是在半导体制造和集成电路(IC)设计中。本文将深入探讨这两个缺陷的本质、成因以及如何进行预防和解决。 首先,HIP,全称为Heat Induced Pinholing,翻译为热诱导针孔缺陷。...
每个人都喜欢Hip Hop音乐和Hip Hop Beats,现在Trap成为都市音乐界的一种趋势。 这就是为什么如果您是一名艺术家,则必须获得最好的嘻哈节拍和器乐。 不管他们是R&B,Smooth,Trap还是New School ...他们都必须听...
简单hiphop街舞教学视频.doc
您是否在为下一个项目寻找West Coast,Gangsta,G-Funk或Hip Hop Beats和Instrumental? 这是你的地方! 许多人在节拍和器乐中寻找那种高品质的声音,这些声音使人想起了旧学校和西海岸的嘻哈音乐的开端,但是却没有...
其中,广告牌(Billboard)的嘻哈图表(Hip-Hop Chart)更是备受关注,它反映了当下最热门的嘻哈音乐趋势。本篇文章将围绕“广告牌嘻哈图表API”展开,探讨如何利用Python语言与其进行交互,获取并分析实时的嘻哈...
享受您最喜爱的Hip Hop艺术家的高清图像 - Lil Pump。每个新标签都会获得不同的壁纸。 如果您喜欢嘻哈音乐,那么您肯定对Lil Pump有所了解。 我们添加了您最喜欢的艺术家的高清背景。 此外,借助我们的Twitter小部件...
安装此扩展程序并享受您最喜爱的RnB和Hip Hop艺术家的高清背景 - The Weeknd。 您喜欢RnB和嘻哈音乐吗? 您喜欢The Weeknd吗? 如果您这样做,那么此扩展名仅适合您。 每个新标签页都会为您显示不同的高清背景或The ...