2005-12-12 Anders Carlsson <andersca@mac.com>
authorandersca <andersca@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Dec 2005 21:24:53 +0000 (21:24 +0000)
committerandersca <andersca@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Dec 2005 21:24:53 +0000 (21:24 +0000)
        Reviewed by Darin.

        - Fixes <http://bugzilla.opendarwin.org/show_bug.cgi?id=6041>

        * bindings/runtime_array.cpp:
        (RuntimeArray::lengthGetter):
        (RuntimeArray::indexGetter):
        * bindings/runtime_array.h:
        * bindings/runtime_method.cpp:
        (RuntimeMethod::lengthGetter):
        * bindings/runtime_method.h:
        * bindings/runtime_object.cpp:
        (RuntimeObjectImp::fallbackObjectGetter):
        (RuntimeObjectImp::fieldGetter):
        (RuntimeObjectImp::methodGetter):
        * bindings/runtime_object.h:
        * kjs/array_instance.h:
        * kjs/array_object.cpp:
        (ArrayInstance::lengthGetter):
        (getProperty):
        Update for changes to PropertySlot::getValue and
        PropertySlot::GetValueFunc.

        * kjs/collector.cpp:
        (KJS::className):
        Handle GetterSetterType.

        * kjs/function.cpp:
        (KJS::FunctionImp::argumentsGetter):
        (KJS::FunctionImp::lengthGetter):
        (KJS::Arguments::mappedIndexGetter):
        (KJS::ActivationImp::argumentsGetter):
        * kjs/function.h:
        Update for changes to PropertySlot::getValue and
        PropertySlot::GetValueFunc.

        * kjs/grammar.y:
        Rework grammar parts for get set declarations directly
        in the object literal.

        * kjs/internal.cpp:
        (KJS::GetterSetterImp::mark):
        (KJS::GetterSetterImp::toPrimitive):
        (KJS::GetterSetterImp::toBoolean):
        (KJS::GetterSetterImp::toNumber):
        (KJS::GetterSetterImp::toString):
        (KJS::GetterSetterImp::toObject):
        Add type conversion functions. These aren't meant to be called.

        (KJS::printInfo):
        Handle GetterSetterType.

        * kjs/lookup.h:
        (KJS::staticFunctionGetter):
        (KJS::staticValueGetter):
        Update for changes to PropertySlot::GetValueFunc.

        * kjs/nodes.cpp:
        Refactor they way properties nodes are implemented.
        We now have a PropertyListNode which is a list of PropertyNodes.
        Each PropertyNode has a name (which is a PropertyNameNode) and an associated
        value node. PropertyNodes can be of different types. The Constant type is the
        old constant declaration and the Getter and Setter types are for property getters
        and setters.
        (ResolveNode::evaluate):
        Update for changes to PropertySlot::getValue.

        (PropertyListNode::evaluate):
        Go through all property nodes and set them on the newly created object. If the
        property nodes are of type Getter or Setter, define getters and setters. Otherwise,
        just add the properties like before.

        (PropertyNode::evaluate):
        This should never be called directly.

        (PropertyNameNode::evaluate):
        Rename from PropertyNode::evaluate.

        (FunctionCallResolveNode::evaluate):
        (FunctionCallBracketNode::evaluate):
        (FunctionCallDotNode::evaluate):
        (PostfixResolveNode::evaluate):
        (PostfixBracketNode::evaluate):
        (PostfixDotNode::evaluate):
        (TypeOfResolveNode::evaluate):
        (PrefixResolveNode::evaluate):
        (PrefixBracketNode::evaluate):
        (PrefixDotNode::evaluate):
        (AssignResolveNode::evaluate):
        (AssignDotNode::evaluate):
        (AssignBracketNode::evaluate):
        Update for changes to PropertySlot::getValue.

        * kjs/nodes.h:
        (KJS::PropertyNameNode::PropertyNameNode):
        Rename from PropertyNode.

        (KJS::PropertyNode::):
        (KJS::PropertyNode::PropertyNode):
        New class, representing a single property.

        (KJS::PropertyListNode::PropertyListNode):
        Rename from PropertyValueNode.

        (KJS::FuncExprNode::FuncExprNode):
        Put ParameterNode parameter last, and make it optional.

        (KJS::ObjectLiteralNode::ObjectLiteralNode):
        Use a PropertyListNode here now.

        * kjs/nodes2string.cpp:
        (PropertyListNode::streamTo):
        Iterate through all property nodes.

        (PropertyNode::streamTo):
        Print out the name and value. Doesn't handle getters and setters currently.

        (PropertyNameNode::streamTo):
        Rename from PropertyNode::streamTo.

        * kjs/object.cpp:
        (KJS::JSObject::get):
        Update for changes to PropertySlot::getValue.

        (KJS::JSObject::put):
        If the property already exists and has a Setter, invoke
        the setter function instead of setting the property directly.

        (KJS::JSObject::defineGetter):
        (KJS::JSObject::defineSetter):
        New functions for defining property getters and setters on the object.

        * kjs/object.h:
        (KJS::GetterSetterImp::type):
        (KJS::GetterSetterImp::GetterSetterImp):
        (KJS::GetterSetterImp::getGetter):
        (KJS::GetterSetterImp::setGetter):
        (KJS::GetterSetterImp::getSetter):
        (KJS::GetterSetterImp::setSetter):
        New class for properties which have getters and setters defined.
        This class is only used internally and should never be seen from the outside.

        (KJS::JSObject::getOwnPropertySlot):
         If the property is a getter, call setGetterSlot on the property slot.

        * kjs/object_object.cpp:
        (ObjectPrototype::ObjectPrototype):
        Add __defineGetter__, __defineSetter, __lookupGetter__, __lookupSetter__
        to prototype.

        (ObjectProtoFunc::callAsFunction):
        Implement handlers for new functions.

        * kjs/object_object.h:
        (KJS::ObjectProtoFunc::):
        Add ids for new functions.

        * kjs/property_slot.cpp:
        (KJS::PropertySlot::undefinedGetter):
        Update for changes to PropertySlot::GetValueFunc.

        (KJS::PropertySlot::functionGetter):
        Call the function getter object and return its value.

        * kjs/property_slot.h:
        (KJS::PropertySlot::getValue):
        Add a new argument which is the original object that
        getPropertySlot was called on.

        (KJS::PropertySlot::setGetterSlot):
        (KJS::PropertySlot::):
        New function which sets a getter slot. When getValue is called on a
        getter slot, the getter function object is invoked.

        * kjs/string_object.cpp:
        (StringInstance::lengthGetter):
        (StringInstance::indexGetter):
        * kjs/string_object.h:
        Update for changes to PropertySlot::GetValueFunc.

        * kjs/value.h:
        (KJS::):
        Add GetterSetterType and make GetterSetterImp a friend class of JSCell.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@11566 268f45cc-cd09-0410-ab3c-d52691b4dbfc

27 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/bindings/runtime_array.cpp
JavaScriptCore/bindings/runtime_array.h
JavaScriptCore/bindings/runtime_method.cpp
JavaScriptCore/bindings/runtime_method.h
JavaScriptCore/bindings/runtime_object.cpp
JavaScriptCore/bindings/runtime_object.h
JavaScriptCore/kjs/array_instance.h
JavaScriptCore/kjs/array_object.cpp
JavaScriptCore/kjs/collector.cpp
JavaScriptCore/kjs/function.cpp
JavaScriptCore/kjs/function.h
JavaScriptCore/kjs/grammar.y
JavaScriptCore/kjs/internal.cpp
JavaScriptCore/kjs/lookup.h
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h
JavaScriptCore/kjs/nodes2string.cpp
JavaScriptCore/kjs/object.cpp
JavaScriptCore/kjs/object.h
JavaScriptCore/kjs/object_object.cpp
JavaScriptCore/kjs/object_object.h
JavaScriptCore/kjs/property_slot.cpp
JavaScriptCore/kjs/property_slot.h
JavaScriptCore/kjs/string_object.cpp
JavaScriptCore/kjs/string_object.h
JavaScriptCore/kjs/value.h

