summaryrefslogtreecommitdiffstats
path: root/kjs/value.h
blob: a54aa9240fe87e25c6d6895360f9fc9db371a659 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/*
 *  This file is part of the KDE libraries
 *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
 *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
 *  Copyright (C) 2003 Apple Computer, Inc.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 *
 */

#ifndef _KJS_VALUE_H_
#define _KJS_VALUE_H_

#include <stdlib.h> // Needed for size_t

#include "ustring.h"
#include "simple_number.h"

// Primitive data types

namespace KJS {

  class Value;
  class ValueImp;
  class ValueImpPrivate;
  class Undefined;
  class UndefinedImp;
  class Null;
  class NullImp;
  class Boolean;
  class BooleanImp;
  class String;
  class StringImp;
  class Number;
  class NumberImp;
  class Object;
  class ObjectImp;
  class Reference;
  class List;
  class ListImp;
  class Completion;
  class ExecState;

  /**
   * Primitive types
   */
  enum Type {
    UnspecifiedType = 0,
    UndefinedType   = 1,
    NullType        = 2,
    BooleanType     = 3,
    StringType      = 4,
    NumberType      = 5,
    ObjectType      = 6
  };

  /**
   * ValueImp is the base type for all primitives (Undefined, Null, Boolean,
   * String, Number) and objects in ECMAScript.
   *
   * Note: you should never inherit from ValueImp as it is for primitive types
   * only (all of which are provided internally by KJS). Instead, inherit from
   * ObjectImp.
   */
  class KJS_EXPORT ValueImp {
    friend class Collector;
    friend class Value;
    friend class ContextImp;
  public:
    ValueImp();
    virtual ~ValueImp();

    ValueImp* ref() { if (!SimpleNumber::is(this)) refcount++; return this; }
    bool deref() { if (SimpleNumber::is(this)) return false; else return (!--refcount); }

    virtual void mark();
    bool marked() const;
    void* operator new(size_t);
    void operator delete(void*);

    /**
     * @internal
     *
     * set by Object() so that the collector is allowed to delete us
     */
    void setGcAllowed();

    // Will crash if called on a simple number.
    void setGcAllowedFast() { _flags |= VI_GCALLOWED; }

    int toInteger(ExecState *exec) const;
    int toInt32(ExecState *exec) const;
    unsigned int toUInt32(ExecState *exec) const;
    unsigned short toUInt16(ExecState *exec) const;

    // Dispatch wrappers that handle the special small number case

    Type dispatchType() const;
    Value dispatchToPrimitive(ExecState *exec, Type preferredType = UnspecifiedType) const;
    bool dispatchToBoolean(ExecState *exec) const;
    double dispatchToNumber(ExecState *exec) const;
    UString dispatchToString(ExecState *exec) const;
    bool dispatchToUInt32(unsigned&) const;
    Object dispatchToObject(ExecState *exec) const;

    unsigned short int refcount;

    bool isDestroyed() const { return _flags & VI_DESTRUCTED; }

  private:
    unsigned short int _flags;

    virtual Type type() const = 0;

    // The conversion operations

    virtual Value toPrimitive(ExecState *exec, Type preferredType = UnspecifiedType) const = 0;
    virtual bool toBoolean(ExecState *exec) const = 0;
    virtual double toNumber(ExecState *exec) const = 0;
    // TODO: no need for the following 4 int conversions to be virtual
    virtual UString toString(ExecState *exec) const = 0;
    virtual Object toObject(ExecState *exec) const = 0;
    virtual bool toUInt32(unsigned&) const;

    enum {
      VI_MARKED = 1,
      VI_GCALLOWED = 2,
      VI_CREATED = 4,
      VI_DESTRUCTED = 8   // nice word we have here :)
    }; // VI means VALUEIMPL

    ValueImpPrivate *_vd;

    // Give a compile time error if we try to copy one of these.
    ValueImp(const ValueImp&);
    ValueImp& operator=(const ValueImp&);
  };

  /**
   * Value objects are act as wrappers ("smart pointers") around ValueImp
   * objects and their descendents. Instead of using ValueImps
   * (and derivatives) during normal program execution, you should use a
   * Value-derived class.
   *
   * Value maintains a pointer to a ValueImp object and uses a reference
   * counting scheme to ensure that the ValueImp object is not deleted or
   * garbage collected.
   *
   * Note: The conversion operations all return values of various types -
   * if an error occurs during conversion, an error object will instead
   * be returned (where possible), and the execution state's exception
   * will be set appropriately.
   */
  class KJS_EXPORT Value {
  public:
    Value() : rep(0) { }
    explicit Value(ValueImp *v);
    Value(const Value &v);
    ~Value();

    Value& operator=(const Value &v);
    /**
     * Returns whether or not this is a valid value. An invalid value
     * has a 0 implementation pointer and should not be used for
     * any other operation than this check. Current use: as a
     * distinct return value signalling failing dynamicCast() calls.
     */
    bool isValid() const { return rep != 0; }
    /**
     * @deprecated
     * Use !isValid() instead.
     */
    bool isNull() const { return rep == 0; }
    ValueImp *imp() const { return rep; }

    /**
     * Returns the type of value. This is one of UndefinedType, NullType,
     * BooleanType, StringType, NumberType, or ObjectType.
     *
     * @return The type of value
     */
    Type type() const { return rep->dispatchType(); }

    /**
     * Checks whether or not the value is of a particular tpye
     *
     * @param t The type to compare with
     * @return true if the value is of the specified type, otherwise false
     */
    bool isA(Type t) const { return rep->dispatchType() == t; }

