cfad47cfa3/tads3/vmtype.cpp

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
#ifdef RCSID
2
static char RCSid[] =
3
"$Header: d:/cvsroot/tads/tads3/VMTYPE.CPP,v 1.3 1999/05/17 02:52:29 MJRoberts Exp $";
4
#endif
5
6
/* 
7
 *   Copyright (c) 1998, 2002 Michael J. Roberts.  All Rights Reserved.
8
 *   
9
 *   Please see the accompanying license file, LICENSE.TXT, for information
10
 *   on using and copying this software.  
11
 */
12
/*
13
Name
14
  vmtype.cpp - VM types
15
Function
16
  
17
Notes
18
  
19
Modified
20
  11/18/98 MJRoberts  - Creation
21
*/
22
23
#include "t3std.h"
24
#include "vmtype.h"
25
#include "vmobj.h"
26
#include "vmstr.h"
27
#include "vmlst.h"
28
#include "vmpool.h"
29
30
/* ------------------------------------------------------------------------ */
31
/*
32
 *   Compare this value to another value to determine if the two values
33
 *   are equal. 
34
 */
35
int vm_val_t::equals(VMG_ const vm_val_t *v, int depth) const
36
{
37
    /* 
38
     *   if the second value is an object and the first isn't, use the object
39
     *   comparison of the second 
40
     */
41
    if (v->typ == VM_OBJ && typ != VM_OBJ)
42
        return vm_objp(vmg_ v->val.obj)
43
            ->equals(vmg_ v->val.obj, this, depth);
44
45
    /* figure out what to do based on my type */
46
    switch(typ)
47
    {
48
    case VM_NIL:
49
    case VM_TRUE:
50
        /* we match only if the other value is the same boolean value */
51
        return (v->typ == typ);
52
53
    case VM_STACK:
54
    case VM_CODEPTR:
55
        /* 
56
         *   we match only if the other value has the same type and its
57
         *   pointer value matches 
58
         */
59
        return (v->typ == typ && v->val.ptr == this->val.ptr);
60
61
    case VM_OBJ:
62
        /* use the object's polymorphic equality test routine */
63
        return vm_objp(vmg_ this->val.obj)
64
            ->equals(vmg_ this->val.obj, v, depth);
65
66
    case VM_PROP:
67
        /* we match if the other value is the same property ID */
68
        return (v->typ == VM_PROP && v->val.prop == this->val.prop);
69
70
    case VM_INT:
71
        /* we match if the other value is the same integer */
72
        return (v->typ == VM_INT && v->val.intval == this->val.intval);
73
74
    case VM_ENUM:
75
        return (v->typ == VM_ENUM && v->val.enumval == this->val.enumval);
76
77
    case VM_SSTRING:
78
        /* use the standard string comparison routine */
79
        return CVmObjString::
80
            const_equals(vmg_ G_const_pool->get_ptr(this->val.ofs), v);
81
82
    case VM_LIST:
83
        /* use the standard list comparison routine */
84
        return CVmObjList::
85
            const_equals(vmg_ this,
86
                         G_const_pool->get_ptr(this->val.ofs), v, depth);
87
88
    case VM_CODEOFS:
89
    case VM_FUNCPTR:
90
        /* we match if the other value is the same code offset */
91
        return (v->typ == typ && v->val.ofs == this->val.ofs);
92
93
    case VM_EMPTY:
94
        /* empty never matches anything */
95
        return FALSE;
96
97
    case VM_DSTRING:
98
        /* dstrings have no value, and are thus never equal to anything */
99
        return FALSE;
100
101
    default:
102
        /* other types are not recognized */
103
        return FALSE;
104
    }
105
}
106
107
/* ------------------------------------------------------------------------ */
108
/*
109
 *   Calculate a hash value 
110
 */
