1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
4 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
5 * Copyright (C) 2004 Apple Computer, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "internal.h"
25
26#include "array_object.h"
27#include "bool_object.h"
28#include "collector.h"
29#include "date_object.h"
30#include "debugger.h"
31#include "error_object.h"
32#include "function_object.h"
33#include "lexer.h"
34#include "math_object.h"
35#include "nodes.h"
36#include "number_object.h"
37#include "object.h"
38#include "object_object.h"
39#include "operations.h"
40#include "regexp_object.h"
41#include "string_object.h"
42#include <assert.h>
43#include <wtf/HashMap.h>
44#include <wtf/HashSet.h>
45#include <wtf/Vector.h>
46#include <math.h>
47#include <stdio.h>
48
49namespace KJS
50{
51
52#if COMPILER(MSVC)
53#define copysign _copysign
54#endif
55
56static const double D16 = 65536.0;
57static const double D32 = 4294967296.0;
58
59// ------------------------------ StringImp ------------------------------------
60
61JSValue *StringImp::toPrimitive(ExecState *, JSType) const
62{
63 return const_cast<StringImp *>(this);
64}
65
66bool GetterSetterImp::getPrimitiveNumber(ExecState *, double &number, JSValue *&value)
67{
68 ASSERT_NOT_REACHED();
69 number = 0;
70 value = nullptr;
71 return true;
72}
73
74bool StringImp::getPrimitiveNumber(ExecState *, double &number, JSValue *&value)
75{
76 value = this;
77 number = val.toDouble();
78 return false;
79}
80
81bool StringImp::toBoolean(ExecState *) const
82{
83 return (val.size() > 0);
84}
85
86double StringImp::toNumber(ExecState *) const
87{
88 return val.toDouble();
89}
90
91UString StringImp::toString(ExecState *) const
92{
93 return val;
94}
95
96JSObject *StringImp::toObject(ExecState *exec) const
97{
98 return new StringInstance(exec->lexicalInterpreter()->builtinStringPrototype(), const_cast<StringImp *>(this));
99}
100
101// ------------------------------ NumberImp ------------------------------------
102
103JSValue *NumberImp::toPrimitive(ExecState *, JSType) const
104{
105 return const_cast<NumberImp *>(this);
106}
107
108bool NumberImp::getPrimitiveNumber(ExecState *, double &number, JSValue *&value)
109{
110 number = val;
111 value = this;
112 return true;
113}
114
115bool NumberImp::toBoolean(ExecState *) const
116{
117 return val < 0.0 || val > 0.0; // false for NaN
118}
119
120double NumberImp::toNumber(ExecState *) const
121{
122 return val;
123}
124
125UString NumberImp::toString(ExecState *) const
126{
127 if (val == 0.0) { // +0.0 or -0.0
128 return "0";
129 }
130 return UString::from(val);
131}
132
133JSObject *NumberImp::toObject(ExecState *exec) const
134{
135 List args;
136 args.append(const_cast<NumberImp *>(this));
137 return static_cast<JSObject *>(exec->lexicalInterpreter()->builtinNumber()->construct(exec, args));
138}
139
140bool NumberImp::getUInt32(uint32_t &uint32) const
141{
142 uint32 = static_cast<uint32_t>(val);
143 return uint32 == val;
144}
145
146bool NumberImp::getTruncatedInt32(int32_t &int32) const
147{
148 if (!(val >= -2147483648.0 && val < 2147483648.0)) {
149 return false;
150 }
151 int32 = static_cast<int32_t>(val);
152 return true;
153}
154
155bool NumberImp::getTruncatedUInt32(uint32_t &uint32) const
156{
157 if (!(val >= 0.0 && val < 4294967296.0)) {
158 return false;
159 }
160 uint32 = static_cast<uint32_t>(val);
161 return true;
162}
163
164// --------------------------- GetterSetterImp ---------------------------------
165void GetterSetterImp::mark()
166{
167 JSCell::mark();
168
169 if (getter && !getter->marked()) {
170 getter->mark();
171 }
172 if (setter && !setter->marked()) {
173 setter->mark();
174 }
175}
176
177JSValue *GetterSetterImp::toPrimitive(ExecState *, JSType) const
178{
179 assert(false);
180 return jsNull();
181}
182
183bool GetterSetterImp::toBoolean(ExecState *) const
184{
185 assert(false);
186 return false;
187}
188
189double GetterSetterImp::toNumber(ExecState *) const
190{
191 assert(false);
192 return 0.0;
193}
194
195UString GetterSetterImp::toString(ExecState *) const
196{
197 assert(false);
198 return UString::null();
199}
200
201JSObject *GetterSetterImp::toObject(ExecState *exec) const
202{
203 assert(false);
204 return jsNull()->toObject(exec);
205}
206
207// ------------------------------ InternalFunctionImp --------------------------
208
209const ClassInfo InternalFunctionImp::info = {"Function", nullptr, nullptr, nullptr};
210
211InternalFunctionImp::InternalFunctionImp()
212{
213}
214
215InternalFunctionImp::InternalFunctionImp(FunctionPrototype *funcProto)
216 : JSObject(funcProto)
217{
218}
219
220InternalFunctionImp::InternalFunctionImp(FunctionPrototype *funcProto, const Identifier &name)
221 : JSObject(funcProto)
222 , m_name(name)
223{
224}
225
226bool InternalFunctionImp::implementsCall() const
227{
228 return true;
229}
230
231bool InternalFunctionImp::implementsHasInstance() const
232{
233 return true;
234}
235
236// ------------------------------ global functions -----------------------------
237
238double roundValue(double d)
239{
240 double ad = fabs(d);
241 if (ad == 0 || isNaN(d) || isInf(d)) {
242 return d;
243 }
244 return copysign(floor(ad), d);
245}
246
247int32_t toInt32(double d)
248{
249 if (isNaN(d) || isInf(d)) {
250 return 0;
251 }
252 double d32 = fmod(roundValue(d), D32);
253
254 if (d32 >= D32 / 2) {
255 d32 -= D32;
256 } else if (d32 < -D32 / 2) {
257 d32 += D32;
258 }
259
260 return static_cast<int32_t>(d32);
261}
262
263int32_t toInt32(double d, bool &ok)
264{
265 ok = true;
266 if (isNaN(d) || isInf(d)) {
267 ok = false;
268 return 0;
269 }
270 return toInt32(d);
271}
272
273uint32_t toUInt32(double dd)
274{
275 double d = roundValue(dd);
276 if (isNaN(d) || isInf(d)) {
277 return 0;
278 }
279 double d32 = fmod(d, D32);
280
281 if (d32 < 0) {
282 d32 += D32;
283 }
284
285 return static_cast<uint32_t>(d32);
286}
287
288uint16_t toUInt16(double dd)
289{
290 double d = roundValue(dd);
291 if (isNaN(d) || isInf(d)) {
292 return 0;
293 }
294 double d16 = fmod(d, D16);
295
296 if (d16 < 0) {
297 d16 += D16;
298 }
299
300 return static_cast<uint16_t>(d16);
301}
302
303//#ifndef NDEBUG
304void printInfo(ExecState *exec, const char *s, JSValue *o, int lineno)
305{
306 UString vString;
307 if (!o) {
308 fprintf(stderr, "KJS: %s: (null)", s);
309 } else {
310 JSValue *v = o;
311
312 unsigned int arrayLength = 0;
313 bool hadExcep = exec->hadException();
314
315 UString name;
316 switch (v->type()) {
317 case UnspecifiedType:
318 name = "Unspecified";
319 break;
320 case UndefinedType:
321 name = "Undefined";
322 break;
323 case NullType:
324 name = "Null";
325 break;
326 case BooleanType:
327 name = "Boolean";
328 break;
329 case StringType:
330 name = "String";
331 break;
332 case NumberType:
333 name = "Number";
334 break;
335 case ObjectType: {
336 JSObject *obj = static_cast<JSObject *>(v);
337 name = obj->className();
338 if (name.isNull()) {
339 name = "(unknown class)";
340 }
341
342 if (obj->inherits(&ArrayInstance::info)) {
343 arrayLength = obj->get(exec, exec->propertyNames().length)->toUInt32(exec);
344 }
345 vString = "[object " + name + "]"; // krazy:exclude=doublequote_chars
346 break;
347 }
348 case GetterSetterType:
349 name = "GetterSetter";
350 break;
351 }
352
353 // Avoid calling toString on a huge array (e.g. 4 billion elements, in mozilla/js/js1_5/Array/array-001.js)
354 if (arrayLength > 100) {
355 vString = UString("[ Array with ") + UString::from(arrayLength) + " elements ]";
356 } else if (v->type() != ObjectType) { // Don't want to call a user toString function!
357 vString = v->toString(exec);
358 }
359 if (!hadExcep) {
360 exec->clearException();
361 }
362
363 if (vString.size() > 350) {
364 vString = vString.substr(0, 350) + "...";
365 }
366
367 // Can't use two UString::ascii() in the same fprintf call
368 CString tempString(vString.cstring());
369
370 fprintf(stderr, "KJS: %s: %s : %s (%p)",
371 s, tempString.c_str(), name.ascii(), (void *)v);
372
373 if (lineno >= 0) {
374 fprintf(stderr, ", line %d\n", lineno);
375 } else {
376 fprintf(stderr, "\n");
377 }
378 }
379}
380//#endif
381
382}
383