index 5c0066b5a2cba3556aec0d9d8b360dd145c3ad01..8d36496d4da3f64db495182ad82b7a1345a32e43 100644 (file)
@@ -1,3 +1,189 @@
+2005-12-12  Anders Carlsson  <andersca@mac.com>
+
+        Reviewed by Darin.
+
+        - Fixes <http://bugzilla.opendarwin.org/show_bug.cgi?id=6041>
+        
+        * bindings/runtime_array.cpp:
+        (RuntimeArray::lengthGetter):
+        (RuntimeArray::indexGetter):
+        * bindings/runtime_array.h:
+        * bindings/runtime_method.cpp:
+        (RuntimeMethod::lengthGetter):
+        * bindings/runtime_method.h:
+        * bindings/runtime_object.cpp:
+        (RuntimeObjectImp::fallbackObjectGetter):
+        (RuntimeObjectImp::fieldGetter):
+        (RuntimeObjectImp::methodGetter):
+        * bindings/runtime_object.h:
+        * kjs/array_instance.h:
+        * kjs/array_object.cpp:
+        (ArrayInstance::lengthGetter):
+        (getProperty):
+        Update for changes to PropertySlot::getValue and
+        PropertySlot::GetValueFunc.
+        
+        * kjs/collector.cpp:
+        (KJS::className):
+        Handle GetterSetterType.
+        
+        * kjs/function.cpp:
+        (KJS::FunctionImp::argumentsGetter):
+        (KJS::FunctionImp::lengthGetter):
+        (KJS::Arguments::mappedIndexGetter):
+        (KJS::ActivationImp::argumentsGetter):
+        * kjs/function.h:
+        Update for changes to PropertySlot::getValue and
+        PropertySlot::GetValueFunc.
+        
+        * kjs/grammar.y:
+        Rework grammar parts for get set declarations directly
+        in the object literal.
+        
+        * kjs/internal.cpp:
+        (KJS::GetterSetterImp::mark):
+        (KJS::GetterSetterImp::toPrimitive):
+        (KJS::GetterSetterImp::toBoolean):
+        (KJS::GetterSetterImp::toNumber):
+        (KJS::GetterSetterImp::toString):
+        (KJS::GetterSetterImp::toObject):
+        Add type conversion functions. These aren't meant to be called.
+        
+        (KJS::printInfo):
+        Handle GetterSetterType.
+        
+        * kjs/lookup.h:        
+        (KJS::staticFunctionGetter):
+        (KJS::staticValueGetter):
+        Update for changes to PropertySlot::GetValueFunc.
+        
+        * kjs/nodes.cpp:
+        Refactor they way properties nodes are implemented.
+        We now have a PropertyListNode which is a list of PropertyNodes.
+        Each PropertyNode has a name (which is a PropertyNameNode) and an associated
+        value node. PropertyNodes can be of different types. The Constant type is the
+        old constant declaration and the Getter and Setter types are for property getters
+        and setters.
+        (ResolveNode::evaluate):
+        Update for changes to PropertySlot::getValue.
+        
+        (PropertyListNode::evaluate):
+        Go through all property nodes and set them on the newly created object. If the
+        property nodes are of type Getter or Setter, define getters and setters. Otherwise,
+        just add the properties like before.
+        
+        (PropertyNode::evaluate):
+        This should never be called directly.
+        
+        (PropertyNameNode::evaluate):
+        Rename from PropertyNode::evaluate.
+        
+        (FunctionCallResolveNode::evaluate):
+        (FunctionCallBracketNode::evaluate):
+        (FunctionCallDotNode::evaluate):
+        (PostfixResolveNode::evaluate):
+        (PostfixBracketNode::evaluate):
+        (PostfixDotNode::evaluate):
+        (TypeOfResolveNode::evaluate):
+        (PrefixResolveNode::evaluate):
+        (PrefixBracketNode::evaluate):
+        (PrefixDotNode::evaluate):
+        (AssignResolveNode::evaluate):
+        (AssignDotNode::evaluate):
+        (AssignBracketNode::evaluate):
+        Update for changes to PropertySlot::getValue.
+        
+        * kjs/nodes.h:
+        (KJS::PropertyNameNode::PropertyNameNode):
+        Rename from PropertyNode.
+        
+        (KJS::PropertyNode::):
+        (KJS::PropertyNode::PropertyNode):
+        New class, representing a single property.
+        
+        (KJS::PropertyListNode::PropertyListNode):
+        Rename from PropertyValueNode.
+        
+        (KJS::FuncExprNode::FuncExprNode):
+        Put ParameterNode parameter last, and make it optional.
+        
+        (KJS::ObjectLiteralNode::ObjectLiteralNode):
+        Use a PropertyListNode here now.
+        
+        * kjs/nodes2string.cpp:
+        (PropertyListNode::streamTo):
+        Iterate through all property nodes.
+        
+        (PropertyNode::streamTo):
+        Print out the name and value. Doesn't handle getters and setters currently.
+        
+        (PropertyNameNode::streamTo):
+        Rename from PropertyNode::streamTo.
+        
+        * kjs/object.cpp:
+        (KJS::JSObject::get):
+        Update for changes to PropertySlot::getValue.
+        
+        (KJS::JSObject::put):
+        If the property already exists and has a Setter, invoke
+        the setter function instead of setting the property directly.
+        
+        (KJS::JSObject::defineGetter):
+        (KJS::JSObject::defineSetter):
+        New functions for defining property getters and setters on the object.
+        
+        * kjs/object.h:
+        (KJS::GetterSetterImp::type):
+        (KJS::GetterSetterImp::GetterSetterImp):
+        (KJS::GetterSetterImp::getGetter):
+        (KJS::GetterSetterImp::setGetter):
+        (KJS::GetterSetterImp::getSetter):
+        (KJS::GetterSetterImp::setSetter):
+        New class for properties which have getters and setters defined.
+        This class is only used internally and should never be seen from the outside.
+        
+        (KJS::JSObject::getOwnPropertySlot):
+         If the property is a getter, call setGetterSlot on the property slot.
+         
+        * kjs/object_object.cpp:
+        (ObjectPrototype::ObjectPrototype):
+        Add __defineGetter__, __defineSetter, __lookupGetter__, __lookupSetter__
+        to prototype.
+        
+        (ObjectProtoFunc::callAsFunction):
+        Implement handlers for new functions.
+        
+        * kjs/object_object.h:
+        (KJS::ObjectProtoFunc::):
+        Add ids for new functions.
+        
+        * kjs/property_slot.cpp:
+        (KJS::PropertySlot::undefinedGetter):
+        Update for changes to PropertySlot::GetValueFunc.
+        
+        (KJS::PropertySlot::functionGetter):
+        Call the function getter object and return its value.
+        
+        * kjs/property_slot.h:
+        (KJS::PropertySlot::getValue):
+        Add a new argument which is the original object that
+        getPropertySlot was called on.
+        
+        (KJS::PropertySlot::setGetterSlot):
+        (KJS::PropertySlot::):
+        New function which sets a getter slot. When getValue is called on a 
+        getter slot, the getter function object is invoked.
+        
+        * kjs/string_object.cpp:
+        (StringInstance::lengthGetter):
+        (StringInstance::indexGetter):
+        * kjs/string_object.h:
+        Update for changes to PropertySlot::GetValueFunc.
+        
+        * kjs/value.h:
+        (KJS::):
+        Add GetterSetterType and make GetterSetterImp a friend class of JSCell.
+
 2005-12-12  Maciej Stachowiak  <mjs@apple.com>
 
         Reviewed by Eric.