    /**
     * Performs the ToPrimitive type conversion operation on this value
     * (ECMA 9.1)
     */
    Value toPrimitive(ExecState *exec,
                      Type preferredType = UnspecifiedType) const
      { return rep->dispatchToPrimitive(exec, preferredType); }

    /**
     * Performs the ToBoolean type conversion operation on this value (ECMA 9.2)
     */
    bool toBoolean(ExecState *exec) const { return rep->dispatchToBoolean(exec); }

    /**
     * Performs the ToNumber type conversion operation on this value (ECMA 9.3)
     */
    double toNumber(ExecState *exec) const { return rep->dispatchToNumber(exec); }

    /**
     * Performs the ToInteger type conversion operation on this value (ECMA 9.4)
     */
    int toInteger(ExecState *exec) const { return rep->toInteger(exec); }

    /**
     * Performs the ToInt32 type conversion operation on this value (ECMA 9.5)
     */
    int toInt32(ExecState *exec) const { return rep->toInt32(exec); }

    /**
     * Performs the ToUInt32 type conversion operation on this value (ECMA 9.6)
     */
    unsigned int toUInt32(ExecState *exec) const { return rep->toUInt32(exec); }

    /**
     * Performs the ToUInt16 type conversion operation on this value (ECMA 9.7)
     */
    unsigned short toUInt16(ExecState *exec) const { return rep->toUInt16(exec); }

    /**
     * Performs the ToString type conversion operation on this value (ECMA 9.8)
     */
    UString toString(ExecState *exec) const { return rep->dispatchToString(exec); }

    /**
     * Performs the ToObject type conversion operation on this value (ECMA 9.9)
     */
    Object toObject(ExecState *exec) const;

    /**
     * Checks if we can do a lossless conversion to UInt32.
     */
    bool toUInt32(unsigned& i) const { return rep->dispatchToUInt32(i); }

  protected:
    ValueImp *rep;
  };

  // Primitive types

  /**
   * Represents an primitive Undefined value. All instances of this class
   * share the same implementation object, so == will always return true
   * for any comparison between two Undefined objects.
   */
  class KJS_EXPORT Undefined : public Value {
  public:
    Undefined();

    /**
     * Converts a Value into an Undefined. If the value's type is not
     * UndefinedType, a null object will be returned (i.e. one with it's
     * internal pointer set to 0). If you do not know for sure whether the
     * value is of type UndefinedType, you should check the isValid()
     * methods afterwards before calling any methods on the returned value.
     *
     * @return The value converted to an Undefined
     */
    static Undefined dynamicCast(const Value &v);
  private:
    friend class UndefinedImp;
    explicit Undefined(UndefinedImp *v);

  };

  /**
   * Represents an primitive Null value. All instances of this class
   * share the same implementation object, so == will always return true
   * for any comparison between two Null objects.
   */
  class KJS_EXPORT Null : public Value {
  public:
    Null();

    /**
     * Converts a Value into an Null. If the value's type is not NullType,
     * a null object will be returned (i.e. one with it's internal pointer set
     * to 0). If you do not know for sure whether the value is of type
     * NullType, you should check the isValid() methods afterwards before
     * calling any methods on the returned value.
     *
     * @return The value converted to a Null
     */
    static Null dynamicCast(const Value &v);
  private:
    friend class NullImp;
    explicit Null(NullImp *v);
  };

  /**
   * Represents an primitive Boolean value
   */
  class KJS_EXPORT Boolean : public Value {
  public:
    Boolean(bool b = false);

    /**
     * Converts a Value into an Boolean. If the value's type is not BooleanType,
     * a null object will be returned (i.e. one with it's internal pointer set
     * to 0). If you do not know for sure whether the value is of type
     * BooleanType, you should check the isValid() methods afterwards before
     * calling any methods on the returned value.
     *
     * @return The value converted to a Boolean
     */
    static Boolean dynamicCast(const Value &v);

    bool value() const;
  private:
    friend class BooleanImp;
    explicit Boolean(BooleanImp *v);
  };

  /**
   * Represents an primitive String value
   */
  class KJS_EXPORT String : public Value {
  public:
    String(const UString &s = "");

    /**
     * Converts a Value into an String. If the value's type is not StringType,
     * a null object will be returned (i.e. one with it's internal pointer set
     * to 0). If you do not know for sure whether the value is of type
     * StringType, you should check the isValid() methods afterwards before
     * calling any methods on the returned value.
     *
     * @return The value converted to a String
     */
    static String dynamicCast(const Value &v);

    UString value() const;
  private:
    friend class StringImp;
    explicit String(StringImp *v);
  };

  extern const double NaN;
  extern const double Inf;

  /**
   * Represents an primitive Number value
   */
  class KJS_EXPORT Number : public Value {
    friend class ValueImp;
  public:
    Number(int i);
    Number(unsigned int u);
    Number(double d = 0.0);
    Number(long int l);
    Number(long unsigned int l);

    double value() const;
    int intValue() const;

    bool isNaN() const;
    bool isInf() const;

    /**
     * Converts a Value into an Number. If the value's type is not NumberType,
     * a null object will be returned (i.e. one with it's internal pointer set
     * to 0). If you do not know for sure whether the value is of type
     * NumberType, you should check the isNull() methods afterwards before
     * calling any methods on the returned value.
     *
     * @return The value converted to a Number
     */
    static Number dynamicCast(const Value &v);
  private:
    friend class NumberImp;
    explicit Number(NumberImp *v);
  };

} // namespace

#endif // _KJS_VALUE_H_