| | 1 | /* $Header: d:/cvsroot/tads/tads3/VMTYPE.H,v 1.3 1999/05/17 02:52:29 MJRoberts Exp $ */ |
| | 2 | |
| | 3 | /* |
| | 4 | * Copyright (c) 1998, 2002 Michael J. Roberts. All Rights Reserved. |
| | 5 | * |
| | 6 | * Please see the accompanying license file, LICENSE.TXT, for information |
| | 7 | * on using and copying this software. |
| | 8 | */ |
| | 9 | /* |
| | 10 | Name |
| | 11 | vmtype.h - VM types |
| | 12 | Function |
| | 13 | |
| | 14 | Notes |
| | 15 | |
| | 16 | Modified |
| | 17 | 10/21/98 MJRoberts - Creation |
| | 18 | */ |
| | 19 | |
| | 20 | #ifndef VMTYPE_H |
| | 21 | #define VMTYPE_H |
| | 22 | |
| | 23 | #include <string.h> |
| | 24 | #include <stdlib.h> |
| | 25 | |
| | 26 | #include "t3std.h" |
| | 27 | #include "vmerr.h" |
| | 28 | #include "vmerrnum.h" |
| | 29 | #include "vmglob.h" |
| | 30 | |
| | 31 | |
| | 32 | /* |
| | 33 | * Constant pool/code offset. This is an address of an object in the |
| | 34 | * pool. Pool offsets are 32-bit values. |
| | 35 | */ |
| | 36 | typedef uint32 pool_ofs_t; |
| | 37 | |
| | 38 | /* |
| | 39 | * Savepoint ID's are stored in a single byte; since we store many |
| | 40 | * copies of savepoint ID's (since they need to be stored with each undo |
| | 41 | * list head), we want to save some space on this type. This limits us |
| | 42 | * to 256 simultaneous savepoints, but this should be more than we |
| | 43 | * actually want to keep around anyway, because of the amount of memory |
| | 44 | * it would consume to try to keep more than that around. |
| | 45 | */ |
| | 46 | typedef uchar vm_savept_t; |
| | 47 | const vm_savept_t VM_SAVEPT_MAX = 255; |
| | 48 | |
| | 49 | /* |
| | 50 | * Object ID type. VM_INVALID_OBJ is a distinguished value that serves |
| | 51 | * as an invalid object ID (a null pointer, effectively); no object can |
| | 52 | * ever have this ID. |
| | 53 | */ |
| | 54 | typedef uint32 vm_obj_id_t; |
| | 55 | const vm_obj_id_t VM_INVALID_OBJ = 0; |
| | 56 | |
| | 57 | /* |
| | 58 | * Property ID. Property ID's are 16-bit values. VM_INVALID_PROP is a |
| | 59 | * distinguished value that serves as an invalid property ID, which can |
| | 60 | * be used to indicate the absence of a property value. |
| | 61 | */ |
| | 62 | typedef uint16 vm_prop_id_t; |
| | 63 | const vm_prop_id_t VM_INVALID_PROP = 0; |
| | 64 | |
| | 65 | /* |
| | 66 | * Maximum recursion depth for recursive equality tests and hash |
| | 67 | * calculations. |
| | 68 | * |
| | 69 | * When we're comparing or hashing a tree of references by value, such as |
| | 70 | * when we're comparing two vectors or hashing a vector, we'll keep track |
| | 71 | * of the recursion depth of our tree traversal. If we reach this depth, |
| | 72 | * we'll throw an error on the assumption that the tree contains cycles and |
| | 73 | * thus cannot be hashed or compared by value. This depth is chosen to be |
| | 74 | * large enough that it's unlikely we'll exceed it with acyclical trees, |
| | 75 | * but small enough that we probably won't blow the C++ stack before we |
| | 76 | * reach this depth. |
| | 77 | */ |
| | 78 | const int VM_MAX_TREE_DEPTH_EQ = 256; |
| | 79 | |
| | 80 | /* |
| | 81 | * Datatypes |
| | 82 | */ |
| | 83 | enum vm_datatype_t |
| | 84 | { |
| | 85 | /* nil - doubles as a null pointer and a boolean false */ |
| | 86 | VM_NIL = 1, |
| | 87 | |
| | 88 | /* true - boolean true */ |
| | 89 | VM_TRUE, |
| | 90 | |
| | 91 | /* |
| | 92 | * Stack pointer (this is used to store a pointer to the enclosing |
| | 93 | * frame in a stack frame). This is a native machine pointer. |
| | 94 | */ |
| | 95 | VM_STACK, |
| | 96 | |
| | 97 | /* |
| | 98 | * Code pointer (this is used to store a pointer to the return |
| | 99 | * address in a stack frame, for example). This is a native machine |
| | 100 | * pointer. This differs from VM_CODEOFS in that this is a native |
| | 101 | * machine pointer. |
| | 102 | */ |
| | 103 | VM_CODEPTR, |
| | 104 | |
| | 105 | /* object reference */ |
| | 106 | VM_OBJ, |
| | 107 | |
| | 108 | /* property ID */ |
| | 109 | VM_PROP, |
| | 110 | |
| | 111 | /* 32-bit signed integer */ |
| | 112 | VM_INT, |
| | 113 | |
| | 114 | /* |
| | 115 | * string constant value - the value is an offset into the constant |
| | 116 | * pool of the string descriptor |
| | 117 | */ |
| | 118 | VM_SSTRING, |
| | 119 | |
| | 120 | /* |
| | 121 | * self-printing string value - the value is an offset into the |
| | 122 | * constant pool of the string descriptor |
| | 123 | */ |
| | 124 | VM_DSTRING, |
| | 125 | |
| | 126 | /* |
| | 127 | * list constant - the value is an offset into the constant pool of |
| | 128 | * the list descriptor |
| | 129 | */ |
| | 130 | VM_LIST, |
| | 131 | |
| | 132 | /* |
| | 133 | * byte-code constant offset - this is an offset into the byte-code |
| | 134 | * pool. This differs from VM_CODEPTR in that this is an offset in |
| | 135 | * the byte-code constant pool rather than a native machine pointer. |
| | 136 | * |
| | 137 | */ |
| | 138 | VM_CODEOFS, |
| | 139 | |
| | 140 | /* |
| | 141 | * function pointer - this is represented as an offset into the |
| | 142 | * byte-code pool. This differs from VM_CODEOFS in that the code |
| | 143 | * referenced by a VM_CODEOFS value is generally invoked directly |
| | 144 | * whenever the value is evaluated, whereas VM_FUNCPTR values are |
| | 145 | * used to convey function pointers, so the underlying code is not |
| | 146 | * executed implicitly on evaluation of such a value but must be |
| | 147 | * explicitly invoked. |
| | 148 | */ |
| | 149 | VM_FUNCPTR, |
| | 150 | |
| | 151 | /* |
| | 152 | * This is a special pseudo-type used to indicate that a value is |
| | 153 | * not present. This differs from nil, in that nil is a null |
| | 154 | * reference or false value, whereas this indicates that there's no |
| | 155 | * specified value at all. This is used, for example, to indicate |
| | 156 | * in an undo record that a property did not previously exist. |
| | 157 | */ |
| | 158 | VM_EMPTY, |
| | 159 | |
| | 160 | /* |
| | 161 | * This is a special pseudo-type used to indicate that evaluating an |
| | 162 | * expression requires executing system code. The value stored is a |
| | 163 | * pointer to a constant CVmNativeCodeDesc object, which describes a |
| | 164 | * native code method. |
| | 165 | */ |
| | 166 | VM_NATIVE_CODE, |
| | 167 | |
| | 168 | /* |
| | 169 | * Enumerated constant |
| | 170 | */ |
| | 171 | VM_ENUM, |
| | 172 | |
| | 173 | /* |
| | 174 | * First invalid type ID. Tools (such as compilers and debuggers) |
| | 175 | * can use this ID and any higher ID values to flag their own |
| | 176 | * internal types. |
| | 177 | */ |
| | 178 | VM_FIRST_INVALID_TYPE |
| | 179 | }; |
| | 180 | |
| | 181 | /* macro to create a private type constant for internal use in a tool */ |
| | 182 | #define VM_MAKE_INTERNAL_TYPE(idx) \ |
| | 183 | ((vm_datatype_t)(((int)VM_FIRST_INVALID_TYPE) + (idx))) |
| | 184 | |
| | 185 | /* |
| | 186 | * Value container. Local variables, stack locations, and other value |
| | 187 | * holders use this structure to store a value and its type. |
| | 188 | */ |
| | 189 | struct vm_val_t |
| | 190 | { |
| | 191 | vm_datatype_t typ; |
| | 192 | union |
| | 193 | { |
| | 194 | /* stack/code pointer */ |
| | 195 | void *ptr; |
| | 196 | |
| | 197 | /* object reference */ |
| | 198 | vm_obj_id_t obj; |
| | 199 | |
| | 200 | /* property ID */ |
| | 201 | vm_prop_id_t prop; |
| | 202 | |
| | 203 | /* 32-bit integer */ |
| | 204 | int32 intval; |
| | 205 | |
| | 206 | /* enumerated constant */ |
| | 207 | uint32 enumval; |
| | 208 | |
| | 209 | /* sstring/dstring/list constant pool offset/pcode pool offset */ |
| | 210 | pool_ofs_t ofs; |
| | 211 | |
| | 212 | /* native code descriptor */ |
| | 213 | const class CVmNativeCodeDesc *native_desc; |
| | 214 | } val; |
| | 215 | |
| | 216 | /* set various types of values */ |
| | 217 | void set_empty() { typ = VM_EMPTY; } |
| | 218 | void set_nil() { typ = VM_NIL; } |
| | 219 | void set_true() { typ = VM_TRUE; } |
| | 220 | void set_stack(void *ptr) { typ = VM_STACK; val.ptr = ptr; } |
| | 221 | void set_codeptr(void *ptr) { typ = VM_CODEPTR; val.ptr = ptr; } |
| | 222 | void set_obj(vm_obj_id_t obj) { typ = VM_OBJ; val.obj = obj; } |
| | 223 | void set_nil_obj() { typ = VM_NIL; val.obj = VM_INVALID_OBJ; } |
| | 224 | void set_propid(vm_prop_id_t prop) { typ = VM_PROP; val.prop = prop; } |
| | 225 | void set_int(int32 intval) { typ = VM_INT; val.intval = intval; } |
| | 226 | void set_enum(uint32 enumval) { typ = VM_ENUM; val.enumval = enumval; } |
| | 227 | void set_sstring(pool_ofs_t ofs) { typ = VM_SSTRING; val.ofs = ofs; } |
| | 228 | void set_dstring(pool_ofs_t ofs) { typ = VM_DSTRING; val.ofs = ofs; } |
| | 229 | void set_list(pool_ofs_t ofs) { typ = VM_LIST; val.ofs = ofs; } |
| | 230 | void set_codeofs(pool_ofs_t ofs) { typ = VM_CODEOFS; val.ofs = ofs; } |
| | 231 | void set_fnptr(pool_ofs_t ofs) { typ = VM_FUNCPTR; val.ofs = ofs; } |
| | 232 | void set_native(const class CVmNativeCodeDesc *desc) |
| | 233 | { typ = VM_NATIVE_CODE; val.native_desc = desc; } |
| | 234 | |
| | 235 | /* |
| | 236 | * set an object or nil value: if the object ID is VM_INVALID_OBJ, |
| | 237 | * we'll set the type to nil |
| | 238 | */ |
| | 239 | void set_obj_or_nil(vm_obj_id_t obj) |
| | 240 | { |
| | 241 | /* set the object value initially */ |
| | 242 | typ = VM_OBJ; |
| | 243 | val.obj = obj; |
| | 244 | |
| | 245 | /* if the object is invalid, set the type to nil */ |
| | 246 | if (obj == VM_INVALID_OBJ) |
| | 247 | typ = VM_NIL; |
| | 248 | } |
| | 249 | |
| | 250 | /* set to an integer giving the datatype of the given value */ |
| | 251 | void set_datatype(VMG_ const vm_val_t *val); |
| | 252 | |
| | 253 | /* set to nil if 'val' is zero, true if 'val' is non-zero */ |
| | 254 | void set_logical(int v) { typ = (v != 0 ? VM_TRUE : VM_NIL); } |
| | 255 | |
| | 256 | /* determine if the value is logical (nil or true) */ |
| | 257 | int is_logical() const { return (typ == VM_NIL || typ == VM_TRUE); } |
| | 258 | |
| | 259 | /* |
| | 260 | * Get a logical as numeric TRUE or FALSE. This does not perform |
| | 261 | * any type checking; the caller must ensure that the value is |
| | 262 | * either true or nil, or this may return meaningless results. |
| | 263 | */ |
| | 264 | int get_logical() const { return (typ == VM_TRUE); } |
| | 265 | |
| | 266 | /* |
| | 267 | * Get the underlying string constant value. If the value does not |
| | 268 | * have an underlying string constant (because it is of a type that |
| | 269 | * does not store a string value), this will return null. |
| | 270 | */ |
| | 271 | const char *get_as_string(VMG0_) const; |
| | 272 | |
| | 273 | /* |
| | 274 | * Get the underlying list constant value. If the value does not |
| | 275 | * have an underlying list constant (because it is of a type that |
| | 276 | * does not store list data), this returns null. |
| | 277 | */ |
| | 278 | const char *get_as_list(VMG0_) const; |
| | 279 | |
| | 280 | /* |
| | 281 | * Get the effective number of elements from this value when the |
| | 282 | * value is used as the right-hand side of a '+' or '-' operator |
| | 283 | * whose left-hand side implies that the operation involved is a set |
| | 284 | * operation (this is the case is the left-hand side is of certain |
| | 285 | * collection types, such as list, array, or vector); and get the |
| | 286 | * nth element in that context. Most types of values contribute |
| | 287 | * only one element to these operations, but some collection types |
| | 288 | * supply their elements individually, rather than the collection |
| | 289 | * itself, for these operations. 'idx' is the 1-based index of the |
| | 290 | * element to retrieve. |
| | 291 | */ |
| | 292 | size_t get_coll_addsub_rhs_ele_cnt(VMG0_) const; |
| | 293 | void get_coll_addsub_rhs_ele(VMG_ size_t idx, vm_val_t *result) const; |
| | 294 | |
| | 295 | /* |
| | 296 | * Convert a numeric value to an integer value. If the value isn't |
| | 297 | * numeric, throws an error. |
| | 298 | */ |
| | 299 | void num_to_logical() |
| | 300 | { |
| | 301 | /* check the type */ |
| | 302 | if (typ == VM_INT) |
| | 303 | { |
| | 304 | /* it's an integer - treat 0 as nil, all else as true */ |
| | 305 | typ = (val.intval == 0 ? VM_NIL : VM_TRUE); |
| | 306 | } |
| | 307 | else |
| | 308 | { |
| | 309 | /* it's not a number - throw an error */ |
| | 310 | err_throw(VMERR_NO_LOG_CONV); |
| | 311 | } |
| | 312 | } |
| | 313 | |
| | 314 | /* determine if the value is some kind of number */ |
| | 315 | int is_numeric() const { return (typ == VM_INT); } |
| | 316 | |
| | 317 | /* |
| | 318 | * Convert a numeric value to an integer. If the value is not |
| | 319 | * numeric, we'll throw an error. |
| | 320 | */ |
| | 321 | int32 num_to_int() const |
| | 322 | { |
| | 323 | /* check the type */ |
| | 324 | if (typ == VM_INT) |
| | 325 | { |
| | 326 | /* it's an integer already - return the value directly */ |
| | 327 | return val.intval; |
| | 328 | } |
| | 329 | else |
| | 330 | { |
| | 331 | /* |
| | 332 | * other types are not numeric and can't be directly |
| | 333 | * converted to integer by arithmetic conversion |
| | 334 | */ |
| | 335 | err_throw(VMERR_NUM_VAL_REQD); |
| | 336 | |
| | 337 | /* the compiler might not know we'll never get here */ |
| | 338 | AFTER_ERR_THROW(return 0;) |
| | 339 | } |
| | 340 | } |
| | 341 | |
| | 342 | /* |
| | 343 | * determine if the numeric value is zero; throws an error if the |
| | 344 | * value is not numeric |
| | 345 | */ |
| | 346 | int num_is_zero() const |
| | 347 | { |
| | 348 | /* check the type */ |
| | 349 | if (typ == VM_INT) |
| | 350 | { |
| | 351 | /* check the integer value to see if it's zero */ |
| | 352 | return (val.intval == 0); |
| | 353 | } |
| | 354 | else |
| | 355 | { |
| | 356 | /* it's not a number */ |
| | 357 | err_throw(VMERR_NUM_VAL_REQD); |
| | 358 | |
| | 359 | /* in case the compiler doesn't know we'll never get here */ |
| | 360 | AFTER_ERR_THROW(return 0;) |
| | 361 | } |
| | 362 | } |
| | 363 | |
| | 364 | /* |
| | 365 | * Determine if this value equals a given value. The nature of the |
| | 366 | * match depends on the type of this value: |
| | 367 | * |
| | 368 | * integers, property ID's, code offsets: the types and values must |
| | 369 | * match exactly. |
| | 370 | * |
| | 371 | * string and list constants: the other value must either be the same |
| | 372 | * type of constant, or an object that has an underlying value of the |
| | 373 | * same type; and the contents of the strings or lists must match. |
| | 374 | * |
| | 375 | * objects: the match depends on the type of the object. We invoke the |
| | 376 | * object's virtual equals() routine to make this determination. |
| | 377 | * |
| | 378 | * 'depth' has the same meaning as in calc_hash(). |
| | 379 | */ |
| | 380 | int equals(VMG_ const vm_val_t *v) const { return equals(vmg_ v, 0); } |
| | 381 | int equals(VMG_ const vm_val_t *val, int depth) const; |
| | 382 | |
| | 383 | /* |
| | 384 | * Calculate a hash for the value. The meaning of the hash varies by |
| | 385 | * type, but is stable for a given value. 'depth' is a recursion depth |
| | 386 | * counter, with the same meaning as in CVmObject::calc_hash(). |
| | 387 | */ |
| | 388 | uint calc_hash(VMG0_) const { return calc_hash(vmg_ 0); } |
| | 389 | uint calc_hash(VMG_ int depth) const; |
| | 390 | |
| | 391 | /* |
| | 392 | * Compare this value to the given value. Returns a value greater than |
| | 393 | * zero if this value is greater than 'val', a value less than zero if |
| | 394 | * this value is less than 'val', or 0 if the two values are equal. |
| | 395 | * Throws an error if the two values are not comparable. |
| | 396 | * |
| | 397 | * By far the most common type of comparison is between integers, so we |
| | 398 | * test in-line to see if we have two integer values, and if so, use a |
| | 399 | * fast in-line comparison. If we don't have two integers, we'll use |
| | 400 | * our full out-of-line test, which will look at other more interesting |
| | 401 | * type combinations. |
| | 402 | */ |
| | 403 | int compare_to(VMG_ const vm_val_t *b) const |
| | 404 | { |
| | 405 | if (typ == VM_INT && b->typ == VM_INT) |
| | 406 | return (val.intval > b->val.intval |
| | 407 | ? 1 : val.intval < b->val.intval ? -1 : 0); |
| | 408 | else |
| | 409 | return gen_compare_to(vmg_ b); |
| | 410 | } |
| | 411 | |
| | 412 | /* |
| | 413 | * relative value comparisons |
| | 414 | */ |
| | 415 | |
| | 416 | /* self > b */ |
| | 417 | int is_gt(VMG_ const vm_val_t *b) const |
| | 418 | { |
| | 419 | if (typ == VM_INT && b->typ == VM_INT) |
| | 420 | return val.intval > b->val.intval; |
| | 421 | else |
| | 422 | return gen_compare_to(vmg_ b) > 0; |
| | 423 | } |
| | 424 | |
| | 425 | /* self >= b */ |
| | 426 | int is_ge(VMG_ const vm_val_t *b) const |
| | 427 | { |
| | 428 | if (typ == VM_INT && b->typ == VM_INT) |
| | 429 | return val.intval >= b->val.intval; |
| | 430 | else |
| | 431 | return gen_compare_to(vmg_ b) >= 0; |
| | 432 | } |
| | 433 | |
| | 434 | /* self < b */ |
| | 435 | int is_lt(VMG_ const vm_val_t *b) const |
| | 436 | { |
| | 437 | if (typ == VM_INT && b->typ == VM_INT) |
| | 438 | return val.intval < b->val.intval; |
| | 439 | else |
| | 440 | return gen_compare_to(vmg_ b) < 0; |
| | 441 | } |
| | 442 | |
| | 443 | /* self <= b */ |
| | 444 | int is_le(VMG_ const vm_val_t *b) const |
| | 445 | { |
| | 446 | if (typ == VM_INT && b->typ == VM_INT) |
| | 447 | return val.intval <= b->val.intval; |
| | 448 | else |
| | 449 | return gen_compare_to(vmg_ b) <= 0; |
| | 450 | } |
| | 451 | |
| | 452 | private: |
| | 453 | /* out-of-line comparison, used when we don't have two integers */ |
| | 454 | int gen_compare_to(VMG_ const vm_val_t *val) const; |
| | 455 | }; |
| | 456 | |
| | 457 | /* ------------------------------------------------------------------------ */ |
| | 458 | /* |
| | 459 | * Native code descriptor. This describes a native method call of an |
| | 460 | * intrinsic class object. |
| | 461 | */ |
| | 462 | class CVmNativeCodeDesc |
| | 463 | { |
| | 464 | public: |
| | 465 | /* create a descriptor with an exact number of arguments */ |
| | 466 | CVmNativeCodeDesc(int argc) |
| | 467 | { |
| | 468 | /* remember the parameters - there are no optional arguments */ |
| | 469 | min_argc_ = argc; |
| | 470 | opt_argc_ = 0; |
| | 471 | varargs_ = FALSE; |
| | 472 | } |
| | 473 | |
| | 474 | /* create a descriptor with optional arguments (but not varargs) */ |
| | 475 | CVmNativeCodeDesc(int min_argc, int opt_argc) |
| | 476 | { |
| | 477 | /* remember the parameters */ |
| | 478 | min_argc_ = min_argc; |
| | 479 | opt_argc_ = opt_argc; |
| | 480 | varargs_ = FALSE; |
| | 481 | } |
| | 482 | |
| | 483 | /* create a descriptor with optional arguments and/or varargs */ |
| | 484 | CVmNativeCodeDesc(int min_argc, int opt_argc, int varargs) |
| | 485 | { |
| | 486 | /* remember the parameters */ |
| | 487 | min_argc_ = min_argc; |
| | 488 | opt_argc_ = opt_argc; |
| | 489 | varargs_ = varargs; |
| | 490 | } |
| | 491 | |
| | 492 | /* check the given number of arguments for validity */ |
| | 493 | int args_ok(int argc) const |
| | 494 | { |
| | 495 | /* |
| | 496 | * the actual parameters must number at least the minimum, and |
| | 497 | * cannot exceed the maximum (i.e., the minimum plus the |
| | 498 | * optionals) unless we have varargs, in which case there is no |
| | 499 | * maximum |
| | 500 | */ |
| | 501 | return (argc >= min_argc_ |
| | 502 | && (varargs_ || argc <= min_argc_ + opt_argc_)); |
| | 503 | } |
| | 504 | |
| | 505 | /* minimum argument count */ |
| | 506 | int min_argc_; |
| | 507 | |
| | 508 | /* number of optional named arguments beyond the minimum */ |
| | 509 | int opt_argc_; |
| | 510 | |
| | 511 | /* |
| | 512 | * true -> varargs: any number of arguments greater than or equal to |
| | 513 | * min_argc_ are valid |
| | 514 | */ |
| | 515 | int varargs_; |
| | 516 | }; |
| | 517 | |
| | 518 | /* ------------------------------------------------------------------------ */ |
| | 519 | /* |
| | 520 | * String handling - these routines are provided as covers to allow for |
| | 521 | * easier adjustment for Unicode or other encodings. Don't include these |
| | 522 | * if we're compiling interface routines for the HTML TADS environment, |
| | 523 | * since HTML TADS has its own similar definitions for these, and we don't |
| | 524 | * need these for interface code. |
| | 525 | * |
| | 526 | * NOTE: The purpose of this macro is to indicate that we're being |
| | 527 | * #included by an HTML TADS source file - that is, the current compile run |
| | 528 | * is for an htmltads/xxx.cpp file. Do NOT #define this macro when |
| | 529 | * compiling tads3/xxx.cpp files. The tads3/xxx.cpp files have absolutely |
| | 530 | * no explicit dependencies on the htmltads subsystem and thus don't |
| | 531 | * #include the htmltads headers that would provide the conflicting |
| | 532 | * interface definitions for these functions. The conflict is in the other |
| | 533 | * direction: some of the htmltads source files explicitly depend on tads3 |
| | 534 | * headers, so they indirectly #include this header. So, this macro needs |
| | 535 | * to be defined only when compiling htmltads/xxx.cpp files. |
| | 536 | */ |
| | 537 | #ifdef T3_COMPILING_FOR_HTML |
| | 538 | #include "tadshtml.h" |
| | 539 | #else |
| | 540 | |
| | 541 | inline size_t get_strlen(const textchar_t *str) { return strlen(str); } |
| | 542 | inline void do_strcpy(textchar_t *dst, const textchar_t *src) |
| | 543 | { strcpy(dst, src); } |
| | 544 | |
| | 545 | #endif /* T3_COMPILING_FOR_HTML */ |
| | 546 | |
| | 547 | /* ------------------------------------------------------------------------ */ |
| | 548 | /* |
| | 549 | * Portable Binary Representations. When we store certain types of |
| | 550 | * information in memory, we store it in a format that is identical to |
| | 551 | * the format we use in portable binary files; using this format allows |
| | 552 | * us to read and write binary files as byte images, without any |
| | 553 | * interpretation, which greatly improves I/O performance in many cases. |
| | 554 | */ |
| | 555 | |
| | 556 | /* |
| | 557 | * Portable binary LENGTH indicator. This is used to store length |
| | 558 | * prefixes for strings, lists, and similar objects. We use a UINT2 |
| | 559 | * (16-bit unsigned integer) for this type of value. |
| | 560 | */ |
| | 561 | const size_t VMB_LEN = 2; |
| | 562 | inline void vmb_put_len(char *buf, size_t len) { oswp2(buf, len); } |
| | 563 | inline size_t vmb_get_len(const char *buf) { return osrp2(buf); } |
| | 564 | |
| | 565 | /* |
| | 566 | * Portable binary unsigned 2-byte integer |
| | 567 | */ |
| | 568 | const size_t VMB_UINT2 = 2; |
| | 569 | inline void vmb_put_uint2(char *buf, uint16 i) { oswp2(buf, i); } |
| | 570 | inline uint16 vmb_get_uint2(const char *buf) { return osrp2(buf); } |
| | 571 | |
| | 572 | /* |
| | 573 | * Portable binary object ID. |
| | 574 | */ |
| | 575 | const size_t VMB_OBJECT_ID = 4; |
| | 576 | inline void vmb_put_objid(char *buf, vm_obj_id_t obj) { oswp4(buf, obj); } |
| | 577 | inline vm_obj_id_t vmb_get_objid(const char *buf) { return t3rp4u(buf); } |
| | 578 | |
| | 579 | /* |
| | 580 | * Portable binary property ID |
| | 581 | */ |
| | 582 | const size_t VMB_PROP_ID = 2; |
| | 583 | inline void vmb_put_propid(char *buf, vm_obj_id_t prop) { oswp2(buf, prop); } |
| | 584 | inline vm_prop_id_t vmb_get_propid(const char *buf) { return osrp2(buf); } |
| | 585 | |
| | 586 | /* |
| | 587 | * Portable data holder. This is used to store varying-type data items; |
| | 588 | * for example, this is used to store an element in a list, or the value |
| | 589 | * of a property in an object. This type of value stores a one-byte |
| | 590 | * prefix indicating the type of the value, and a four-byte area in |
| | 591 | * which the value is stored. The actual use of the four-byte value |
| | 592 | * area depends on the type. |
| | 593 | */ |
| | 594 | const size_t VMB_DATAHOLDER = 5; |
| | 595 | |
| | 596 | /* offset from a portable data holder pointer to the data value */ |
| | 597 | const size_t VMB_DH_DATAOFS = 1; |
| | 598 | |
| | 599 | /* store a portable dataholder from a vm_val_t */ |
| | 600 | void vmb_put_dh(char *buf, const vm_val_t *val); |
| | 601 | |
| | 602 | /* store a nil value in a portable dataholder */ |
| | 603 | inline void vmb_put_dh_nil(char *buf) { buf[0] = VM_NIL; } |
| | 604 | |
| | 605 | /* store an object value in a portable dataholder */ |
| | 606 | inline void vmb_put_dh_obj(char *buf, vm_obj_id_t obj) |
| | 607 | { buf[0] = VM_OBJ; vmb_put_objid(buf + 1, obj); } |
| | 608 | |
| | 609 | /* store a property value in a portable dataholder */ |
| | 610 | inline void vmb_put_dh_prop(char *buf, vm_prop_id_t prop) |
| | 611 | { buf[0] = VM_PROP; vmb_put_propid(buf + 1, prop); } |
| | 612 | |
| | 613 | /* get the value portion of a vm_val_t from a portable dataholder */ |
| | 614 | void vmb_get_dh_val(const char *buf, vm_val_t *val); |
| | 615 | |
| | 616 | /* get the type from a portable dataholder */ |
| | 617 | inline vm_datatype_t vmb_get_dh_type(const char *buf) |
| | 618 | { return (vm_datatype_t)buf[0]; } |
| | 619 | |
| | 620 | /* get a vm_val_t from a portable dataholder */ |
| | 621 | inline void vmb_get_dh(const char *buf, vm_val_t *val) |
| | 622 | { val->typ = vmb_get_dh_type(buf); vmb_get_dh_val(buf, val); } |
| | 623 | |
| | 624 | /* get an object value from a portable dataholder */ |
| | 625 | inline vm_obj_id_t vmb_get_dh_obj(const char *buf) |
| | 626 | { return (vm_obj_id_t)t3rp4u(buf+1); } |
| | 627 | |
| | 628 | /* get an integer value from a portable dataholder */ |
| | 629 | inline int32 vmb_get_dh_int(const char *buf) |
| | 630 | { return (int32)osrp4(buf+1); } |
| | 631 | |
| | 632 | /* get a property ID value from a portable dataholder */ |
| | 633 | inline vm_prop_id_t vmb_get_dh_prop(const char *buf) |
| | 634 | { return (vm_prop_id_t)osrp2(buf+1); } |
| | 635 | |
| | 636 | /* get a constant offset value from a portable dataholder */ |
| | 637 | inline pool_ofs_t vmb_get_dh_ofs(const char *buf) |
| | 638 | { return (pool_ofs_t)t3rp4u(buf+1); } |
| | 639 | |
| | 640 | |
| | 641 | #endif /* VMTYPE_H */ |
| | 642 | |