index 9df241fc8f5685fba5998fb8dec8e521fa9e2970..8baf05c17e239d2f284825b64874338f3c6ab47f 100644 (file)
@@ -44,13 +44,13 @@ RuntimeArray::~RuntimeArray()
     delete _array;
 }
 
-JSValue *RuntimeArray::lengthGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *RuntimeArray::lengthGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
 {
     RuntimeArray *thisObj = static_cast<RuntimeArray *>(slot.slotBase());
     return jsNumber(thisObj->getLength());
 }
 
-JSValue *RuntimeArray::indexGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *RuntimeArray::indexGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
 {
     RuntimeArray *thisObj = static_cast<RuntimeArray *>(slot.slotBase());
     return thisObj->getConcreteArray()->valueAt(exec, slot.index());
index 2dd91e645955c38cb1b0d31e14fa1e837c79888d..d53fb1256b52b6483241d49bec3e28113fb36b24 100644 (file)
@@ -54,8 +54,8 @@ public:
     static const ClassInfo info;
 
 private:
-    static JSValue *lengthGetter(ExecState *, const Identifier&, const PropertySlot&);
-    static JSValue *indexGetter(ExecState *, const Identifier&, const PropertySlot&);
+    static JSValue *lengthGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
+    static JSValue *indexGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
 
     Bindings::Array *_array;
 };
index 6f9155a72dd5501bbc39ebcd89bb96673d38e98e..2a65638a50daedf8c097274e9404fc8bf5d246e6 100644 (file)
@@ -41,7 +41,7 @@ RuntimeMethod::~RuntimeMethod()
 {
 }
 
-JSValue *RuntimeMethod::lengthGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *RuntimeMethod::lengthGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
 {
     RuntimeMethod *thisObj = static_cast<RuntimeMethod *>(slot.slotBase());
 
index b64188928f5d1256dbc1d13424d623e4f50f1095..3d21281e011f4e18e25526ceba3a038b3a190d25 100644 (file)
@@ -48,7 +48,7 @@ public:
     virtual Completion execute(ExecState *exec);
 
 private:
-    static JSValue *lengthGetter(ExecState *, const Identifier&, const PropertySlot&);
+    static JSValue *lengthGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
 
     Bindings::MethodList _methodList;
 };
index 7f143db43441b90953a7e5367ce40ab666bb30a8..2de942270ebb2e09af05e6ea954eec711b210da7 100644 (file)
@@ -61,7 +61,7 @@ RuntimeObjectImp::RuntimeObjectImp(Bindings::Instance *i, bool oi)
     instance = i;
 }
 
-JSValue *RuntimeObjectImp::fallbackObjectGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *RuntimeObjectImp::fallbackObjectGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
 {
     RuntimeObjectImp *thisObj = static_cast<RuntimeObjectImp *>(slot.slotBase());
     Bindings::Instance *instance = thisObj->instance;
@@ -76,7 +76,7 @@ JSValue *RuntimeObjectImp::fallbackObjectGetter(ExecState *exec, const Identifie
     return result;
 }
 
-JSValue *RuntimeObjectImp::fieldGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *RuntimeObjectImp::fieldGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
 {
     RuntimeObjectImp *thisObj = static_cast<RuntimeObjectImp *>(slot.slotBase());
     Bindings::Instance *instance = thisObj->instance;
@@ -92,7 +92,7 @@ JSValue *RuntimeObjectImp::fieldGetter(ExecState *exec, const Identifier& proper
     return result;
 }
 
-JSValue *RuntimeObjectImp::methodGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *RuntimeObjectImp::methodGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
 {
     RuntimeObjectImp *thisObj = static_cast<RuntimeObjectImp *>(slot.slotBase());
     Bindings::Instance *instance = thisObj->instance;
index 652d20c44fc1650feefa87685759642fe3d1c33d..f6db3153456adc59c02ea54feca7c1e09ac4d154 100644 (file)
@@ -53,9 +53,9 @@ public:
     static const ClassInfo info;
 
 private:
-    static JSValue *fallbackObjectGetter(ExecState *, const Identifier&, const PropertySlot&);
-    static JSValue *fieldGetter(ExecState *, const Identifier&, const PropertySlot&);
-    static JSValue *methodGetter(ExecState *, const Identifier&, const PropertySlot&);
+    static JSValue *fallbackObjectGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
+    static JSValue *fieldGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
+    static JSValue *methodGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
 
     Bindings::Instance *instance;
     bool ownsInstance;
index 44158ef0df8f2779fb052277539b6004ca3241e4..f1ae5c908672c0b8b87604e59fa409b91235cba5 100644 (file)
@@ -52,7 +52,7 @@ namespace KJS {
     void sort(ExecState *exec, JSObject *compareFunction);
     
   private:
-    static JSValue *lengthGetter(ExecState *, const Identifier&, const PropertySlot&);
+    static JSValue *lengthGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
 
     void setLength(unsigned newLength, ExecState *exec);
     
index 44bfd8bddfd376ae838988bd998f22ebefc9e2cb..72461ab0336e9d9c0e458ddeae0e67415e8e9804 100644 (file)
@@ -74,7 +74,7 @@ ArrayInstance::~ArrayInstance()
   fastFree(storage);
 }
 
-JSValue *ArrayInstance::lengthGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *ArrayInstance::lengthGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
 {
   return jsNumber(static_cast<ArrayInstance *>(slot.slotBase())->length);
 }
@@ -428,7 +428,7 @@ static JSValue *getProperty(ExecState *exec, JSObject *obj, unsigned index)
     PropertySlot slot;
     if (!obj->getPropertySlot(exec, index, slot))
         return NULL;
-    return slot.getValue(exec, index);
+    return slot.getValue(exec, obj, index);
 }
 
 // ECMA 15.4.4
index 791a7770fc35cf6eaa3daf128949826fdcafb874..c89e392ab5adcb79099807d9a3f8be56aa14b3db 100644 (file)
@@ -618,6 +618,9 @@ static const char *className(JSCell *val)
       name = info ? info->className : "Object";
       break;
     }
+    case GetterSetterType:
+      name = "gettersetter";
+      break;
   }
   return name;
 }
index 546caa372b10b498422b30d8411de873777b53df..5e8c1b56adfcbdd3d087970dcbb71530831c75d8 100644 (file)
@@ -206,7 +206,7 @@ void FunctionImp::processVarDecls(ExecState */*exec*/)
 {
 }
 