111
uint vm_val_t::calc_hash(VMG_ int depth) const
112
{
113
    /* see what we have */
114
    switch(typ)
115
    {
116
    case VM_NIL:
117
        /* this is rather arbitrary */
118
        return 0;
119
        
120
    case VM_TRUE:
121
        /* this is arbitrary, but at least make it different from nil */
122
        return 1;
123
        
124
    case VM_EMPTY:
125
        /* also arbitrary */
126
        return 2;
127
        
128
    case VM_CODEOFS:
129
    case VM_FUNCPTR:
130
        /* use a 16-bit hash of the code address */
131
        return (uint)((val.ofs & 0xffff)
132
                      ^ ((val.ofs & 0xffff0000) >> 16));
133
134
    case VM_PROP:
135
        /* use the property ID as the hash */
136
        return (uint)val.prop;
137
138
    case VM_INT:
139
        /* use a 16-bit hash of the int */
140
        return (uint)((val.intval & 0xffff)
141
                      ^ ((val.intval & 0xffff0000) >> 16));
142
143
    case VM_ENUM:
144
        /* use a 16-bit hash of the enum value */
145
        return (uint)((val.enumval & 0xffff)
146
                      ^ ((val.enumval & 0xffff0000) >> 16));
147
148
    case VM_OBJ:
149
        /* ask the object to calculate its hash value */
150
        return vm_objp(vmg_ val.obj)->calc_hash(vmg_ val.obj, depth);
151
        break;
152
153
    case VM_SSTRING:
154
        /* get the hash of the constant string */
155
        return CVmObjString::
156
            const_calc_hash(G_const_pool->get_ptr(val.ofs));
157
        break;
158
159
    case VM_LIST:
160
        /* get the hash of the constant list */
161
        return CVmObjList::
162
            const_calc_hash(vmg_ this, G_const_pool->get_ptr(val.ofs), depth);
163
164
    default:
165
        /* return an arbitrary value for any other type */
166
        return 3;
167
    }
168
}
169
170
/* ------------------------------------------------------------------------ */
171
/*
172
 *   Compare this value to the given value.  Returns a positive value if
173
 *   this value is greater than 'val', a negative value if this value is
174
 *   less than 'val', and 0 if the two values are equal.  Throws an error
175
 *   if a magnitude comparison is not meaningful for the involved types.  
176
 */
177
int vm_val_t::gen_compare_to(VMG_ const vm_val_t *v) const
178
{
179
    /* 
180
     *   if the other value is of type object and I'm not, let the object
181
     *   perform the comparison, and invert the sense of the result 
182
     */
183
    if (typ != VM_OBJ && v->typ == VM_OBJ)
184
        return -(v->compare_to(vmg_ this));
185
186
    /* the comparison depends on my type */
187
    switch(typ)
188
    {
189
    case VM_OBJ:
190
        /* let the object perform the comparison */
191
        return vm_objp(vmg_ this->val.obj)
192
            ->compare_to(vmg_ this->val.obj, v);
193
194
    case VM_SSTRING:
195
        /* compare the string */
196
        return CVmObjString::
197
            const_compare(vmg_ G_const_pool->get_ptr(this->val.ofs), v);
198
199
    case VM_INT:
200
        {
201
            int32 a, b;
202
            
203
            /* the comparison is legal only for another number */
204
            if (!v->is_numeric())
205
                err_throw(VMERR_INVALID_COMPARISON);
206
            
207
            /* get the integers */
208
            a = this->val.intval;
209
            b = v->val.intval;
210
211
            /* compare them and return the results */
212
            if (a > b)
213
                return 1;
214
            else if (a < b)
215
                return -1;
216
            else
217
                return 0;
218
        }
219
220
    default:
221
        /* other types cannot be compared for magnitude */
222
        err_throw(VMERR_INVALID_COMPARISON);
223
224
        /* this code is never reached, but the compiler doesn't know that */
225
        AFTER_ERR_THROW(return 0;)
226
    }
227
}
228
229
/* ------------------------------------------------------------------------ */
230
/*
231
 *   Get the underlying string constant value. 
232
 */
233
const char *vm_val_t::get_as_string(VMG0_) const
234
{
235
    /* check my type */
236
    if (typ == VM_SSTRING)
237
    {
238
        /* it's a constant string - return its text from the constant pool */
239
        return G_const_pool->get_ptr(val.ofs);
240
    }
241
    else if (typ == VM_OBJ)
242
    {
243
        /* it's an object - ask for its underlying string, if any */
244
        return vm_objp(vmg_ val.obj)->get_as_string(vmg0_);
245
    }
246
    else
247
    {
248
        /* other types do not have underlying strings */
249
        return 0;
250
    }
251
}
252
253
/* ------------------------------------------------------------------------ */
254
/*
255
 *   Get the underlying list constant value.  
256
 */
257
const char *vm_val_t::get_as_list(VMG0_) const
258
{
259
    /* check my type */
260
    if (typ == VM_LIST)
261
    {
262
        /* it's a constant list - return its data from the constant pool */
263
        return G_const_pool->get_ptr(val.ofs);
264
    }
265
    else if (typ == VM_OBJ)
266
    {
267
        /* it's an object - ask for its underlying list, if any */
268
        return vm_objp(vmg_ val.obj)->get_as_list();
269
    }
270
    else
271
    {
272
        /* other types do not have underlying lists */
273
        return 0;
274
    }
275
}
276
277
/* ------------------------------------------------------------------------ */
278
/*
279
 *   get the effective number of elements when this value is used as the
280
 *   right-hand side of a '+' or '-' operator whose left-hand side is a
281
 *   collection type
282
 */
283
size_t vm_val_t::get_coll_addsub_rhs_ele_cnt(VMG0_) const
284
{
285
    /* the handling depends on the type */
286
    switch(typ)
287
    {
288
    case VM_LIST:
289
        /* it's a static list - return the number of elements in the list */
290
        return vmb_get_len(G_const_pool->get_ptr(val.ofs));
291
292
    case VM_OBJ:
293
        /* ask the object what it thinks */
294
        return vm_objp(vmg_ val.obj)->get_coll_addsub_rhs_ele_cnt(vmg0_);
295
296
    default:
297
        /* for any other type, there's only one element */
298
        return 1;
299
    }
300
}
301
302
/*
303
 *   get the nth element of a collection add/sub operation of which we're
304
 *   the right-hand side 
305
 */
306
void vm_val_t::get_coll_addsub_rhs_ele(VMG_ size_t idx,
307
                                       vm_val_t *result) const
308
{
309
    /* the handling depends on the type */
310
    switch(typ)
311
    {
312
    case VM_LIST:
313
        /* it's a static list - get the nth element from the list */
314
        CVmObjList::index_list(vmg_ result,
315
                               G_const_pool->get_ptr(val.ofs), idx);
316
        break;
317
318
    case VM_OBJ:
319
        /* ask the object for its indexed value */
320
        vm_objp(vmg_ val.obj)->get_coll_addsub_rhs_ele(
321
            vmg_ result, val.obj, idx);
322
        break;
323
324
    default:
325
        /* for anything else, we have just our own value */
326
        *result = *this;
327
        break;
328
    }
329
}
330
331
/* ------------------------------------------------------------------------ */
332
/*
333
 *   Set to an integer giving the datatype code for the given value 
334
 */
335
void vm_val_t::set_datatype(VMG_ const vm_val_t *v)
336
{
337
    /* check for an object */
338
    if (v->typ == VM_OBJ)
339
    {
340
        /* check for List and String values */
341
        if (v->get_as_string(vmg0_) != 0)
342
        {
343
            /* treat this the same as a string constant */
344
            set_int((int)VM_SSTRING);
345
        }
346
        else if (v->get_as_list(vmg0_) != 0)
347
        {
348
            /* treat this the same as a list constant */
349
            set_int((int)VM_LIST);
350
        }
351
        else
352
        {
353
            /* any other type of object is simply an object */
354
            set_int((int)VM_OBJ);
355
        }
356
    }
357
    else
358
    {
359
        /* for any other type, return our internal type code */
360
        set_int((int)v->typ);
361
    }
362
}