Changeset 29588 in webkit for trunk/JavaScriptCore/kjs/function_object.cpp
- Timestamp:
- Jan 17, 2008, 11:27:33 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/function_object.cpp
r29067 r29588 37 37 #include <wtf/Assertions.h> 38 38 39 using namespace KJS; 39 namespace KJS { 40 40 41 41 // ------------------------------ FunctionPrototype ------------------------- 42 42 43 FunctionPrototype::FunctionPrototype(ExecState *exec) 44 { 45 static const Identifier* applyPropertyName = new Identifier("apply"); 46 static const Identifier* callPropertyName = new Identifier("call"); 47 48 putDirect(exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum); 49 putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::ToString, 0, exec->propertyNames().toString), DontEnum); 50 putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::Apply, 2, *applyPropertyName), DontEnum); 51 putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::Call, 1, *callPropertyName), DontEnum); 52 } 53 54 FunctionPrototype::~FunctionPrototype() 55 { 43 static JSValue* functionProtoFuncToString(ExecState*, JSObject*, const List&); 44 static JSValue* functionProtoFuncApply(ExecState*, JSObject*, const List&); 45 static JSValue* functionProtoFuncCall(ExecState*, JSObject*, const List&); 46 47 FunctionPrototype::FunctionPrototype(ExecState* exec) 48 { 49 static const Identifier* applyPropertyName = new Identifier("apply"); 50 static const Identifier* callPropertyName = new Identifier("call"); 51 52 putDirect(exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum); 53 54 putDirectFunction(new PrototypeFunction(exec, this, 0, exec->propertyNames().toString, functionProtoFuncToString), DontEnum); 55 putDirectFunction(new PrototypeFunction(exec, this, 2, *applyPropertyName, functionProtoFuncApply), DontEnum); 56 putDirectFunction(new PrototypeFunction(exec, this, 1, *callPropertyName, functionProtoFuncCall), DontEnum); 56 57 } 57 58 58 59 // ECMA 15.3.4 59 JSValue *FunctionPrototype::callAsFunction(ExecState*, JSObject* /*thisObj*/, const List &/*args*/) 60 { 61 return jsUndefined(); 62 } 63 64 // ------------------------------ FunctionProtoFunc ------------------------- 65 66 FunctionProtoFunc::FunctionProtoFunc(ExecState* exec, FunctionPrototype* funcProto, int i, int len, const Identifier& name) 67 : InternalFunctionImp(funcProto, name) 68 , id(i) 69 { 70 putDirect(exec->propertyNames().length, len, DontDelete | ReadOnly | DontEnum); 71 } 72 73 JSValue* FunctionProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args) 74 { 75 JSValue* result = NULL; 76 77 switch (id) { 78 case ToString: 60 JSValue* FunctionPrototype::callAsFunction(ExecState*, JSObject*, const List&) 61 { 62 return jsUndefined(); 63 } 64 65 // Functions 66 67 JSValue* functionProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&) 68 { 79 69 if (!thisObj || !thisObj->inherits(&InternalFunctionImp::info)) { 80 70 #ifndef NDEBUG 81 fprintf(stderr,"attempted toString() call on null or non-function object\n");71 fprintf(stderr,"attempted toString() call on null or non-function object\n"); 82 72 #endif 83 return throwError(exec, TypeError); 84 } 73 return throwError(exec, TypeError); 74 } 75 85 76 if (thisObj->inherits(&FunctionImp::info)) { 86 FunctionImp *fi = static_cast<FunctionImp*>(thisObj); 87 return jsString("function " + fi->functionName().ustring() + "(" + 88 fi->body->paramString() + ") " + fi->body->toString()); 89 } else if (thisObj->inherits(&InternalFunctionImp::info) && 90 !static_cast<InternalFunctionImp*>(thisObj)->functionName().isNull()) { 91 result = jsString("\nfunction " + static_cast<InternalFunctionImp*>(thisObj)->functionName().ustring() + "() {\n" 92 " [native code]\n}\n"); 93 } else { 94 result = jsString("[function]"); 95 } 96 break; 97 case Apply: { 98 JSValue *thisArg = args[0]; 99 JSValue *argArray = args[1]; 100 JSObject *func = thisObj; 101 102 if (!func->implementsCall()) 103 return throwError(exec, TypeError); 104 105 JSObject *applyThis; 77 FunctionImp* fi = static_cast<FunctionImp*>(thisObj); 78 return jsString("function " + fi->functionName().ustring() + "(" + fi->body->paramString() + ") " + fi->body->toString()); 79 } 80 81 if (thisObj->inherits(&InternalFunctionImp::info) && !static_cast<InternalFunctionImp*>(thisObj)->functionName().isNull()) 82 return jsString("\nfunction " + static_cast<InternalFunctionImp*>(thisObj)->functionName().ustring() + "() {\n [native code]\n}\n"); 83 84 return jsString("[function]"); 85 } 86 87 JSValue* functionProtoFuncApply(ExecState* exec, JSObject* thisObj, const List& args) 88 { 89 if (!thisObj->implementsCall()) 90 return throwError(exec, TypeError); 91 92 JSValue* thisArg = args[0]; 93 JSValue* argArray = args[1]; 94 95 JSObject* applyThis; 106 96 if (thisArg->isUndefinedOrNull()) 107 applyThis = exec->dynamicGlobalObject();97 applyThis = exec->dynamicGlobalObject(); 108 98 else 109 applyThis = thisArg->toObject(exec);99 applyThis = thisArg->toObject(exec); 110 100 111 101 List applyArgs; 112 102 if (!argArray->isUndefinedOrNull()) { 113 if (argArray->isObject() && 114 (static_cast<JSObject *>(argArray)->inherits(&ArrayInstance::info) || 115 static_cast<JSObject *>(argArray)->inherits(&Arguments::info))) { 116 117 JSObject *argArrayObj = static_cast<JSObject *>(argArray); 118 unsigned int length = argArrayObj->get(exec, exec->propertyNames().length)->toUInt32(exec); 119 for (unsigned int i = 0; i < length; i++) 120 applyArgs.append(argArrayObj->get(exec,i)); 121 } 122 else 103 if (argArray->isObject() && 104 (static_cast<JSObject*>(argArray)->inherits(&ArrayInstance::info) || 105 static_cast<JSObject*>(argArray)->inherits(&Arguments::info))) { 106 107 JSObject* argArrayObj = static_cast<JSObject*>(argArray); 108 unsigned int length = argArrayObj->get(exec, exec->propertyNames().length)->toUInt32(exec); 109 for (unsigned int i = 0; i < length; i++) 110 applyArgs.append(argArrayObj->get(exec, i)); 111 } else 112 return throwError(exec, TypeError); 113 } 114 115 return thisObj->call(exec, applyThis, applyArgs); 116 } 117 118 JSValue* functionProtoFuncCall(ExecState* exec, JSObject* thisObj, const List& args) 119 { 120 if (!thisObj->implementsCall()) 123 121 return throwError(exec, TypeError); 124 } 125 result = func->call(exec,applyThis,applyArgs); 126 } 127 break; 128 case Call: { 129 JSValue *thisArg = args[0]; 130 JSObject *func = thisObj; 131 132 if (!func->implementsCall()) 133 return throwError(exec, TypeError); 134 135 JSObject *callThis; 122 123 JSValue* thisArg = args[0]; 124 125 JSObject* callThis; 136 126 if (thisArg->isUndefinedOrNull()) 137 callThis = exec->dynamicGlobalObject();127 callThis = exec->dynamicGlobalObject(); 138 128 else 139 callThis = thisArg->toObject(exec);129 callThis = thisArg->toObject(exec); 140 130 141 131 List argsTail; 142 132 args.getSlice(1, argsTail); 143 result = func->call(exec, callThis, argsTail); 144 } 145 break; 146 } 147 148 return result; 133 return thisObj->call(exec, callThis, argsTail); 149 134 } 150 135 151 136 // ------------------------------ FunctionObjectImp ---------------------------- 152 137 153 FunctionObjectImp::FunctionObjectImp(ExecState* exec, FunctionPrototype* funcProto) 154 : InternalFunctionImp(funcProto) 155 { 156 putDirect(exec->propertyNames().prototype, funcProto, DontEnum|DontDelete|ReadOnly); 157 158 // no. of arguments for constructor 159 putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly|DontDelete|DontEnum); 160 } 161 162 FunctionObjectImp::~FunctionObjectImp() 163 { 138 FunctionObjectImp::FunctionObjectImp(ExecState* exec, FunctionPrototype* functionPrototype) 139 : InternalFunctionImp(functionPrototype) 140 { 141 putDirect(exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly); 142 143 // Number of arguments for constructor 144 putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum); 164 145 } 165 146 166 147 bool FunctionObjectImp::implementsConstruct() const 167 148 { 168 return true;149 return true; 169 150 } 170 151 … … 172 153 JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args, const Identifier& functionName, const UString& sourceURL, int lineNumber) 173 154 { 174 UString p(""); 175 UString body; 176 int argsSize = args.size(); 177 if (argsSize == 0) { 178 body = ""; 179 } else if (argsSize == 1) { 180 body = args[0]->toString(exec); 181 } else { 182 p = args[0]->toString(exec); 183 for (int k = 1; k < argsSize - 1; k++) 184 p += "," + args[k]->toString(exec); 185 body = args[argsSize-1]->toString(exec); 186 } 187 188 // parse the source code 189 int sourceId; 190 int errLine; 191 UString errMsg; 192 RefPtr<FunctionBodyNode> functionBody = parser().parse<FunctionBodyNode>(sourceURL, lineNumber, body.data(), body.size(), &sourceId, &errLine, &errMsg); 193 194 // notify debugger that source has been parsed 195 Debugger *dbg = exec->dynamicGlobalObject()->debugger(); 196 if (dbg) { 197 // send empty sourceURL to indicate constructed code 198 bool cont = dbg->sourceParsed(exec, sourceId, UString(), body, lineNumber, errLine, errMsg); 199 if (!cont) { 200 dbg->imp()->abort(); 201 return new JSObject(); 202 } 203 } 204 205 // no program node == syntax error - throw a syntax error 206 if (!functionBody) 207 // we can't return a Completion(Throw) here, so just set the exception 208 // and return it 209 return throwError(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL); 210 211 ScopeChain scopeChain; 212 scopeChain.push(exec->lexicalGlobalObject()); 213 214 FunctionImp* fimp = new FunctionImp(exec, functionName, functionBody.get(), scopeChain); 155 UString p(""); 156 UString body; 157 int argsSize = args.size(); 158 if (argsSize == 0) 159 body = ""; 160 else if (argsSize == 1) 161 body = args[0]->toString(exec); 162 else { 163 p = args[0]->toString(exec); 164 for (int k = 1; k < argsSize - 1; k++) 165 p += "," + args[k]->toString(exec); 166 body = args[argsSize - 1]->toString(exec); 167 } 168 169 // parse the source code 170 int sourceId; 171 int errLine; 172 UString errMsg; 173 RefPtr<FunctionBodyNode> functionBody = parser().parse<FunctionBodyNode>(sourceURL, lineNumber, body.data(), body.size(), &sourceId, &errLine, &errMsg); 174 175 // notify debugger that source has been parsed 176 Debugger* dbg = exec->dynamicGlobalObject()->debugger(); 177 if (dbg) { 178 // send empty sourceURL to indicate constructed code 179 bool cont = dbg->sourceParsed(exec, sourceId, UString(), body, lineNumber, errLine, errMsg); 180 if (!cont) { 181 dbg->imp()->abort(); 182 return new JSObject(); 183 } 184 } 185 186 // No program node == syntax error - throw a syntax error 187 if (!functionBody) 188 // We can't return a Completion(Throw) here, so just set the exception 189 // and return it 190 return throwError(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL); 191 192 ScopeChain scopeChain; 193 scopeChain.push(exec->lexicalGlobalObject()); 194 195 FunctionImp* fimp = new FunctionImp(exec, functionName, functionBody.get(), scopeChain); 196 197 // parse parameter list. throw syntax error on illegal identifiers 198 int len = p.size(); 199 const UChar* c = p.data(); 200 int i = 0, params = 0; 201 UString param; 202 while (i < len) { 203 while (*c == ' ' && i < len) 204 c++, i++; 205 if (Lexer::isIdentStart(c->uc)) { // else error 206 param = UString(c, 1); 207 c++, i++; 208 while (i < len && (Lexer::isIdentPart(c->uc))) { 209 param += UString(c, 1); 210 c++, i++; 211 } 212 while (i < len && *c == ' ') 213 c++, i++; 214 if (i == len) { 215 functionBody->parameters().append(Identifier(param)); 216 params++; 217 break; 218 } else if (*c == ',') { 219 functionBody->parameters().append(Identifier(param)); 220 params++; 221 c++, i++; 222 continue; 223 } // else error 224 } 225 return throwError(exec, SyntaxError, "Syntax error in parameter list"); 226 } 215 227 216 // parse parameter list. throw syntax error on illegal identifiers 217 int len = p.size(); 218 const UChar *c = p.data(); 219 int i = 0, params = 0; 220 UString param; 221 while (i < len) { 222 while (*c == ' ' && i < len) 223 c++, i++; 224 if (Lexer::isIdentStart(c->uc)) { // else error 225 param = UString(c, 1); 226 c++, i++; 227 while (i < len && (Lexer::isIdentPart(c->uc))) { 228 param += UString(c, 1); 229 c++, i++; 230 } 231 while (i < len && *c == ' ') 232 c++, i++; 233 if (i == len) { 234 functionBody->parameters().append(Identifier(param)); 235 params++; 236 break; 237 } else if (*c == ',') { 238 functionBody->parameters().append(Identifier(param)); 239 params++; 240 c++, i++; 241 continue; 242 } // else error 243 } 244 return throwError(exec, SyntaxError, "Syntax error in parameter list"); 245 } 246 247 List consArgs; 248 249 JSObject* objCons = exec->lexicalGlobalObject()->objectConstructor(); 250 JSObject* prototype = objCons->construct(exec, exec->emptyList()); 251 prototype->put(exec, exec->propertyNames().constructor, fimp, DontEnum|DontDelete|ReadOnly); 252 fimp->put(exec, exec->propertyNames().prototype, prototype, Internal|DontDelete); 253 return fimp; 228 List consArgs; 229 230 JSObject* objCons = exec->lexicalGlobalObject()->objectConstructor(); 231 JSObject* prototype = objCons->construct(exec, exec->emptyList()); 232 prototype->put(exec, exec->propertyNames().constructor, fimp, DontEnum | DontDelete | ReadOnly); 233 fimp->put(exec, exec->propertyNames().prototype, prototype, Internal | DontDelete); 234 return fimp; 254 235 } 255 236 … … 257 238 JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args) 258 239 { 259 return construct(exec, args, "anonymous", UString(), 0);240 return construct(exec, args, "anonymous", UString(), 0); 260 241 } 261 242 262 243 // ECMA 15.3.1 The Function Constructor Called as a Function 263 JSValue* FunctionObjectImp::callAsFunction(ExecState* exec, JSObject* /*thisObj*/, const List &args) 264 { 265 return construct(exec, args); 266 } 244 JSValue* FunctionObjectImp::callAsFunction(ExecState* exec, JSObject*, const List& args) 245 { 246 return construct(exec, args); 247 } 248 249 } // namespace KJS
Note:
See TracChangeset
for help on using the changeset viewer.