-JSValue *FunctionImp::argumentsGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *FunctionImp::argumentsGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
 {
   FunctionImp *thisObj = static_cast<FunctionImp *>(slot.slotBase());
   ContextImp *context = exec->_context;
@@ -219,7 +219,7 @@ JSValue *FunctionImp::argumentsGetter(ExecState *exec, const Identifier& propert
   return jsNull();
 }
 
-JSValue *FunctionImp::lengthGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *FunctionImp::lengthGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
 {
   FunctionImp *thisObj = static_cast<FunctionImp *>(slot.slotBase());
   const Parameter *p = thisObj->param;
@@ -442,7 +442,7 @@ void Arguments::mark()
     _activationObject->mark();
 }
 
-JSValue *Arguments::mappedIndexGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *Arguments::mappedIndexGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
 {
   Arguments *thisObj = static_cast<Arguments *>(slot.slotBase());
   return thisObj->_activationObject->get(exec, thisObj->indexToNameMap[propertyName]);
@@ -489,7 +489,7 @@ ActivationImp::ActivationImp(FunctionImp *function, const List &arguments)
   // FIXME: Do we need to support enumerating the arguments property?
 }
 
-JSValue *ActivationImp::argumentsGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *ActivationImp::argumentsGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
 {
   ActivationImp *thisObj = static_cast<ActivationImp *>(slot.slotBase());
 
index fb1279714ea9287efb5884f8873f1979ea08fc64..b550da6de3a5d3bcc5e152a13ce94a11e4657505 100644 (file)
@@ -64,8 +64,8 @@ namespace KJS {
     Identifier ident;
 
   private:
-    static JSValue *argumentsGetter(ExecState *, const Identifier &, const PropertySlot&);
-    static JSValue *lengthGetter(ExecState *, const Identifier &, const PropertySlot&);
+    static JSValue *argumentsGetter(ExecState *, JSObject *, const Identifier &, const PropertySlot&);
+    static JSValue *lengthGetter(ExecState *, JSObject *, const Identifier &, const PropertySlot&);
 
     void processParameters(ExecState *exec, const List &);
     virtual void processVarDecls(ExecState *exec);
@@ -115,7 +115,7 @@ namespace KJS {
     virtual const ClassInfo *classInfo() const { return &info; }
     static const ClassInfo info;
   private:
-    static JSValue *mappedIndexGetter(ExecState *exec, const Identifier &, const PropertySlot& slot);
+    static JSValue *mappedIndexGetter(ExecState *exec, JSObject *, const Identifier &, const PropertySlot& slot);
 
     ActivationImp *_activationObject; 
     mutable IndexToNameMap indexToNameMap;
@@ -136,7 +136,7 @@ namespace KJS {
     bool isActivation() { return true; }
   private:
     static PropertySlot::GetValueFunc getArgumentsGetter();
-    static JSValue *argumentsGetter(ExecState *exec, const Identifier &, const PropertySlot& slot);
+    static JSValue *argumentsGetter(ExecState *exec, JSObject *, const Identifier &, const PropertySlot& slot);
     void createArgumentsObject(ExecState *exec) const;
     
     FunctionImp *_function;
index 278d23c87dacaa09a2a9e90ed90f722a8fca2be4..01401951618f64f0414f85e2c54a8d86dd9d9481 100644 (file)
@@ -54,6 +54,7 @@ using namespace KJS;
 static bool makeAssignNode(Node*& result, Node *loc, Operator op, Node *expr);
 static bool makePrefixNode(Node*& result, Node *expr, Operator op);
 static bool makePostfixNode(Node*& result, Node *expr, Operator op);
+static bool makeGetterOrSetterPropertyNode(PropertyNode*& result, Identifier &getOrSet, Identifier& name, ParameterNode *params, FunctionBodyNode *body);
 static Node *makeFunctionCallNode(Node *func, ArgumentsNode *args);
 static Node *makeTypeOfNode(Node *expr);
 static Node *makeDeleteNode(Node *expr);
@@ -84,8 +85,9 @@ static Node *makeDeleteNode(Node *expr);
   CaseClauseNode      *ccl;
   ElementNode         *elm;
   Operator            op;
-  PropertyValueNode   *plist;
-  PropertyNode        *pnode;
+  PropertyListNode   *plist;
+  PropertyNode       *pnode;
+  PropertyNameNode   *pname;
 }
 
 %start Program
@@ -179,9 +181,9 @@ static Node *makeDeleteNode(Node *expr);
 %type <clist> CaseClauses  CaseClausesOpt
 %type <ival>  Elision ElisionOpt
 %type <elm>   ElementList
-%type <plist> PropertyNameAndValueList
-%type <pnode> PropertyName
-
+%type <pname> PropertyName
+%type <pnode> Property
+%type <plist> PropertyList
 %%
 
 Literal:
@@ -202,10 +204,28 @@ Literal:
                                         }
 ;
 
+PropertyName:
+    IDENT                               { $$ = new PropertyNameNode(*$1); }
+  | STRING                              { $$ = new PropertyNameNode(Identifier(*$1)); }
+  | NUMBER                              { $$ = new PropertyNameNode($1); }
+;
+
+Property:
+    PropertyName ':' AssignmentExpr     { $$ = new PropertyNode($1, $3, PropertyNode::Constant); }
+  | IDENT IDENT '(' ')' FunctionBody    { if (!makeGetterOrSetterPropertyNode($$, *$1, *$2, 0, $5)) YYABORT; }
+  | IDENT IDENT '(' FormalParameterList ')' FunctionBody
+                                        { if (!makeGetterOrSetterPropertyNode($$, *$1, *$2, $4, $6)) YYABORT; }
+;
+
+PropertyList:
+    Property                            { $$ = new PropertyListNode($1); }
+  | PropertyList ',' Property           { $$ = new PropertyListNode($3, $1); }
+;
+
 PrimaryExpr:
     PrimaryExprNoBrace
   | '{' '}'                             { $$ = new ObjectLiteralNode(); }
-  | '{' PropertyNameAndValueList '}'    { $$ = new ObjectLiteralNode($2); }
+  | '{' PropertyList '}'                { $$ = new ObjectLiteralNode($2); }
 ;
 
 PrimaryExprNoBrace:
@@ -238,18 +258,6 @@ Elision:
   | Elision ','                         { $$ = $1 + 1; }
 ;
 
-PropertyNameAndValueList:
-    PropertyName ':' AssignmentExpr     { $$ = new PropertyValueNode($1, $3); }
-  | PropertyNameAndValueList ',' PropertyName ':' AssignmentExpr
-                                        { $$ = new PropertyValueNode($3, $5, $1); }
-;
-
-PropertyName:
-    IDENT                               { $$ = new PropertyNode(*$1); }
-  | STRING                              { $$ = new PropertyNode(Identifier(*$1)); }
-  | NUMBER                              { $$ = new PropertyNode($1); }
-;
-
 MemberExpr:
     PrimaryExpr
   | FunctionExpr                        { $$ = $1; }
@@ -806,10 +814,10 @@ FunctionDeclaration:
 FunctionExpr:
     FUNCTION '(' ')' FunctionBody       { $$ = new FuncExprNode(Identifier::null(), $4); }
   | FUNCTION '(' FormalParameterList ')' FunctionBody
-                                        { $$ = new FuncExprNode(Identifier::null(), $3, $5); }
+                                        { $$ = new FuncExprNode(Identifier::null(), $5, $3); }
   | FUNCTION IDENT '(' ')' FunctionBody { $$ = new FuncExprNode(*$2, $5); }
   | FUNCTION IDENT '(' FormalParameterList ')' FunctionBody
-                                        { $$ = new FuncExprNode(*$2, $4, $6); }
+                                        { $$ = new FuncExprNode(*$2, $6, $4); }
 ;
 
 FormalParameterList:
@@ -960,6 +968,23 @@ static Node *makeDeleteNode(Node *expr)
     }
 }
 
+static bool makeGetterOrSetterPropertyNode(PropertyNode*& result, Identifier& getOrSet, Identifier& name, ParameterNode *params, FunctionBodyNode *body)
+{
+    PropertyNode::Type type;
+    
+    if (getOrSet == "get")
+        type = PropertyNode::Getter;
+    else if (getOrSet == "set")
+        type = PropertyNode::Setter;
+    else
+        return false;
+    
+    result = new PropertyNode(new PropertyNameNode(name), 
+                              new FuncExprNode(Identifier::null(), body, params), type);
+
+    return true;
+}
+
 int yyerror(const char * /* s */)  /* Called by yyparse on error */
 {
   // fprintf(stderr, "ERROR: %s at line %d\n", s, KJS::Lexer::curr()->lineNo());
index 5fb4110ff9b507591cc6520ead19ad50aa850565..52a56947faa02594d2bda3c7e91e24d1cc4c8d49 100644 (file)
@@ -223,6 +223,45 @@ bool NumberImp::getUInt32(uint32_t& uint32) const
   return (double)uint32 == val;
 }
 
+// --------------------------- GetterSetterImp ---------------------------------
+void GetterSetterImp::mark()
+{
+    if (getter && !getter->marked())
+        getter->mark();
+    if (setter && !setter->marked())
+        setter->mark();
+}
+
+JSValue *GetterSetterImp::toPrimitive(ExecState *exec, Type type) const
+{
+    assert(false);
+    return jsNull();
+}
+
+bool GetterSetterImp::toBoolean(ExecState *) const
+{
+    assert(false);
+    return false;
+}
+
+double GetterSetterImp::toNumber(ExecState *) const
+{
+    assert(false);
+    return 0.0;
+}
+
+UString GetterSetterImp::toString(ExecState *) const
+{
+    assert(false);
+    return UString::null();
+}
+
+JSObject *GetterSetterImp::toObject(ExecState *exec) const
+{
+    assert(false);
+    return jsNull()->toObject(exec);
+}
+
 // ------------------------------ LabelStack -----------------------------------
 
 bool LabelStack::push(const Identifier &id)
@@ -835,6 +874,9 @@ void printInfo(ExecState *exec, const char *s, JSValue *o, int lineno)
       if (name.isNull())
         name = "(unknown class)";
       break;
+    case GetterSetterType:
+      name = "GetterSetter";
+      break;
     }
     UString vString = v->toString(exec);
     if ( vString.size() > 50 )
