Implement +=, -=, *=, /= and %= outside of Variant
Esse commit está contido em:
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef incl_HPHP_BINARY_OPERATIONS_H_
|
||||
#define incl_HPHP_BINARY_OPERATIONS_H_
|
||||
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
|
||||
/**
|
||||
* This file contains binary operations that are frequently used and they
|
||||
* are overloaded to ease the code generation so that we need fewer type
|
||||
* casts.
|
||||
*/
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Variant
|
||||
|
||||
inline Variant operator+(bool n, CVarRef v) { return Variant(v) += n;}
|
||||
inline Variant operator+(char n, CVarRef v) { return Variant(v) += n;}
|
||||
inline Variant operator+(short n, CVarRef v) { return Variant(v) += n;}
|
||||
inline Variant operator+(int n, CVarRef v) { return Variant(v) += n;}
|
||||
inline Variant operator+(int64_t n, CVarRef v) { return Variant(v) += n;}
|
||||
inline Variant operator+(double n, CVarRef v) { return Variant(v) += n;}
|
||||
|
||||
// String + Variant means string concatenation
|
||||
inline Variant operator+(String&& n, CVarRef v) {
|
||||
return Variant(std::move(n += v.toString()));
|
||||
}
|
||||
|
||||
inline Variant operator+(CStrRef n, CVarRef v) {
|
||||
return String(n) += v.toString();
|
||||
}
|
||||
// Array + Variant is already defined in type_array.h
|
||||
inline Variant operator+(CObjRef n, CVarRef v) { return Variant(v) += n;}
|
||||
|
||||
#define HPHP_DEFINE_ADDITION(T) \
|
||||
inline Variant&& operator+(Variant&& lhs, T rhs) { \
|
||||
return std::move(lhs += rhs); \
|
||||
} \
|
||||
inline Variant operator+(CVarRef lhs, T rhs) { \
|
||||
return Variant(lhs) += rhs; \
|
||||
}
|
||||
|
||||
HPHP_DEFINE_ADDITION(bool);
|
||||
HPHP_DEFINE_ADDITION(int);
|
||||
HPHP_DEFINE_ADDITION(int64_t);
|
||||
HPHP_DEFINE_ADDITION(double);
|
||||
HPHP_DEFINE_ADDITION(CStrRef);
|
||||
HPHP_DEFINE_ADDITION(litstr);
|
||||
HPHP_DEFINE_ADDITION(CArrRef);
|
||||
HPHP_DEFINE_ADDITION(CObjRef);
|
||||
|
||||
#undef HPHP_DEFINE_ADDITION
|
||||
|
||||
// String + String is already defined in type_string.h
|
||||
// Array + Array is already defined in type_array.h
|
||||
inline Variant operator+(CObjRef v, CObjRef n) { return Variant(v) += n;}
|
||||
|
||||
inline Variant operator-(bool n, CVarRef v) { return v.negate() += n;}
|
||||
inline Variant operator-(char n, CVarRef v) { return v.negate() += n;}
|
||||
inline Variant operator-(short n, CVarRef v) { return v.negate() += n;}
|
||||
inline Variant operator-(int n, CVarRef v) { return v.negate() += n;}
|
||||
inline Variant operator-(int64_t n, CVarRef v) { return v.negate() += n;}
|
||||
inline Variant operator-(double n, CVarRef v) { return v.negate() += n;}
|
||||
inline Variant operator-(CStrRef n, CVarRef v) { return v.negate() += n;}
|
||||
inline Variant operator-(litstr n, CVarRef v) { return v.negate() += n;}
|
||||
inline Variant operator-(CArrRef n, CVarRef v) { return v.negate() += n;}
|
||||
inline Variant operator-(CObjRef n, CVarRef v) { return v.negate() += n;}
|
||||
|
||||
inline Variant operator-(CVarRef v, bool n) { return Variant(v) -= n;}
|
||||
inline Variant operator-(CVarRef v, char n) { return Variant(v) -= n;}
|
||||
inline Variant operator-(CVarRef v, short n) { return Variant(v) -= n;}
|
||||
inline Variant operator-(CVarRef v, int n) { return Variant(v) -= n;}
|
||||
inline Variant operator-(CVarRef v, int64_t n) { return Variant(v) -= n;}
|
||||
inline Variant operator-(CVarRef v, double n) { return Variant(v) -= n;}
|
||||
inline Variant operator-(CVarRef v, CStrRef n) { return Variant(v) -= n;}
|
||||
inline Variant operator-(CVarRef v, litstr n) { return Variant(v) -= n;}
|
||||
inline Variant operator-(CVarRef v, CArrRef n) { return Variant(v) -= n;}
|
||||
inline Variant operator-(CVarRef v, CObjRef n) { return Variant(v) -= n;}
|
||||
|
||||
inline Variant operator*(bool n, CVarRef v) { return Variant(v) *= n;}
|
||||
inline Variant operator*(char n, CVarRef v) { return Variant(v) *= n;}
|
||||
inline Variant operator*(short n, CVarRef v) { return Variant(v) *= n;}
|
||||
inline Variant operator*(int n, CVarRef v) { return Variant(v) *= n;}
|
||||
inline Variant operator*(int64_t n, CVarRef v) { return Variant(v) *= n;}
|
||||
inline Variant operator*(double n, CVarRef v) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CStrRef n, CVarRef v) { return Variant(v) *= n;}
|
||||
inline Variant operator*(litstr n, CVarRef v) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CArrRef n, CVarRef v) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CObjRef n, CVarRef v) { return Variant(v) *= n;}
|
||||
|
||||
inline Variant operator*(CVarRef v, bool n) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CVarRef v, char n) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CVarRef v, short n) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CVarRef v, int n) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CVarRef v, int64_t n) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CVarRef v, double n) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CVarRef v, CStrRef n) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CVarRef v, litstr n) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CVarRef v, CArrRef n) { return Variant(v) *= n;}
|
||||
inline Variant operator*(CVarRef v, CObjRef n) { return Variant(v) *= n;}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
#endif // incl_HPHP_BINARY_OPERATIONS_H_
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "hphp/runtime/base/execution_context.h"
|
||||
#include "hphp/runtime/base/types.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/base/binary_operations.h"
|
||||
#include "hphp/runtime/base/intercept.h"
|
||||
#include "hphp/runtime/base/runtime_error.h"
|
||||
#include "hphp/runtime/base/runtime_option.h"
|
||||
@@ -111,35 +110,6 @@ inline String concat(CStrRef s1, CStrRef s2) {
|
||||
String concat3(CStrRef s1, CStrRef s2, CStrRef s3);
|
||||
String concat4(CStrRef s1, CStrRef s2, CStrRef s3, CStrRef s4);
|
||||
|
||||
inline Variant &concat_assign(Variant &v1, litstr s2) {
|
||||
if (v1.getType() == KindOfString) {
|
||||
StringData *data = v1.getStringData();
|
||||
if (data->getCount() == 1) {
|
||||
data->append(s2, strlen(s2));
|
||||
return v1;
|
||||
}
|
||||
}
|
||||
String s1 = v1.toString();
|
||||
s1 += s2;
|
||||
v1 = s1;
|
||||
return v1;
|
||||
}
|
||||
|
||||
inline Variant &concat_assign(Variant &v1, CStrRef s2) {
|
||||
if (v1.getType() == KindOfString) {
|
||||
StringData *data = v1.getStringData();
|
||||
if (data->getCount() == 1) {
|
||||
data->append(s2.data(), s2.size());
|
||||
return v1;
|
||||
}
|
||||
}
|
||||
String s1 = v1.toString();
|
||||
s1 += s2;
|
||||
|
||||
v1 = s1;
|
||||
return v1;
|
||||
}
|
||||
|
||||
template <class K, class V>
|
||||
const V &String::set(K key, const V &value) {
|
||||
StringData *s = StringData::Escalate(m_px);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "hphp/runtime/base/server/http_request_handler.h"
|
||||
#include "hphp/runtime/base/server/transport.h"
|
||||
#include "hphp/runtime/debugger/debugger.h"
|
||||
#include "hphp/runtime/base/tv_arith.h"
|
||||
|
||||
using std::map;
|
||||
|
||||
@@ -198,7 +199,7 @@ void SourceRootInfo::setServerVariables(Variant &server) const {
|
||||
}
|
||||
|
||||
if (!m_serverVars.empty()) {
|
||||
server += m_serverVars;
|
||||
cellAddEq(*server.asCell(), make_tv<KindOfArray>(m_serverVars.get()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace HPHP {
|
||||
namespace {
|
||||
|
||||
// Helper for converting String, Array, Bool, Null or Obj to Dbl|Int.
|
||||
// Other types must be handled outside of this.
|
||||
// Other types (i.e. Int and Double) must be handled outside of this.
|
||||
TypedNum numericConvHelper(Cell cell) {
|
||||
assert(cellIsPlausible(&cell));
|
||||
|
||||
@@ -48,32 +48,32 @@ TypedNum numericConvHelper(Cell cell) {
|
||||
|
||||
template<class Op>
|
||||
Cell cellArith(Op o, Cell c1, Cell c2) {
|
||||
for (;;) {
|
||||
if (c1.m_type == KindOfInt64) {
|
||||
for (;;) {
|
||||
if (c2.m_type == KindOfInt64) return o(c1.m_data.num, c2.m_data.num);
|
||||
if (c2.m_type == KindOfDouble) return o(c1.m_data.num, c2.m_data.dbl);
|
||||
c2 = numericConvHelper(c2);
|
||||
assert(c1.m_type == KindOfInt64 || c1.m_type == KindOfDouble);
|
||||
}
|
||||
again:
|
||||
if (c1.m_type == KindOfInt64) {
|
||||
for (;;) {
|
||||
if (c2.m_type == KindOfInt64) return o(c1.m_data.num, c2.m_data.num);
|
||||
if (c2.m_type == KindOfDouble) return o(c1.m_data.num, c2.m_data.dbl);
|
||||
c2 = numericConvHelper(c2);
|
||||
assert(c2.m_type == KindOfInt64 || c2.m_type == KindOfDouble);
|
||||
}
|
||||
|
||||
if (c1.m_type == KindOfDouble) {
|
||||
for (;;) {
|
||||
if (c2.m_type == KindOfDouble) return o(c1.m_data.dbl, c2.m_data.dbl);
|
||||
if (c2.m_type == KindOfInt64) return o(c1.m_data.dbl, c2.m_data.num);
|
||||
c2 = numericConvHelper(c2);
|
||||
assert(c1.m_type == KindOfInt64 || c1.m_type == KindOfDouble);
|
||||
}
|
||||
}
|
||||
|
||||
if (c1.m_type == KindOfArray && c2.m_type == KindOfArray) {
|
||||
return make_tv<KindOfArray>(o(c1.m_data.parr, c2.m_data.parr));
|
||||
}
|
||||
|
||||
c1 = numericConvHelper(c1);
|
||||
assert(c1.m_type == KindOfInt64 || c1.m_type == KindOfDouble);
|
||||
}
|
||||
|
||||
if (c1.m_type == KindOfDouble) {
|
||||
for (;;) {
|
||||
if (c2.m_type == KindOfDouble) return o(c1.m_data.dbl, c2.m_data.dbl);
|
||||
if (c2.m_type == KindOfInt64) return o(c1.m_data.dbl, c2.m_data.num);
|
||||
c2 = numericConvHelper(c2);
|
||||
assert(c2.m_type == KindOfInt64 || c2.m_type == KindOfDouble);
|
||||
}
|
||||
}
|
||||
|
||||
if (c1.m_type == KindOfArray && c2.m_type == KindOfArray) {
|
||||
return make_tv<KindOfArray>(o(c1.m_data.parr, c2.m_data.parr));
|
||||
}
|
||||
|
||||
c1 = numericConvHelper(c1);
|
||||
assert(c1.m_type == KindOfInt64 || c1.m_type == KindOfDouble);
|
||||
goto again;
|
||||
}
|
||||
|
||||
Cell num(int64_t n) { return make_tv<KindOfInt64>(n); }
|
||||
@@ -152,6 +152,91 @@ struct Div {
|
||||
}
|
||||
};
|
||||
|
||||
template<class Op>
|
||||
void cellOpEq(Op op, Cell& c1, Cell c2) {
|
||||
again:
|
||||
if (c1.m_type == KindOfInt64) {
|
||||
for (;;) {
|
||||
if (c2.m_type == KindOfInt64) {
|
||||
c1.m_data.num = op(c1.m_data.num, c2.m_data.num);
|
||||
return;
|
||||
}
|
||||
if (c2.m_type == KindOfDouble) {
|
||||
c1.m_type = KindOfDouble;
|
||||
c1.m_data.dbl = op(c1.m_data.num, c2.m_data.dbl);
|
||||
return;
|
||||
}
|
||||
c2 = numericConvHelper(c2);
|
||||
assert(c2.m_type == KindOfInt64 || c2.m_type == KindOfDouble);
|
||||
}
|
||||
}
|
||||
|
||||
if (c1.m_type == KindOfDouble) {
|
||||
for (;;) {
|
||||
if (c2.m_type == KindOfInt64) {
|
||||
c1.m_data.dbl = op(c1.m_data.dbl, c2.m_data.num);
|
||||
return;
|
||||
}
|
||||
if (c2.m_type == KindOfDouble) {
|
||||
c1.m_data.dbl = op(c1.m_data.dbl, c2.m_data.dbl);
|
||||
return;
|
||||
}
|
||||
c2 = numericConvHelper(c2);
|
||||
assert(c2.m_type == KindOfInt64 || c2.m_type == KindOfDouble);
|
||||
}
|
||||
}
|
||||
|
||||
if (c1.m_type == KindOfArray && c2.m_type == KindOfArray) {
|
||||
auto const ad1 = c1.m_data.parr;
|
||||
auto const newArr = op(ad1, c2.m_data.parr);
|
||||
if (newArr != ad1) {
|
||||
newArr->incRefCount();
|
||||
c1.m_data.parr = newArr;
|
||||
decRefArr(ad1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cellCopy(numericConvHelper(c1), c1);
|
||||
assert(c1.m_type == KindOfInt64 || c1.m_type == KindOfDouble);
|
||||
goto again;
|
||||
}
|
||||
|
||||
struct AddEq {
|
||||
int64_t operator()(int64_t a, int64_t b) const { return a + b; }
|
||||
double operator()(double a, int64_t b) const { return a + b; }
|
||||
double operator()(int64_t a, double b) const { return a + b; }
|
||||
double operator()(double a, double b) const { return a + b; }
|
||||
|
||||
ArrayData* operator()(ArrayData* ad1, ArrayData* ad2) const {
|
||||
if (ad2->empty() || ad1 == ad2) return ad1;
|
||||
if (ad1->empty()) return ad2;
|
||||
return ad1->plus(ad2, ad1->getCount() > 1 /* copy */);
|
||||
}
|
||||
};
|
||||
|
||||
struct SubEq {
|
||||
int64_t operator()(int64_t a, int64_t b) const { return a - b; }
|
||||
double operator()(double a, int64_t b) const { return a - b; }
|
||||
double operator()(int64_t a, double b) const { return a - b; }
|
||||
double operator()(double a, double b) const { return a - b; }
|
||||
|
||||
ArrayData* operator()(ArrayData* ad1, ArrayData* ad2) const {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
};
|
||||
|
||||
struct MulEq {
|
||||
int64_t operator()(int64_t a, int64_t b) const { return a * b; }
|
||||
double operator()(double a, int64_t b) const { return a * b; }
|
||||
double operator()(int64_t a, double b) const { return a * b; }
|
||||
double operator()(double a, double b) const { return a * b; }
|
||||
|
||||
ArrayData* operator()(ArrayData* ad1, ArrayData* ad2) const {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@@ -186,6 +271,31 @@ Cell cellMod(Cell c1, Cell c2) {
|
||||
return make_tv<KindOfInt64>(i1 % i2);
|
||||
}
|
||||
|
||||
void cellAddEq(Cell& c1, Cell c2) {
|
||||
cellOpEq(AddEq(), c1, c2);
|
||||
}
|
||||
|
||||
void cellSubEq(Cell& c1, Cell c2) {
|
||||
cellOpEq(SubEq(), c1, c2);
|
||||
}
|
||||
|
||||
void cellMulEq(Cell& c1, Cell c2) {
|
||||
cellOpEq(MulEq(), c1, c2);
|
||||
}
|
||||
|
||||
void cellDivEq(Cell& c1, Cell c2) {
|
||||
assert(cellIsPlausible(&c1));
|
||||
assert(cellIsPlausible(&c2));
|
||||
if (!isTypedNum(c1)) {
|
||||
cellSet(numericConvHelper(c1), c1);
|
||||
}
|
||||
cellCopy(cellDiv(c1, c2), c1);
|
||||
}
|
||||
|
||||
void cellModEq(Cell& c1, Cell c2) {
|
||||
cellCopy(cellMod(c1, c2), c1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
|
||||
@@ -23,17 +23,13 @@ namespace HPHP {
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* Functions that implement php arithmetic.
|
||||
*
|
||||
* These functions return Cells by value. In cases where they may
|
||||
* return reference counted types, the value is already incRef'd when
|
||||
* returned.
|
||||
*/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* Operator +.
|
||||
* PHP operator +
|
||||
*
|
||||
* Returns a TypedNum, unless both arguments are KindOfArray, in which
|
||||
* case it returns an Cell that contains an Array.
|
||||
@@ -41,7 +37,7 @@ namespace HPHP {
|
||||
Cell cellAdd(Cell, Cell);
|
||||
|
||||
/*
|
||||
* Operators - and *.
|
||||
* PHP operators - and *.
|
||||
*
|
||||
* These arithmetic operators on any php value only return numbers.
|
||||
*/
|
||||
@@ -49,7 +45,7 @@ TypedNum cellSub(Cell, Cell);
|
||||
TypedNum cellMul(Cell, Cell);
|
||||
|
||||
/*
|
||||
* Operators / and %.
|
||||
* PHP operators / and %.
|
||||
*
|
||||
* The operators return numbers unless the second argument converts to
|
||||
* zero, in which case they return boolean false.
|
||||
@@ -59,6 +55,42 @@ Cell cellMod(Cell, Cell);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* PHP operator +=
|
||||
*
|
||||
* Mutates the first argument in place, by adding the second argument
|
||||
* to it in the sense of php's operator +=.
|
||||
*
|
||||
* Post: isTypedNum(c1), unless both arguments are KindOfArray, in
|
||||
* which case it will contain a Cell of KindOfArray.
|
||||
*/
|
||||
void cellAddEq(Cell& c1, Cell);
|
||||
|
||||
/*
|
||||
* PHP operators -= and *=.
|
||||
*
|
||||
* Mutates the first argument in place, by combining the second
|
||||
* argument with it in the sense of either php operator -= or *=.
|
||||
*
|
||||
* Post: isTypedNum(c1)
|
||||
*/
|
||||
void cellSubEq(Cell& c1, Cell);
|
||||
void cellMulEq(Cell& c1, Cell);
|
||||
|
||||
/*
|
||||
* PHP operators /= and %=.
|
||||
*
|
||||
* Mutates the first argument in place, by combining the second
|
||||
* argument with it in the sense of either php operator /= or %=.
|
||||
*
|
||||
* Post: isTypedNum(c1), unless the second argument converts to zero,
|
||||
* in which case c1 will contain boolean false.
|
||||
*/
|
||||
void cellDivEq(Cell& c1, Cell);
|
||||
void cellModEq(Cell& c1, Cell);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -37,6 +37,14 @@ bool tvIsPlausible(const TypedValue*);
|
||||
bool cellIsPlausible(const Cell*);
|
||||
bool varIsPlausible(const Var*);
|
||||
|
||||
/*
|
||||
* Returns: true if the supplied TypedValue is KindOfDouble or
|
||||
* KindOfInt64. I.e. if it is a TypedNum.
|
||||
*/
|
||||
inline bool isTypedNum(const TypedValue& tv) {
|
||||
return tv.m_type == KindOfInt64 || tv.m_type == KindOfDouble;
|
||||
}
|
||||
|
||||
// Assumes 'data' is live
|
||||
// Assumes 'IS_REFCOUNTED_TYPE(type)'
|
||||
void tvDecRefHelper(DataType type, uint64_t datum);
|
||||
@@ -305,6 +313,19 @@ inline void tvSetIgnoreRef(const Cell& fr, TypedValue& to) {
|
||||
tvRefcountedDecRefHelper(oldType, oldDatum);
|
||||
}
|
||||
|
||||
/*
|
||||
* Assigned the value of the Cell in `fr' to the Cell `to', with
|
||||
* appropriate reference count modifications.
|
||||
*
|
||||
* This function has the same effects as tvSetIgnoreRef, with stronger
|
||||
* assertions on `to'.
|
||||
*/
|
||||
inline void cellSet(const Cell& fr, Cell& to) {
|
||||
assert(cellIsPlausible(&fr));
|
||||
assert(cellIsPlausible(&to));
|
||||
tvSetIgnoreRef(fr, to);
|
||||
}
|
||||
|
||||
// Assumes 'to' and 'fr' are live
|
||||
// Assumes that 'fr->m_type == KindOfRef'
|
||||
inline void tvBind(TypedValue* fr, TypedValue* to) {
|
||||
|
||||
@@ -754,29 +754,6 @@ CVarRef Array::appendWithRef(CVarRef v) {
|
||||
return v;
|
||||
}
|
||||
|
||||
Variant Array::appendOpEqual(int op, CVarRef v) {
|
||||
if (!m_px) ArrayBase::operator=(ArrayData::Create());
|
||||
Variant *cv = nullptr;
|
||||
ArrayData *escalated = m_px->lvalNew(cv, m_px->getCount() > 1);
|
||||
if (escalated != m_px) ArrayBase::operator=(escalated);
|
||||
assert(cv);
|
||||
switch (op) {
|
||||
case T_CONCAT_EQUAL: return concat_assign((*cv), v.toString());
|
||||
case T_PLUS_EQUAL: return ((*cv) += v);
|
||||
case T_MINUS_EQUAL: return ((*cv) -= v);
|
||||
case T_MUL_EQUAL: return ((*cv) *= v);
|
||||
case T_DIV_EQUAL: return ((*cv) /= v);
|
||||
case T_MOD_EQUAL: return ((*cv) %= v);
|
||||
case T_AND_EQUAL: return ((*cv) &= v);
|
||||
case T_OR_EQUAL: return ((*cv) |= v);
|
||||
case T_XOR_EQUAL: return ((*cv) ^= v);
|
||||
case T_SL_EQUAL: return ((*cv) <<= v.toInt64());
|
||||
case T_SR_EQUAL: return ((*cv) >>= v.toInt64());
|
||||
default:
|
||||
throw FatalErrorException(0, "invalid operator %d", op);
|
||||
}
|
||||
}
|
||||
|
||||
Variant Array::pop() {
|
||||
if (m_px) {
|
||||
Variant ret;
|
||||
|
||||
@@ -430,7 +430,6 @@ class Array : protected SmartPtr<ArrayData> {
|
||||
CVarRef append(RefResult v) { return appendRef(variant(v)); }
|
||||
CVarRef appendRef(CVarRef v);
|
||||
CVarRef appendWithRef(CVarRef v);
|
||||
Variant appendOpEqual(int op, CVarRef v);
|
||||
Variant pop();
|
||||
Variant dequeue();
|
||||
void prepend(CVarRef v);
|
||||
|
||||
@@ -633,97 +633,6 @@ Variant Variant::operator+() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// add or array append
|
||||
|
||||
Variant &Variant::operator+=(CVarRef var) {
|
||||
if (m_type == KindOfInt64 && var.m_type == KindOfInt64) {
|
||||
m_data.num += var.m_data.num;
|
||||
return *this;
|
||||
}
|
||||
if (isIntVal() && var.isIntVal()) {
|
||||
set(toInt64() + var.toInt64());
|
||||
return *this;
|
||||
}
|
||||
int na = is(KindOfArray) + var.is(KindOfArray);
|
||||
if (na == 2) {
|
||||
ArrayData *arr1 = getArrayData();
|
||||
ArrayData *arr2 = var.getArrayData();
|
||||
if (arr1 == nullptr || arr2 == nullptr) {
|
||||
throw BadArrayMergeException();
|
||||
}
|
||||
if (arr2->empty() || arr1 == arr2) return *this;
|
||||
if (arr1->empty()) {
|
||||
set(arr2);
|
||||
return *this;
|
||||
}
|
||||
ArrayData *escalated = arr1->plus(arr2, arr1->getCount() > 1);
|
||||
if (escalated != arr1) set(escalated);
|
||||
return *this;
|
||||
}
|
||||
if (na) throw BadArrayMergeException();
|
||||
if (isDouble() || var.isDouble()) {
|
||||
set(toDouble() + var.toDouble());
|
||||
return *this;
|
||||
}
|
||||
if (isString()) {
|
||||
int64_t lval; double dval;
|
||||
DataType ret = convertToNumeric(&lval, &dval);
|
||||
if (ret == KindOfDouble) {
|
||||
set(dval + var.toDouble());
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
if (var.isString()) {
|
||||
int64_t lval; double dval;
|
||||
DataType ret = var.convertToNumeric(&lval, &dval);
|
||||
if (ret == KindOfDouble) {
|
||||
set(toDouble() + dval);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
set(toInt64() + var.toInt64());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant &Variant::operator+=(int64_t n) {
|
||||
if (m_type == KindOfInt64) {
|
||||
m_data.num += n;
|
||||
return *this;
|
||||
}
|
||||
if (isIntVal()) {
|
||||
set(toInt64() + n);
|
||||
return *this;
|
||||
}
|
||||
if (isDouble()) {
|
||||
set(toDouble() + n);
|
||||
return *this;
|
||||
}
|
||||
if (is(KindOfArray)) {
|
||||
throw BadArrayMergeException();
|
||||
}
|
||||
if (isString()) {
|
||||
int64_t lval; double dval;
|
||||
DataType ret = convertToNumeric(&lval, &dval);
|
||||
if (ret == KindOfDouble) {
|
||||
set(dval + n);
|
||||
return *this;
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
set(toInt64() + n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant &Variant::operator+=(double n) {
|
||||
if (is(KindOfArray)) {
|
||||
throw BadArrayMergeException();
|
||||
}
|
||||
set(toDouble() + n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// minus
|
||||
|
||||
@@ -753,272 +662,6 @@ Variant Variant::operator-() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant &Variant::operator-=(CVarRef var) {
|
||||
if (is(KindOfArray) || var.is(KindOfArray)) {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
if (isDouble() || var.isDouble()) {
|
||||
set(toDouble() - var.toDouble());
|
||||
} else if (isIntVal() && var.isIntVal()) {
|
||||
set(toInt64() - var.toInt64());
|
||||
} else {
|
||||
if (isString()) {
|
||||
int64_t lval; double dval;
|
||||
DataType ret = convertToNumeric(&lval, &dval);
|
||||
if (ret == KindOfDouble) {
|
||||
set(dval - var.toDouble());
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
if (var.isString()) {
|
||||
int64_t lval; double dval;
|
||||
DataType ret = var.convertToNumeric(&lval, &dval);
|
||||
if (ret == KindOfDouble) {
|
||||
set(toDouble() - dval);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
set(toInt64() - var.toInt64());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant &Variant::operator-=(int64_t n) {
|
||||
if (is(KindOfArray)) {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
if (isDouble()) {
|
||||
set(toDouble() - n);
|
||||
} else if (isIntVal()) {
|
||||
set(toInt64() - n);
|
||||
} else {
|
||||
if (isString()) {
|
||||
int64_t lval; double dval;
|
||||
DataType ret = convertToNumeric(&lval, &dval);
|
||||
if (ret == KindOfDouble) {
|
||||
set(dval - n);
|
||||
return *this;
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
set(toInt64() - n);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant &Variant::operator-=(double n) {
|
||||
if (is(KindOfArray)) {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
set(toDouble() - n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// multiply
|
||||
|
||||
Variant &Variant::operator*=(CVarRef var) {
|
||||
if (is(KindOfArray) || var.is(KindOfArray)) {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
if (isDouble() || var.isDouble()) {
|
||||
set(toDouble() * var.toDouble());
|
||||
} else if (isIntVal() && var.isIntVal()) {
|
||||
set(toInt64() * var.toInt64());
|
||||
} else {
|
||||
if (isString()) {
|
||||
int64_t lval; double dval;
|
||||
DataType ret = convertToNumeric(&lval, &dval);
|
||||
if (ret == KindOfDouble) {
|
||||
set(dval * var.toDouble());
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
if (var.isString()) {
|
||||
int64_t lval; double dval;
|
||||
DataType ret = var.convertToNumeric(&lval, &dval);
|
||||
if (ret == KindOfDouble) {
|
||||
set(toDouble() * dval);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
set(toInt64() * var.toInt64());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant &Variant::operator*=(int64_t n) {
|
||||
if (is(KindOfArray)) {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
if (isDouble()) {
|
||||
set(toDouble() * n);
|
||||
} else if (isIntVal()) {
|
||||
set(toInt64() * n);
|
||||
} else {
|
||||
if (isString()) {
|
||||
int64_t lval; double dval;
|
||||
DataType ret = convertToNumeric(&lval, &dval);
|
||||
if (ret == KindOfDouble) {
|
||||
set(dval * n);
|
||||
return *this;
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
set(toInt64() * n);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant &Variant::operator*=(double n) {
|
||||
if (is(KindOfArray)) {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
set(toDouble() * n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// divide
|
||||
|
||||
Variant &Variant::operator/=(CVarRef var) {
|
||||
if (is(KindOfArray) || var.is(KindOfArray)) {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
int64_t lval; double dval; bool int1 = true;
|
||||
int64_t lval2; double dval2; bool int2 = true;
|
||||
|
||||
if (isDouble()) {
|
||||
dval = toDouble();
|
||||
int1 = false;
|
||||
} else if (isIntVal()) {
|
||||
lval = toInt64();
|
||||
} else if (isString()) {
|
||||
DataType ret = convertToNumeric(&lval, &dval);
|
||||
if (ret == KindOfDouble) {
|
||||
int1 = false;
|
||||
} else if (ret != KindOfInt64) {
|
||||
lval = 0;
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
if (var.isDouble()) {
|
||||
dval2 = var.toDouble();
|
||||
int2 = false;
|
||||
} else if (var.isIntVal()) {
|
||||
lval2 = var.toInt64();
|
||||
} else if (var.isString()) {
|
||||
DataType ret = var.convertToNumeric(&lval2, &dval2);
|
||||
if (ret == KindOfDouble) {
|
||||
int2 = false;
|
||||
} else if (ret != KindOfInt64) {
|
||||
lval2 = 0;
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if ((int2 && lval2 == 0) || (!int2 && dval2 == 0)) {
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (int1 && int2) {
|
||||
if (lval % lval2 == 0) {
|
||||
set(lval / lval2);
|
||||
} else {
|
||||
set((double)lval / lval2);
|
||||
}
|
||||
} else if (int1 && !int2) {
|
||||
set(lval / dval2);
|
||||
} else if (!int1 && int2) {
|
||||
set(dval / lval2);
|
||||
} else {
|
||||
set(dval / dval2);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant &Variant::operator/=(int64_t n) {
|
||||
if (is(KindOfArray)) {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
if (n == 0) {
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (isIntVal() && toInt64() % n == 0) {
|
||||
set(toInt64() / n);
|
||||
} else if (isDouble()) {
|
||||
set(toDouble() / n);
|
||||
} else {
|
||||
if (isString()) {
|
||||
int64_t lval; double dval;
|
||||
DataType ret = convertToNumeric(&lval, &dval);
|
||||
if (ret == KindOfInt64 && lval % n == 0) {
|
||||
set(lval / n);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
set(toDouble() / n);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant &Variant::operator/=(double n) {
|
||||
if (is(KindOfArray)) {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
if (n == 0.0) {
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
set(toDouble() / n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// modulus
|
||||
|
||||
Variant &Variant::operator%=(CVarRef var) {
|
||||
int64_t lval = toInt64();
|
||||
int64_t lval2 = var.toInt64();
|
||||
if (lval2 == 0) {
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
set(lval % lval2);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant &Variant::operator%=(int64_t n) {
|
||||
if (n == 0) {
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
set(toInt64() % n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant &Variant::operator%=(double n) {
|
||||
if ((int64_t)n == 0) {
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
set(toInt64() % (int64_t)n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// bitwise
|
||||
|
||||
|
||||
@@ -541,36 +541,36 @@ class Variant : private TypedValue {
|
||||
|
||||
Variant operator + () const;
|
||||
Variant unary_plus() const { return Variant(*this).operator+();}
|
||||
Variant &operator += (CVarRef v);
|
||||
Variant &operator += (int n) { return operator+=((int64_t)n);}
|
||||
Variant &operator += (int64_t n);
|
||||
Variant &operator += (double n);
|
||||
Variant &operator += (CVarRef v) = delete;
|
||||
Variant &operator += (int n) = delete;
|
||||
Variant &operator += (int64_t n) = delete;
|
||||
Variant &operator += (double n) = delete;
|
||||
|
||||
Variant negate() const { return Variant(*this).operator-();}
|
||||
Variant operator - () const;
|
||||
Variant operator - (CVarRef v) const = delete;
|
||||
Variant &operator -= (CVarRef v);
|
||||
Variant &operator -= (int n) { return operator-=((int64_t)n);}
|
||||
Variant &operator -= (int64_t n);
|
||||
Variant &operator -= (double n);
|
||||
Variant &operator -= (CVarRef v) = delete;
|
||||
Variant &operator -= (int n) = delete;
|
||||
Variant &operator -= (int64_t n) = delete;
|
||||
Variant &operator -= (double n) = delete;
|
||||
|
||||
Variant operator * (CVarRef v) const = delete;
|
||||
Variant &operator *= (CVarRef v);
|
||||
Variant &operator *= (int n) { return operator*=((int64_t)n);}
|
||||
Variant &operator *= (int64_t n);
|
||||
Variant &operator *= (double n);
|
||||
Variant &operator *= (CVarRef v) = delete;
|
||||
Variant &operator *= (int n) = delete;
|
||||
Variant &operator *= (int64_t n) = delete;
|
||||
Variant &operator *= (double n) = delete;
|
||||
|
||||
Variant operator / (CVarRef v) const = delete;
|
||||
Variant &operator /= (CVarRef v);
|
||||
Variant &operator /= (int n) { return operator/=((int64_t)n);}
|
||||
Variant &operator /= (int64_t n);
|
||||
Variant &operator /= (double n);
|
||||
Variant &operator /= (CVarRef v) = delete;
|
||||
Variant &operator /= (int n) = delete;
|
||||
Variant &operator /= (int64_t n) = delete;
|
||||
Variant &operator /= (double n) = delete;
|
||||
|
||||
int64_t operator % (CVarRef v) const = delete;
|
||||
Variant &operator %= (CVarRef v);
|
||||
Variant &operator %= (int n) { return operator%=((int64_t)n);}
|
||||
Variant &operator %= (int64_t n);
|
||||
Variant &operator %= (double n);
|
||||
Variant &operator %= (CVarRef v) = delete;
|
||||
Variant &operator %= (int n) = delete;
|
||||
Variant &operator %= (int64_t n) = delete;
|
||||
Variant &operator %= (double n) = delete;
|
||||
|
||||
Variant operator | (CVarRef v) const;
|
||||
Variant &operator |= (CVarRef v);
|
||||
@@ -1340,6 +1340,24 @@ inline Variant uninit_null() {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
// TODO(#2298051) litstr must die
|
||||
inline Variant &concat_assign(Variant &v1, litstr s2) = delete;
|
||||
|
||||
inline Variant &concat_assign(Variant &v1, CStrRef s2) {
|
||||
if (v1.getType() == KindOfString) {
|
||||
StringData *data = v1.getStringData();
|
||||
if (data->getCount() == 1) {
|
||||
data->append(s2.data(), s2.size());
|
||||
return v1;
|
||||
}
|
||||
}
|
||||
String s1 = v1.toString();
|
||||
s1 += s2;
|
||||
|
||||
v1 = s1;
|
||||
return v1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
|
||||
@@ -343,7 +343,7 @@ void f_spl_autoload(CStrRef class_name,
|
||||
String lClass = StringUtil::ToLower(class_name);
|
||||
bool found = false;
|
||||
for (ArrayIter iter(ext); iter; ++iter) {
|
||||
String fileName = lClass + iter.second();
|
||||
String fileName = lClass + iter.second().toString();
|
||||
include(fileName, true, "", false);
|
||||
if (f_class_exists(class_name, false)) {
|
||||
found = true;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "hphp/util/util.h"
|
||||
#include "hphp/runtime/base/complex_types.h"
|
||||
#include "hphp/runtime/base/tv_arith.h"
|
||||
#include "hphp/runtime/base/class_info.h"
|
||||
#include "hphp/runtime/base/array/array_iterator.h"
|
||||
#include "hphp/runtime/vm/class.h"
|
||||
@@ -32,29 +33,30 @@
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
// SETOP_BODY() would ideally be an inline function, but the header
|
||||
// dependencies for concat_assign() make this unfeasible.
|
||||
#define SETOP_BODY(lhs, op, rhs) do { \
|
||||
switch (op) { \
|
||||
case SetOpPlusEqual: tvAsVariant(lhs) += tvCellAsCVarRef(rhs); break; \
|
||||
case SetOpMinusEqual: tvAsVariant(lhs) -= tvCellAsCVarRef(rhs); break; \
|
||||
case SetOpMulEqual: tvAsVariant(lhs) *= tvCellAsCVarRef(rhs); break; \
|
||||
case SetOpDivEqual: tvAsVariant(lhs) /= tvCellAsCVarRef(rhs); break; \
|
||||
case SetOpConcatEqual: { \
|
||||
concat_assign(tvAsVariant(lhs), tvCellAsCVarRef(rhs).toString()); \
|
||||
break; \
|
||||
} \
|
||||
case SetOpModEqual: tvAsVariant(lhs) %= tvCellAsCVarRef(rhs); break; \
|
||||
case SetOpAndEqual: tvAsVariant(lhs) &= tvCellAsCVarRef(rhs); break; \
|
||||
case SetOpOrEqual: tvAsVariant(lhs) |= tvCellAsCVarRef(rhs); break; \
|
||||
case SetOpXorEqual: tvAsVariant(lhs) ^= tvCellAsCVarRef(rhs); break; \
|
||||
case SetOpSlEqual: tvAsVariant(lhs) <<= \
|
||||
tvCellAsCVarRef(rhs).toInt64(); break; \
|
||||
case SetOpSrEqual: tvAsVariant(lhs) >>= \
|
||||
tvCellAsCVarRef(rhs).toInt64(); break; \
|
||||
default: assert(false); \
|
||||
} \
|
||||
} while (0)
|
||||
inline ALWAYS_INLINE
|
||||
void SETOP_BODY(TypedValue* lhs, unsigned char op, Cell* rhs) {
|
||||
assert(cellIsPlausible(rhs));
|
||||
lhs = tvToCell(lhs);
|
||||
|
||||
switch (op) {
|
||||
case SetOpPlusEqual: cellAddEq(*lhs, *rhs); break;
|
||||
case SetOpMinusEqual: cellSubEq(*lhs, *rhs); break;
|
||||
case SetOpMulEqual: cellMulEq(*lhs, *rhs); break;
|
||||
case SetOpDivEqual: cellDivEq(*lhs, *rhs); break;
|
||||
case SetOpModEqual: cellModEq(*lhs, *rhs); break;
|
||||
case SetOpConcatEqual:
|
||||
concat_assign(tvAsVariant(lhs), tvCellAsCVarRef(rhs).toString());
|
||||
break;
|
||||
case SetOpAndEqual: tvAsVariant(lhs) &= tvCellAsCVarRef(rhs); break;
|
||||
case SetOpOrEqual: tvAsVariant(lhs) |= tvCellAsCVarRef(rhs); break;
|
||||
case SetOpXorEqual: tvAsVariant(lhs) ^= tvCellAsCVarRef(rhs); break;
|
||||
case SetOpSlEqual: tvAsVariant(lhs) <<=
|
||||
tvCellAsCVarRef(rhs).toInt64(); break;
|
||||
case SetOpSrEqual: tvAsVariant(lhs) >>=
|
||||
tvCellAsCVarRef(rhs).toInt64(); break;
|
||||
default: not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
class Func;
|
||||
class ActRec;
|
||||
|
||||
@@ -621,15 +621,6 @@ bool TestCppBase::TestObject() {
|
||||
}
|
||||
|
||||
bool TestCppBase::TestVariant() {
|
||||
// operators
|
||||
{
|
||||
Variant v(15);
|
||||
v += 20;
|
||||
VERIFY(v.isNumeric());
|
||||
VERIFY(v.is(KindOfInt64));
|
||||
VERIFY(equal(v, Variant(35)));
|
||||
}
|
||||
|
||||
// conversions
|
||||
{
|
||||
Variant v("123");
|
||||
|
||||
@@ -26,4 +26,60 @@ function main() {
|
||||
var_dump(foo() * twelve());
|
||||
}
|
||||
|
||||
function setop_main() {
|
||||
$a = array(zero());
|
||||
$a[0] += foo();
|
||||
var_dump($a[0]);
|
||||
$a = array(zero());
|
||||
$a[0] -= foo();
|
||||
var_dump($a[0]);
|
||||
$a = array(zero());
|
||||
$a[0] /= foo();
|
||||
var_dump($a[0]);
|
||||
$a = array(zero());
|
||||
$a[0] *= foo();
|
||||
var_dump($a[0]);
|
||||
|
||||
$a = array(foo());
|
||||
$a[0] += zero();
|
||||
var_dump($a[0]);
|
||||
$a = array(foo());
|
||||
$a[0] -= zero();
|
||||
var_dump($a[0]);
|
||||
$a = array(foo());
|
||||
$a[0] /= zero();
|
||||
var_dump($a[0]);
|
||||
$a = array(foo());
|
||||
$a[0] *= zero();
|
||||
var_dump($a[0]);
|
||||
|
||||
$a = array(twelve());
|
||||
$a[0] += foo();
|
||||
var_dump($a[0]);
|
||||
$a = array(twelve());
|
||||
$a[0] -= foo();
|
||||
var_dump($a[0]);
|
||||
$a = array(twelve());
|
||||
$a[0] /= foo();
|
||||
var_dump($a[0]);
|
||||
$a = array(twelve());
|
||||
$a[0] *= foo();
|
||||
var_dump($a[0]);
|
||||
|
||||
$a = array(foo());
|
||||
$a[0] += twelve();
|
||||
var_dump($a[0]);
|
||||
$a = array(foo());
|
||||
$a[0] -= twelve();
|
||||
var_dump($a[0]);
|
||||
$a = array(foo());
|
||||
$a[0] /= twelve();
|
||||
var_dump($a[0]);
|
||||
$a = array(foo());
|
||||
$a[0] *= twelve();
|
||||
var_dump($a[0]);
|
||||
}
|
||||
|
||||
main();
|
||||
setop_main();
|
||||
|
||||
|
||||
@@ -15,3 +15,20 @@ int(28)
|
||||
int(4)
|
||||
float(1.3333333333333)
|
||||
int(192)
|
||||
int(16)
|
||||
int(-16)
|
||||
int(0)
|
||||
int(0)
|
||||
int(16)
|
||||
int(16)
|
||||
HipHop Warning: Division by zero in %s on line 50
|
||||
bool(false)
|
||||
int(0)
|
||||
int(28)
|
||||
int(-4)
|
||||
float(0.75)
|
||||
int(192)
|
||||
int(28)
|
||||
int(4)
|
||||
float(1.3333333333333)
|
||||
int(192)
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário