class Property(ClassMember): getter = None _immutable_fields_ = [ 'name', 'mangled_name', 'access_flags', 'w_initial_value', 'getter' ] def __init__(self, name, klass, access_flags, w_initial_value, src=None): ClassMember.__init__(self, access_flags) self.name = name self.klass = klass self.mangled_name = self.mk_mangled_name() self.src = src # which Property this one is a copy() of assert w_initial_value is not None self.w_initial_value = w_initial_value self.reset_initial_value() def reset_initial_value(self): self.value = self.w_initial_value if self.src is not None: self.r_value = self.src.r_value else: self.r_value = W_Reference(None) # a new ref, lazily filled def getclass(self): return self.klass def mk_mangled_name(self): if self.is_public(): return self.name if self.is_protected(): return '\x00*\x00' + self.name if self.is_private(): return '\x00%s\x00%s' % (self.klass.name, self.name) raise AssertionError def getvalue(self, space): assert self.is_static() if self.r_value.deref_temp() is None: self.r_value.store(self.value.eval_static(space)) return self.r_value def copy(self): res = Property(self.name, self.klass, self.access_flags, self.w_initial_value, src=self) res.value = self.value return res def special_lookup(self, LOOKUP, interp, this, w_newvalue): pass def repr(self): return "%s::$%s" % (self.klass.name, self.name)
class Property(ClassMember): getter = None _immutable_fields_ = ['name', 'mangled_name', 'access_flags', 'w_initial_value', 'getter'] def __init__(self, name, klass, access_flags, w_initial_value, src=None): ClassMember.__init__(self, access_flags) self.name = name self.klass = klass self.mangled_name = self.mk_mangled_name() self.src = src # which Property this one is a copy() of assert w_initial_value is not None self.w_initial_value = w_initial_value self.reset_initial_value() def reset_initial_value(self): self.value = self.w_initial_value if self.src is not None: self.r_value = self.src.r_value else: self.r_value = W_Reference(None) # a new ref, lazily filled def getclass(self): return self.klass def mk_mangled_name(self): if self.is_public(): return self.name if self.is_protected(): return '\x00*\x00' + self.name if self.is_private(): return '\x00%s\x00%s' % (self.klass.name, self.name) raise AssertionError def getvalue(self, space): assert self.is_static() if self.r_value.deref_temp() is None: self.r_value.store(self.value.eval_static(space)) return self.r_value def copy(self): res = Property(self.name, self.klass, self.access_flags, self.w_initial_value, src=self) res.value = self.value return res def special_lookup(self, LOOKUP, interp, this, w_newvalue): pass def repr(self): return "%s::$%s" % (self.klass.name, self.name)
def test_call_args(self): space = ObjSpace() interp = MockInterpreter(space) sin = interp.locate_function("sin") w_res = space.call_args(sin, [space.wrap(1.2)]) assert space.float_w(w_res) == math.sin(1.2) max = interp.locate_function("max") w_res = space.call_args( max, [space.wrap(2), space.wrap(15), space.wrap(3)]) assert space.int_w(w_res) == 15 w_res = space.call_args( max, [W_Reference(space.wrap(2)), space.wrap(15), space.wrap(3)]) assert space.int_w(w_res) == 15 str_repeat = interp.locate_function("str_repeat") w_res = space.call_args(str_repeat, [space.newstr("a"), space.wrap(3)]) assert space.str_w(w_res) == "aaa" source = """<?php function f($a, $b) { return $a + 10 * $b; } """ bc = compile_php('<input>', source, space, interp) interp.run_main(space, bc) f = interp.locate_function("f") w_res = space.call_args(f, [space.wrap(1), space.wrap(2)]) assert space.int_w(w_res) == 21
def getvalue(self, space): assert self.is_static() r_value = self.r_value if not isinstance(r_value, W_Reference): return W_Reference(r_value.eval_static(space)) else: return r_value
def check_reference(space, w_ref, fname): if not isinstance(w_ref, W_Reference): space.ec.hippy_warn("The built-in function %s() takes an argument " "by reference, but didn't get a reference in " "the indirect call" % (fname,)) w_ref = W_Reference(w_ref) return w_ref
def load_ref(space, fp, memo): fp.error_pos = fp.pos type_ = fp.readchr() if type_ == 'a': fp.expect(':') w_result = load_array(space, fp, memo) elif type_ == 'O': fp.expect(':') w_result = load_object(space, fp, memo) elif type_ == 'R': w_result = load_reference(fp, memo) elif type_ == 'r': w_temp = load_reference(fp, memo) w_result = W_Reference(w_temp.deref()) else: w_result = W_Reference(load_primitive(space, fp, type_)) memo.add_object_reference(w_result) return w_result
def _lookup_item_ref(self, space, w_arg): if self.klass.is_array_access: interp = space.ec.interpreter w_res = interp.call_method(self, 'offsetGet', [w_arg]) if isinstance(w_res, W_Reference): return w_res else: if not isinstance(w_res, W_InstanceObject): interp.notice("Indirect modification of overloaded element" " of %s has no effect" % (self.klass.name, )) return W_Reference(w_res)
def _setitem_str(self, key, w_value, as_ref, unique_item=False): if not as_ref: cell = self._get_cell(jit.promote(self._globals_version), key) if cell is not None: w_old = cell.ref assert isinstance(w_old, W_Reference) w_old.store(w_value, unique_item) return self w_value = W_Reference(w_value) assert isinstance(w_value, W_Reference) self.set_var(key, w_value) gframe = self.space.ec.interpreter.global_frame if gframe is not None: gframe.set_ref_by_name(key, w_value) return self
def _create_fixed_iter(self, space, contextclass, byref): # not exactly correct, because it computes the list of returned # attributes at once. We might see differences if the object # is modified during iteration. "But well" for now. from hippy.objects.arrayiter import W_FixedIterator klass = self.getclass() items_w = [] attrs = self.map.get_all_attrs() for attr in attrs: key = attr.name w_value = self.storage_w[attr.index] key1 = klass.check_access_and_demangle_property(key, contextclass) if key1 is not None: if byref and not isinstance(w_value, W_Reference): w_value = W_Reference(w_value) self.storage_w[attr.index] = w_value items_w.append((key1, w_value)) return W_FixedIterator(items_w)
def _make_property(self, prop, w_initial_value): if isinstance(prop, tuple): name, access_flags = prop p = Property(name, self, access_flags) self.properties[name] = p self.property_decl.append(p) if not p.is_static(): p.value = w_initial_value else: if not isinstance(w_initial_value, W_Object): r_value = w_initial_value else: r_value = W_Reference(w_initial_value) p.r_value = r_value elif not we_are_translated(): # compile time only prop = prop.build(self) self.properties[prop.name] = prop self.property_decl.append(prop)
def call_args(self, interp, args_w, w_this=None, thisclass=None, closureargs=None): from hippy.interpreter import Frame from hippy.objects.instanceobject import W_InstanceObject # XXX warn if too many arguments and this function does not call # func_get_arg() & friends if w_this is not None: assert isinstance(w_this, W_InstanceObject) newframe = Frame(interp, self.bytecode, self, thisclass, w_this) newframe.args_w = args_w # save it for later, for func_get_args nb_args = len(args_w) for i in range(len(self.types)): if i < nb_args: # this argument was provided w_argument = args_w[i] if self.needs_value(i) and isinstance(w_argument, W_Reference): w_argument = w_argument.deref() else: arg = self.defaults_w[i] if arg is None: interp.warn("Missing argument %d for %s()" % (i + 1, self.get_fullname())) interp.notice("Undefined variable: %s" % (self.names[i])) w_argument = interp.space.w_Null else: w_argument = arg.eval_static(interp.space) newframe.vars_w[i] = w_argument if closureargs is not None: assert len(closureargs) == len(self.closuredecls) cl_start = len(self.types) if self.bytecode.this_var_num >= 0: cl_start += 1 for i, decl in enumerate(self.closuredecls): r_var = closureargs[i] if not isinstance(r_var, W_Reference): r_var = W_Reference(r_var) newframe.vars_w[cl_start + i] = r_var w_res = interp.interpret(newframe) assert w_res is not None return w_res
def do_get(self, interp, w_obj, attr, isref): key = (w_obj, attr) recursion = rec_custom_get_set if key in recursion: interp.notice("Undefined property: %s::$%s" % (self.name, attr)) w_res = interp.space.w_Null else: recursion[key] = None try: method = self.method__get space = interp.space w_res = method.method_func.call_args(interp, [space.newstr(attr)], w_this=w_obj, thisclass=self) finally: del recursion[key] if isref and not isinstance(w_res, W_Reference): interp.notice("Indirect modification of overloaded property " "%s::$%s has no effect" % (self.name, attr)) w_res = W_Reference(w_res) return w_res
def reset_initial_value(self): self.value = self.w_initial_value if self.src is not None: self.r_value = self.src.r_value else: self.r_value = W_Reference(None) # a new ref, lazily filled
cls = self.getclass() try: name = cls.lookup_property_name(LOOKUP_GETATTR, interp, self, attr, contextclass) except VisibilityError, e: if cls.method__get is not None: return cls.do_get(interp, self, attr, isref) raise e.reraise_property(interp) except SpecialPropertyReturn, e: return e.w_value mapattr = self.map.lookup(name) if mapattr is not None: w_value = self.storage_w[mapattr.index] if w_value is not None: if isref and not isinstance(w_value, W_Reference): w_value = W_Reference(w_value) self.storage_w[mapattr.index] = w_value return w_value if cls.method__get is not None: return cls.do_get(interp, self, attr, isref) if give_notice: interp.notice("Undefined property: %s::$%s" % (cls.name, attr)) if isref: r_value = interp.space.empty_ref() self._create_attr(name, r_value) return r_value else: return interp.space.w_Null def getattr(self, interp, attr, contextclass=None, give_notice=False): return self._getattr(interp,
def unset_ref(self, interp): self.store_ref(interp, W_Reference(interp.space.w_Null))
def store(self, interp, w_value, unique_item=False, give_notice=True): assert not give_notice return W_Reference(w_value)
def get_ref(self, interp, err_is_ref=True): return W_Reference(self.w_obj)
def lookup_ref(self, interp): return W_Reference(self.w_obj)
def empty_ref(self): return W_Reference(self.w_Null)
def load_object(fp): fp.next_reference_obj -= 1 needs_ref = (fp.next_reference_obj == 0) # fp.error_pos = fp.pos try: i = fp.consume(2) except SerializerError: i = fp.consume(1) if fp.s[i] == '}': fp.space.ec.notice("unserialize(): " "Unexpected end of serialized data") raise s = fp.s tp = s[i] check_nonneg(i) check_nonneg(fp.pos) # if tp == 'i': if s[i + 1] != ':': raise SerializerError("':' expected") i = fp.read_int_until(';') w_result = fp.space.wrap(i) # elif tp == 's': if s[i + 1] != ':': raise SerializerError("':' expected") w_result = fp.space.newstr(load_str(fp, ';')) # elif tp == 'd': if s[i + 1] != ':': raise SerializerError("':' expected") data = fp.read_substring_until(';') if data == 'INF': w_result = fp.space.wrap(rfloat.INFINITY) elif data == '-INF': w_result = fp.space.wrap(-rfloat.INFINITY) elif data == 'NAN': w_result = fp.space.wrap(rfloat.NAN) else: w_number, valid = convert_string_to_number(data) if not valid: raise SerializerError('bad double') w_result = fp.space.newfloat(w_number.float_w(fp.space)) # elif tp == 'b': if s[i + 1] != ':': raise SerializerError("':' expected") i = fp.consume(2) digit = s[i] if digit == '0': w_result = fp.space.w_False elif digit == '1': w_result = fp.space.w_True else: raise SerializerError('bad bool') if s[i + 1] != ';': raise SerializerError("';' expected") # elif tp == 'N': if s[i + 1] != ';': raise SerializerError("';' expected") w_result = fp.space.w_Null # elif tp == 'a': if s[i + 1] != ':': raise SerializerError("':' expected") length = fp.read_int_until(':', can_be_negative=False) if length < 0: raise SerializerError("integer overflow") i = fp.consume(1) if s[i] != '{': raise SerializerError("'{' expected") w_result = None if needs_ref: w_result = fp.space.empty_ref() fp.save_reference(w_result) # first try to load the array as a direct list lst_w = [] expected = ['i', ':', '0', ';'] for n in range(length): i = fp.pos if i + len(expected) >= len(s): break for j in range(len(expected)): if s[i] != expected[j]: break i += 1 else: # ok, we got exactly 'i:N;' where N is the expected index fp.pos = i lst_w.append(load_object(fp)) # increment the expected counter j = len(expected) - 2 while j >= 2: if expected[j] != '9': expected[j] = chr(ord(expected[j]) + 1) break expected[j] = '0' j -= 1 else: expected = ['i', ':', '1'] + expected[2:] continue break else: # we succeeded in loading the complete array as a list n = length _succeeded_as_a_list() # for tests # fill in the remaining entries, if any, the slow way w_array = fp.space.new_array_from_list(lst_w) for n in range(n, length): w_key = load_array_key(fp) w_value = load_object(fp) w_array = fp.space.setitem_maybe_inplace(w_array, w_key, w_value) fp.expect_closing_brace() if w_result is not None: # needs_ref w_result.store(w_array, unique=True) return w_result else: return w_array # elif tp == 'R': if s[i + 1] != ':': raise SerializerError("':' expected") return load_reference(fp) # elif tp == 'r': if s[i + 1] != ':': raise SerializerError("':' expected") return load_reference(fp).deref() # elif tp == 'O': if s[i + 1] != ':': raise SerializerError("':' expected") klass_name = load_str(fp, ':') space = fp.space interp = space.ec.interpreter klass = interp.lookup_class_or_intf(klass_name) if klass is None: klass = k_incomplete w_instance = klass.get_empty_instance(space) w_instance.setattr(interp, '__PHP_Incomplete_Class_Name', space.wrap(klass_name), None) else: w_instance = klass.get_empty_instance(space) w_result = w_instance if needs_ref: w_result = W_Reference(w_instance) fp.save_reference(w_result) count_attrs = fp.read_int_until(':') # negative value accepted :-( i = fp.consume(1) if s[i] != '{': raise SerializerError("'{' expected") attrs = {} for i in xrange(count_attrs): w_attr = load_array_key(fp) w_value = load_object(fp) attr_name = space.str_w(w_attr) attrs[attr_name] = w_value w_instance.setattr(interp, attr_name, w_value, None) fp.expect_closing_brace() w_instance.unserialize(space, attrs) if '__wakeup' in klass.methods: klass.methods['__wakeup'].method_func.call_args(space.ec.interpreter, [], w_this=w_instance, thisclass=klass) return w_result # else: if tp == '}': fp.space.ec.notice("unserialize(): " "Unexpected end of serialized data") raise SerializerError('malformed input') # this is for primitive types only; complex types 'return' above if needs_ref: w_result = W_Reference(w_result) fp.save_reference(w_result) return w_result