index 51c3ff32e8a808ce037c0daedd83c44de5e98b85..bfd33ea84e4f5d2ae52575073969648488b75968 100644 (file)
@@ -127,7 +127,7 @@ namespace KJS {
    * Helper for getStaticFunctionSlot and getStaticPropertySlot
    */
   template <class FuncImp>
-  inline JSValue *staticFunctionGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
+  inline JSValue *staticFunctionGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
   {
       // Look for cached value in dynamic map of properties (in JSObject)
       JSObject *thisObj = slot.slotBase();
@@ -146,7 +146,7 @@ namespace KJS {
    * Helper for getStaticValueSlot and getStaticPropertySlot
    */
   template <class ThisImp>
-  inline JSValue *staticValueGetter(ExecState *exec, const Identifier&, const PropertySlot& slot)
+  inline JSValue *staticValueGetter(ExecState *exec, JSObject *originalObject, const Identifier&, const PropertySlot& slot)
   {
       ThisImp *thisObj = static_cast<ThisImp *>(slot.slotBase());
       const HashEntry *entry = slot.staticEntry();
index 49c42b99315ebc0eea0802b32c2094efd3a65c2f..6ab9f983879164c04eb91e6620a708bab5e16032 100644 (file)
@@ -277,7 +277,7 @@ JSValue *ResolveNode::evaluate(ExecState *exec)
     JSObject *o = *iter;
 
     if (o->getPropertySlot(exec, ident, slot))
-      return slot.getValue(exec, ident);
+      return slot.getValue(exec, o, ident);
     
     ++iter;
   } while (iter != end);
@@ -353,29 +353,50 @@ JSValue *ObjectLiteralNode::evaluate(ExecState *exec)
   return exec->lexicalInterpreter()->builtinObject()->construct(exec,List::empty());
 }
 
-// ------------------------------ PropertyValueNode ----------------------------
+// ------------------------------ PropertyListNode -----------------------------
 
 // ECMA 11.1.5
-JSValue *PropertyValueNode::evaluate(ExecState *exec)
+JSValue *PropertyListNode::evaluate(ExecState *exec)
 {
   JSObject *obj = exec->lexicalInterpreter()->builtinObject()->construct(exec, List::empty());
   
-  for (PropertyValueNode *p = this; p; p = p->list.get()) {
-    JSValue *n = p->name->evaluate(exec);
+  for (PropertyListNode *p = this; p; p = p->list.get()) {
+    JSValue *n = p->node->name->evaluate(exec);
     KJS_CHECKEXCEPTIONVALUE
-    JSValue *v = p->assign->evaluate(exec);
+    JSValue *v = p->node->assign->evaluate(exec);
     KJS_CHECKEXCEPTIONVALUE
-
-    obj->put(exec, Identifier(n->toString(exec)), v);
+    
+    Identifier propertyName = Identifier(n->toString(exec));
+    switch (p->node->type) {
+      case PropertyNode::Getter:
+        assert(v->isObject());
+        obj->defineGetter(exec, propertyName, static_cast<JSObject *>(v));
+        break;
+      case PropertyNode::Setter:
+        assert(v->isObject());
+        obj->defineSetter(exec, propertyName, static_cast<JSObject *>(v));
+        break;
+      case PropertyNode::Constant:
+        obj->put(exec, propertyName, v);
+        break;
+    }
   }
 
   return obj;
 }
 
-// ------------------------------ PropertyNode ---------------------------------
+// ------------------------------ PropertyNode -----------------------------
+// ECMA 11.1.5
+JSValue *PropertyNode::evaluate(ExecState *exec)
+{
+  assert(false);
+  return jsNull();
+}
+
+// ---------------------------- PropertyNameNode -------------------------------
 
 // ECMA 11.1.5
-JSValue *PropertyNode::evaluate(ExecState *)
+JSValue *PropertyNameNode::evaluate(ExecState *)
 {
   JSValue *s;
 
@@ -520,7 +541,7 @@ JSValue *FunctionCallResolveNode::evaluate(ExecState *exec)
   do { 
     base = *iter;
     if (base->getPropertySlot(exec, ident, slot)) {
-      JSValue *v = slot.getValue(exec, ident);
+      JSValue *v = slot.getValue(exec, base, ident);
       KJS_CHECKEXCEPTIONVALUE
         
       if (!v->isObject()) {
@@ -569,7 +590,7 @@ JSValue *FunctionCallBracketNode::evaluate(ExecState *exec)
   JSValue *funcVal;
   if (subscriptVal->getUInt32(i)) {
     if (baseObj->getPropertySlot(exec, i, slot))
-      funcVal = slot.getValue(exec, i);
+      funcVal = slot.getValue(exec, baseObj, i);
     else
       funcVal = jsUndefined();
   } else {
@@ -620,7 +641,7 @@ JSValue *FunctionCallDotNode::evaluate(ExecState *exec)
 
   JSObject *baseObj = baseVal->toObject(exec);
   PropertySlot slot;
-  JSValue *funcVal = baseObj->getPropertySlot(exec, ident, slot) ? slot.getValue(exec, ident) : jsUndefined();
+  JSValue *funcVal = baseObj->getPropertySlot(exec, ident, slot) ? slot.getValue(exec, baseObj, ident) : jsUndefined();
   KJS_CHECKEXCEPTIONVALUE
 
   if (!funcVal->isObject())
@@ -660,7 +681,7 @@ JSValue *PostfixResolveNode::evaluate(ExecState *exec)
   do { 
     base = *iter;
     if (base->getPropertySlot(exec, m_ident, slot)) {
-        JSValue *v = slot.getValue(exec, m_ident);
+        JSValue *v = slot.getValue(exec, base, m_ident);
 
         double n = v->toNumber(exec);
         
@@ -690,7 +711,7 @@ JSValue *PostfixBracketNode::evaluate(ExecState *exec)
   uint32_t propertyIndex;
   if (subscript->getUInt32(propertyIndex)) {
     PropertySlot slot;
-    JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, propertyIndex) : jsUndefined();
+    JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
     KJS_CHECKEXCEPTIONVALUE
 
     double n = v->toNumber(exec);
@@ -703,7 +724,7 @@ JSValue *PostfixBracketNode::evaluate(ExecState *exec)
 
   Identifier propertyName(subscript->toString(exec));
   PropertySlot slot;
-  JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, propertyName) : jsUndefined();
+  JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
   KJS_CHECKEXCEPTIONVALUE
 
   double n = v->toNumber(exec);
@@ -723,7 +744,7 @@ JSValue *PostfixDotNode::evaluate(ExecState *exec)
   JSObject *base = baseValue->toObject(exec);
 
   PropertySlot slot;
-  JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, m_ident) : jsUndefined();
+  JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
   KJS_CHECKEXCEPTIONVALUE
 
   double n = v->toNumber(exec);
@@ -848,7 +869,7 @@ JSValue *TypeOfResolveNode::evaluate(ExecState *exec)
   do { 
     base = *iter;
     if (base->getPropertySlot(exec, m_ident, slot)) {
-        JSValue *v = slot.getValue(exec, m_ident);
+        JSValue *v = slot.getValue(exec, base, m_ident);
         return typeStringForValue(v);
     }
 
@@ -886,7 +907,7 @@ JSValue *PrefixResolveNode::evaluate(ExecState *exec)
   do { 
     base = *iter;
     if (base->getPropertySlot(exec, m_ident, slot)) {
-        JSValue *v = slot.getValue(exec, m_ident);
+        JSValue *v = slot.getValue(exec, base, m_ident);
 
         double n = v->toNumber(exec);
         
@@ -917,7 +938,7 @@ JSValue *PrefixBracketNode::evaluate(ExecState *exec)
   uint32_t propertyIndex;
   if (subscript->getUInt32(propertyIndex)) {
     PropertySlot slot;
-    JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, propertyIndex) : jsUndefined();
+    JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
     KJS_CHECKEXCEPTIONVALUE
 
     double n = v->toNumber(exec);
@@ -931,7 +952,7 @@ JSValue *PrefixBracketNode::evaluate(ExecState *exec)
 
   Identifier propertyName(subscript->toString(exec));
   PropertySlot slot;
-  JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, propertyName) : jsUndefined();
+  JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
   KJS_CHECKEXCEPTIONVALUE
 
   double n = v->toNumber(exec);
@@ -952,7 +973,7 @@ JSValue *PrefixDotNode::evaluate(ExecState *exec)
   JSObject *base = baseValue->toObject(exec);
 
   PropertySlot slot;
-  JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, m_ident) : jsUndefined();
+  JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
   KJS_CHECKEXCEPTIONVALUE
 
   double n = v->toNumber(exec);
@@ -1291,7 +1312,7 @@ JSValue *AssignResolveNode::evaluate(ExecState *exec)
   if (m_oper == OpEqual) {
     v = m_right->evaluate(exec);
   } else {
-    JSValue *v1 = slot.getValue(exec, m_ident);
+    JSValue *v1 = slot.getValue(exec, base, m_ident);
     KJS_CHECKEXCEPTIONVALUE
     JSValue *v2 = m_right->evaluate(exec);
     v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
@@ -1317,7 +1338,7 @@ JSValue *AssignDotNode::evaluate(ExecState *exec)
     v = m_right->evaluate(exec);
   } else {
     PropertySlot slot;
-    JSValue *v1 = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, m_ident) : jsUndefined();
+    JSValue *v1 = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
     KJS_CHECKEXCEPTIONVALUE
     JSValue *v2 = m_right->evaluate(exec);
     v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
@@ -1347,7 +1368,7 @@ JSValue *AssignBracketNode::evaluate(ExecState *exec)
       v = m_right->evaluate(exec);
     } else {
       PropertySlot slot;
-      JSValue *v1 = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, propertyIndex) : jsUndefined();
+      JSValue *v1 = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
       KJS_CHECKEXCEPTIONVALUE
       JSValue *v2 = m_right->evaluate(exec);
       v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
@@ -1366,7 +1387,7 @@ JSValue *AssignBracketNode::evaluate(ExecState *exec)
     v = m_right->evaluate(exec);
   } else {
     PropertySlot slot;
-    JSValue *v1 = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, propertyName) : jsUndefined();
+    JSValue *v1 = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
     KJS_CHECKEXCEPTIONVALUE
     JSValue *v2 = m_right->evaluate(exec);
     v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
index 115e3c56b02fc84625557a8a4755286eed2dfa8d..a4fd2e27c29b76ba5663a3f7269e50a943fb57ed 100644 (file)
@@ -32,8 +32,8 @@
 namespace KJS {
 
   class ProgramNode;
-  class PropertyNode;
-  class PropertyValueNode;
+  class PropertyNameNode;
+  class PropertyListNode;
   class Reference;
   class RegExp;
   class SourceElementsNode;
@@ -246,41 +246,54 @@ namespace KJS {
     bool opt;
   };
 
-  class PropertyValueNode : public Node {
+  class PropertyNameNode : public Node {
   public:
-    // list pointer is tail of a circular list, cracked in the ObjectLiteralNode ctor
-    PropertyValueNode(PropertyNode *n, Node *a)
-      : name(n), assign(a), list(this) { }
-    PropertyValueNode(PropertyNode *n, Node *a, PropertyValueNode *l)
-      : name(n), assign(a), list(l->list) { l->list = this; }
+    PropertyNameNode(double d) : numeric(d) { }
+    PropertyNameNode(const Identifier &s) : str(s) { }
     JSValue *evaluate(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
   private:
-    friend class ObjectLiteralNode;
-    RefPtr<PropertyNode> name;
+    double numeric;
+    Identifier str;
+  };
+  
+  class PropertyNode : public Node {
+  public:
+    enum Type { Constant, Getter, Setter };
+    PropertyNode(PropertyNameNode *n, Node *a, Type t) 
+      : name(n), assign(a), type(t) { }
+    JSValue *evaluate(ExecState *exec);
+    virtual void streamTo(SourceStream &s) const;
+    friend class PropertyListNode;
+  private:
+    RefPtr<PropertyNameNode> name;
     RefPtr<Node> assign;
-    RefPtr<PropertyValueNode> list;
+    Type type;
   };
-
-  class ObjectLiteralNode : public Node {
+  
+  class PropertyListNode : public Node {
   public:
-    ObjectLiteralNode() : list(0) { }
-    ObjectLiteralNode(PropertyValueNode *l) : list(l->list) { l->list = 0; }
+    // list pointer is tail of a circular list, cracked in the ObjectLiteralNode ctor
+    PropertyListNode(PropertyNode *n)\v
+      : node(n), list(this) { }
+    PropertyListNode(PropertyNode *n, PropertyListNode *l)
+      : node(n), list(l->list) { l->list = this; }
     JSValue *evaluate(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
   private:
-    RefPtr<PropertyValueNode> list;
+    friend class ObjectLiteralNode;
+    RefPtr<PropertyNode> node;
+    RefPtr<PropertyListNode> list;
   };
 
-  class PropertyNode : public Node {
+  class ObjectLiteralNode : public Node {
   public:
-    PropertyNode(double d) : numeric(d) { }
-    PropertyNode(const Identifier &s) : str(s) { }
+    ObjectLiteralNode() : list(0) { }
+    ObjectLiteralNode(PropertyListNode *l) : list(l->list) { l->list = 0; }
     JSValue *evaluate(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
   private:
-    double numeric;
-    Identifier str;
+    RefPtr<PropertyListNode> list;
   };
 
   class BracketAccessorNode : public Node {
@@ -1030,13 +1043,13 @@ namespace KJS {
 
   class FuncExprNode : public Node {
   public:
-    FuncExprNode(const Identifier &i, FunctionBodyNode *b)
-      : ident(i), param(0), body(b) { }
-    FuncExprNode(const Identifier &i, ParameterNode *p, FunctionBodyNode *b)
-      : ident(i), param(p->next), body(b) { p->next = 0; }
+    FuncExprNode(const Identifier &i, FunctionBodyNode *b, ParameterNode *p = 0)
+      : ident(i), param(p ? p->next : 0), body(b) { if (p) p->next = 0; }
     virtual JSValue *evaluate(ExecState *);
     virtual void streamTo(SourceStream &) const;
   private:
+    // Used for streamTo
+    friend class PropertyNode;
     Identifier ident;
     RefPtr<ParameterNode> param;
     RefPtr<FunctionBodyNode> body;
index f8b804a81e4309bb43a28c72c2e107e642bf6226..1bd92c36e1f163f059c028b485e4bfb85e4cf384 100644 (file)
@@ -155,13 +155,35 @@ void ObjectLiteralNode::streamTo(SourceStream &s) const
     s << "{ }";
 }
 
-void PropertyValueNode::streamTo(SourceStream &s) const
+void PropertyListNode::streamTo(SourceStream &s) const
 {
-  for (const PropertyValueNode *n = this; n; n = n->list.get())
-    s << n->name << ": " << n->assign;
+  s << node;
+  
+  for (const PropertyListNode *n = list.get(); n; n = n->list.get())
+    s << ", " << n->node;
 }
 
 void PropertyNode::streamTo(SourceStream &s) const
+{
+  switch (type) {
+    case Constant:
+      s << name << ": " << assign;
+      break;
+    case Getter:
+    case Setter: {
+      const FuncExprNode *func = static_cast<const FuncExprNode *>(assign.get());
+      if (type == Getter)
+        s << "get "; 
+      else
+        s << "set ";
+      
+      s << name << "(" << func->param << ")" << func->body;
+      break;
+    }
+  }
+}
+
+void PropertyNameNode::streamTo(SourceStream &s) const
 {
   if (str.isNull())
     s << UString::from(numeric);
index 21ac2205fc1c7e8634bfec525c60116b05bb23e2..8a7c7158c2c7442e52949b18e0a13a6c43ebc3ca 100644 (file)
@@ -153,7 +153,7 @@ JSValue *JSObject::get(ExecState *exec, const Identifier &propertyName) const
   PropertySlot slot;
 
   if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot))
-    return slot.getValue(exec, propertyName);
+    return slot.getValue(exec, const_cast<JSObject *>(this), propertyName);
     
   return jsUndefined();
 }
@@ -162,7 +162,7 @@ JSValue *JSObject::get(ExecState *exec, unsigned propertyName) const
 {
   PropertySlot slot;
   if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot))
-    return slot.getValue(exec, propertyName);
+    return slot.getValue(exec, const_cast<JSObject *>(this), propertyName);
     
   return jsUndefined();
 }
@@ -213,6 +213,35 @@ void JSObject::put(ExecState *exec, const Identifier &propertyName, JSValue *val
     return;
   }
 
+  JSObject *obj = this;
+  while (true) {
+    if (JSValue *gs = obj->_prop.get(propertyName)) {
+      if (gs->type() == GetterSetterType) {
+        JSObject *setterFunc = static_cast<GetterSetterImp *>(gs)->getSetter();
+            
+        if (!setterFunc) {
+          throwError(exec, TypeError, "setting a property that has only a getter");
+          return;
+        }
+            
+        List args;
+        args.append(value);
+        
+        setterFunc->call(exec, this, args);
+        return;
+      } else  {
+        // If there's an existing property on the object or one of its 
+        // prototype it should be replaced, so we just break here.
+        break;
+      }
+    }
+     
+    if (!obj->_proto || !obj->_proto->isObject())
+      break;
+        
+    obj = static_cast<JSObject *>(obj->_proto);
+  }
+
   _prop.put(propertyName,value,attr);
 }
 
@@ -332,6 +361,36 @@ const HashEntry* JSObject::findPropertyHashEntry(const Identifier& propertyName)
   return 0;
 }
 
+void JSObject::defineGetter(ExecState *exec, const Identifier& propertyName, JSObject *getterFunc)
+{
+    JSValue *o = getDirect(propertyName);
+    GetterSetterImp *gs;
+    
+    if (o && o->type() == GetterSetterType) {
+        gs = static_cast<GetterSetterImp *>(o);
+    } else {
+        gs = new GetterSetterImp;
+        putDirect(propertyName, gs);
+    }
+    
+    gs->setGetter(getterFunc);
+}
+
+void JSObject::defineSetter(ExecState *exec, const Identifier& propertyName, JSObject *setterFunc)
+{
+    JSValue *o = getDirect(propertyName);
+    GetterSetterImp *gs;
+    
+    if (o && o->type() == GetterSetterType) {
+        gs = static_cast<GetterSetterImp *>(o);
+    } else {
+        gs = new GetterSetterImp;
+        putDirect(propertyName, gs);
+    }
+    
+    gs->setSetter(setterFunc);
+}
+
 bool JSObject::implementsConstruct() const
 {
   return false;
index 01978f8c41359aae8c317d83fa2629015bee04d5..bc768a0ab309f7d0ab19aa01a3eb3676753947d8 100644 (file)
@@ -80,6 +80,32 @@ namespace KJS {
     void *dummy;
   };
   
+  // This is an internal value object which stores getter and setter functions
+  // for a property.
+  class GetterSetterImp : public JSCell {
+  public:
+    Type type() const { return GetterSetterType; }
+      
+    GetterSetterImp() : getter(0), setter(0) { }
+      
+    virtual JSValue *toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const;
+    virtual bool toBoolean(ExecState *exec) const;
+    virtual double toNumber(ExecState *exec) const;
+    virtual UString toString(ExecState *exec) const;
+    virtual JSObject *toObject(ExecState *exec) const;
+      
+    virtual void mark();
+      
+    JSObject *getGetter() { return getter; }
+    void setGetter(JSObject *g) { getter = g; }
+    JSObject *getSetter() { return setter; }
+    void setSetter(JSObject *s) { setter = s; }
+      
+  private:
+    JSObject *getter;
+    JSObject *setter;  
+  };
+  
   class JSObject : public JSCell {
   public:
     /**
@@ -477,6 +503,9 @@ namespace KJS {
     void putDirect(const Identifier &propertyName, JSValue *value, int attr = 0);
     void putDirect(const Identifier &propertyName, int value, int attr = 0);
     
+    void defineGetter(ExecState *exec, const Identifier& propertyName, JSObject *getterFunc);
+    void defineSetter(ExecState *exec, const Identifier& propertyName, JSObject *setterFunc);
+
     /**
      * Remove all properties from this object.
      * This doesn't take DontDelete into account, and isn't in the ECMA spec.
@@ -606,7 +635,16 @@ inline bool JSObject::getPropertySlot(ExecState *exec, const Identifier& propert
 inline bool JSObject::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
 {
     if (JSValue **location = getDirectLocation(propertyName)) {
-        slot.setValueSlot(this, location);
+        if ((*location)->type() == GetterSetterType) {
+            GetterSetterImp *gs = static_cast<GetterSetterImp *>(*location);
+            JSObject *getterFunc = gs->getGetter();
+            if (getterFunc)
+                slot.setGetterSlot(this, getterFunc);
+            else
+                slot.setUndefined(this);
+        } else {
+            slot.setValueSlot(this, location);
+        }
         return true;
     }
 
index bccf46744a6b4b79980ad4f567fdb4c2f5209c0a..f05ca4ff36b40ccdc53bcdfb2163db6927c5e79f 100644 (file)
@@ -43,6 +43,11 @@ ObjectPrototype::ObjectPrototype(ExecState *exec,
     putDirect(valueOfPropertyName, new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::ValueOf,                 0), DontEnum);
     putDirect("hasOwnProperty", new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::HasOwnProperty,             1), DontEnum);
     putDirect("propertyIsEnumerable", new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::PropertyIsEnumerable, 1), DontEnum);
+    // Mozilla extensions
+    putDirect("__defineGetter__", new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::DefineGetter,             2), DontEnum);
+    putDirect("__defineSetter__", new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::DefineSetter,             2), DontEnum);
+    putDirect("__lookupGetter__", new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::LookupGetter,             1), DontEnum);
+    putDirect("__lookupSetter__", new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::LookupSetter,             1), DontEnum);
 }
 
 
@@ -73,6 +78,53 @@ JSValue *ObjectProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, con
             PropertySlot slot;
             return jsBoolean(thisObj->getOwnPropertySlot(exec, Identifier(args[0]->toString(exec)), slot));
         }
+        case DefineGetter: 
+        case DefineSetter: {
+            if (!args[1]->isObject() ||
+                !static_cast<JSObject *>(args[1])->implementsCall()) {
+                if (id == DefineGetter)
+                    return throwError(exec, SyntaxError, "invalid getter usage");
+                else
+                    return throwError(exec, SyntaxError, "invalid setter usage");
+            }
+
+            if (id == DefineGetter)
+                thisObj->defineGetter(exec, Identifier(args[0]->toString(exec)), static_cast<JSObject *>(args[1]));
+            else
+                thisObj->defineSetter(exec, Identifier(args[0]->toString(exec)), static_cast<JSObject *>(args[1]));
+            return jsUndefined();
+        }
+        case LookupGetter:
+        case LookupSetter: {
+            Identifier propertyName = Identifier(args[0]->toString(exec));
+            
+            JSObject *obj = thisObj;
+            while (true) {
+                JSValue *v = obj->getDirect(propertyName);
+                
+                if (v) {
+                    if (v->type() != GetterSetterType)
+                        return jsUndefined();
+
+                    JSObject *funcObj;
+                        
+                    if (id == LookupGetter)
+                        funcObj = static_cast<GetterSetterImp *>(v)->getGetter();
+                    else
+                        funcObj = static_cast<GetterSetterImp *>(v)->getSetter();
+                
+                    if (!funcObj)
+                        return jsUndefined();
+                    else
+                        return funcObj;
+                }
+                
+                if (!obj->prototype() || !obj->prototype()->isObject())
+                    return jsUndefined();
+                
+                obj = static_cast<JSObject *>(obj->prototype());
+            }
+        }
         case PropertyIsEnumerable:
             return jsBoolean(thisObj->propertyIsEnumerable(exec, Identifier(args[0]->toString(exec))));
         case ToLocaleString:
index 4aa63764f19a7fa97ee213220ce9a1a543d23f63..e78ea40bafb89c4649a336a762770d5015a16788 100644 (file)
@@ -52,7 +52,8 @@ namespace KJS {
     virtual bool implementsCall() const;
     virtual JSValue *callAsFunction(ExecState *, JSObject *, const List &args);
 
-    enum { ToString, ToLocaleString, ValueOf, HasOwnProperty, PropertyIsEnumerable };
+    enum { ToString, ToLocaleString, ValueOf, HasOwnProperty, PropertyIsEnumerable,
+           DefineGetter, DefineSetter, LookupGetter, LookupSetter };
   private:
     int id;
   };
index 4111a1f5384cefb90890d55566d984f285b1e8a8..9bec7ea821ddd1fc224b1eb0e11b2e1fa0fe6330 100644 (file)
 
 #include "config.h"
 #include "property_slot.h"
+#include "object.h"
 
 namespace KJS {
 
-JSValue *PropertySlot::undefinedGetter(ExecState *, const Identifier& propertyName, const PropertySlot& slot)
+JSValue *PropertySlot::undefinedGetter(ExecState *, JSObject *, const Identifier& propertyName, const PropertySlot& slot)
 {
     return jsUndefined();
 }
 
+JSValue *PropertySlot::functionGetter(ExecState *exec, JSObject *originalObject, const Identifier&, const PropertySlot& slot)
+{
+    return slot.m_data.getterFunc->call(exec, originalObject, List::empty());
+}
+
 }
index d8cf61fd1be2ddca984ac141230142d422f7e4d3..90d29da669a39f490b6cc29f9b184a1d4ac7575a 100644 (file)
@@ -36,20 +36,20 @@ class JSObject;
 class PropertySlot
 {
 public:
-    typedef JSValue *(*GetValueFunc)(ExecState *, const Identifier&, const PropertySlot&);
+    typedef JSValue *(*GetValueFunc)(ExecState *, JSObject *originalObject, const Identifier&, const PropertySlot&);
 
-    JSValue *getValue(ExecState *exec, const Identifier& propertyName) const
+    JSValue *getValue(ExecState *exec, JSObject *originalObject, const Identifier& propertyName) const
     { 
         if (m_getValue == VALUE_SLOT_MARKER)
             return *m_data.valueSlot;
-        return m_getValue(exec, propertyName, *this); 
+        return m_getValue(exec, originalObject, propertyName, *this); 
     }
 
-    JSValue *getValue(ExecState *exec, unsigned propertyName) const
+    JSValue *getValue(ExecState *exec, JSObject *originalObject, unsigned propertyName) const
     { 
         if (m_getValue == VALUE_SLOT_MARKER)
             return *m_data.valueSlot;
-        return m_getValue(exec, Identifier::from(propertyName), *this); 
+        return m_getValue(exec, originalObject, Identifier::from(propertyName), *this); 
     }
     
     void setValueSlot(JSObject *slotBase, JSValue **valueSlot) 
@@ -81,7 +81,14 @@ public:
         m_data.index = index;
         m_getValue = getValue;
     }
-
+    
+    void setGetterSlot(JSObject *slotBase, JSObject *getterFunc)
+    {
+        m_getValue = functionGetter;
+        m_slotBase = slotBase;
+        m_data.getterFunc = getterFunc;
+    }
+    
     void setUndefined(JSObject *slotBase)
     {
         m_slotBase = slotBase;
@@ -94,12 +101,14 @@ public:
     unsigned index() const { return m_data.index; }
 
 private:
-    static JSValue *undefinedGetter(ExecState *, const Identifier&, const PropertySlot&);
-
+    static JSValue *undefinedGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
+    static JSValue *functionGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
+    
     GetValueFunc m_getValue;
 
     JSObject *m_slotBase;
     union {
+        JSObject *getterFunc;
         JSValue **valueSlot;
         const HashEntry *staticEntry;
         unsigned index;
index 8e7d51a767fd09cfc735ff46edaf0b1f99ab023b..d87971295955fc82066c965de82c76223562b09c 100644 (file)
@@ -52,12 +52,12 @@ StringInstance::StringInstance(JSObject *proto, const UString &string)
   setInternalValue(jsString(string));
 }
 
-JSValue *StringInstance::lengthGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot &slot)
+JSValue *StringInstance::lengthGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot &slot)
 {
     return jsNumber(static_cast<StringInstance *>(slot.slotBase())->internalValue()->toString(exec).size());
 }
 
-JSValue *StringInstance::indexGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot &slot)
+JSValue *StringInstance::indexGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot &slot)
 {
     const UChar c = static_cast<StringInstance *>(slot.slotBase())->internalValue()->toString(exec)[slot.index()];
     return jsString(UString(&c, 1));
index 2950ebc21704569ba8ecf1dfe64cc792190a614a..6bc686d56876599d798b935f08dabdae2fe27d81 100644 (file)
@@ -39,8 +39,8 @@ namespace KJS {
     virtual const ClassInfo *classInfo() const { return &info; }
     static const ClassInfo info;
   private:
-    static JSValue *lengthGetter(ExecState *exec, const Identifier&, const PropertySlot &slot);
-    static JSValue *indexGetter(ExecState *exec, const Identifier&, const PropertySlot &slot);
+    static JSValue *lengthGetter(ExecState *exec, JSObject *, const Identifier&, const PropertySlot &slot);
+    static JSValue *indexGetter(ExecState *exec, JSObject *, const Identifier&, const PropertySlot &slot);
   };
 
   /**
index d72bed63412f4661d0315efb1fdc8937ff1f2410..912a23e3a7a71e8d82223a77a9d199a3264c5747 100644 (file)
@@ -54,7 +54,8 @@ enum Type {
     BooleanType       = 3,
     StringType        = 4,
     NumberType        = 5,
-    ObjectType        = 6
+    ObjectType        = 6,
+    GetterSetterType  = 7
 };
 
 /**
@@ -132,6 +133,7 @@ class JSCell : public JSValue {
     friend class NumberImp;
     friend class StringImp;
     friend class JSObject;
+    friend class GetterSetterImp;
 private:
     JSCell();
     virtual ~JSCell();