| /* |
| * Copyright 2012 Jacek Caban for CodeWeavers |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 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 |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #ifndef JSVAL_H |
| #define JSVAL_H |
| |
| #include "jsstr.h" |
| |
| /* |
| * jsval_t structure is used to represent JavaScript dynamically-typed values. |
| * It's a (type,value) pair, usually represented as a structure of enum (type) |
| * and union (value of given type). For both memory and speed performance, we |
| * use tricks allowing storing both values as a struct with size equal to |
| * size of double (that is 64-bit) on 32-bit systems. For that, we use the fact |
| * that NaN value representation has 52 (almost) free bits. |
| */ |
| |
| #ifdef __i386__ |
| #define JSVAL_DOUBLE_LAYOUT_PTR32 |
| #endif |
| |
| #ifdef JSVAL_DOUBLE_LAYOUT_PTR32 |
| /* NaN exponent and our 0x80000 marker */ |
| #define JSV_VAL(x) (0x7ff80000|x) |
| #else |
| #define JSV_VAL(x) x |
| #endif |
| |
| typedef enum { |
| JSV_UNDEFINED = JSV_VAL(1), |
| JSV_NULL = JSV_VAL(2), |
| JSV_OBJECT = JSV_VAL(3), |
| JSV_STRING = JSV_VAL(4), |
| JSV_NUMBER = JSV_VAL(5), |
| JSV_BOOL = JSV_VAL(6), |
| JSV_VARIANT = JSV_VAL(7) |
| } jsval_type_t; |
| |
| struct _jsval_t { |
| #ifdef JSVAL_DOUBLE_LAYOUT_PTR32 |
| union { |
| double n; |
| struct { |
| union { |
| IDispatch *obj; |
| jsstr_t *str; |
| BOOL b; |
| VARIANT *v; |
| UINT_PTR as_uintptr; |
| } u; |
| jsval_type_t tag; |
| } s; |
| } u; |
| #else |
| jsval_type_t type; |
| union { |
| IDispatch *obj; |
| jsstr_t *str; |
| double n; |
| BOOL b; |
| VARIANT *v; |
| } u; |
| #endif |
| }; |
| |
| #ifdef JSVAL_DOUBLE_LAYOUT_PTR32 |
| |
| C_ASSERT(sizeof(jsval_t) == sizeof(double)); |
| |
| #define __JSVAL_TYPE(x) ((x).u.s.tag) |
| #define __JSVAL_BOOL(x) ((x).u.s.u.b) |
| #define __JSVAL_STR(x) ((x).u.s.u.str) |
| #define __JSVAL_OBJ(x) ((x).u.s.u.obj) |
| #define __JSVAL_VAR(x) ((x).u.s.u.v) |
| |
| #else |
| |
| #define __JSVAL_TYPE(x) ((x).type) |
| #define __JSVAL_BOOL(x) ((x).u.b) |
| #define __JSVAL_STR(x) ((x).u.str) |
| #define __JSVAL_OBJ(x) ((x).u.obj) |
| #define __JSVAL_VAR(x) ((x).u.v) |
| |
| #endif |
| |
| static inline jsval_t jsval_bool(BOOL b) |
| { |
| jsval_t ret; |
| __JSVAL_TYPE(ret) = JSV_BOOL; |
| __JSVAL_BOOL(ret) = b; |
| return ret; |
| } |
| |
| static inline jsval_t jsval_string(jsstr_t *str) |
| { |
| jsval_t ret; |
| __JSVAL_TYPE(ret) = JSV_STRING; |
| __JSVAL_STR(ret) = str; |
| return ret; |
| } |
| |
| static inline jsval_t jsval_disp(IDispatch *obj) |
| { |
| jsval_t ret; |
| __JSVAL_TYPE(ret) = JSV_OBJECT; |
| __JSVAL_OBJ(ret) = obj; |
| return ret; |
| } |
| |
| static inline jsval_t jsval_obj(jsdisp_t *obj) |
| { |
| return jsval_disp(to_disp(obj)); |
| } |
| |
| static inline jsval_t jsval_null(void) |
| { |
| jsval_t ret; |
| __JSVAL_TYPE(ret) = JSV_NULL; |
| return ret; |
| } |
| |
| static inline jsval_t jsval_undefined(void) |
| { |
| jsval_t ret; |
| __JSVAL_TYPE(ret) = JSV_UNDEFINED; |
| return ret; |
| } |
| |
| static inline jsval_t jsval_number(double n) |
| { |
| jsval_t ret; |
| #ifdef JSVAL_DOUBLE_LAYOUT_PTR32 |
| ret.u.n = n; |
| /* normalize NaN value */ |
| if((ret.u.s.tag & 0x7ff00000) == 0x7ff00000) { |
| /* isinf */ |
| if(ret.u.s.tag & 0xfffff) { |
| ret.u.s.tag = 0x7ff00000; |
| ret.u.s.u.as_uintptr = ~0; |
| }else if(ret.u.s.u.as_uintptr) { |
| ret.u.s.tag = 0x7ff00000; |
| } |
| } |
| #else |
| ret.type = JSV_NUMBER; |
| ret.u.n = n; |
| #endif |
| return ret; |
| } |
| |
| static inline BOOL is_object_instance(jsval_t v) |
| { |
| return __JSVAL_TYPE(v) == JSV_OBJECT; |
| } |
| |
| static inline BOOL is_undefined(jsval_t v) |
| { |
| return __JSVAL_TYPE(v) == JSV_UNDEFINED; |
| } |
| |
| static inline BOOL is_null(jsval_t v) |
| { |
| return __JSVAL_TYPE(v) == JSV_NULL; |
| } |
| |
| static inline BOOL is_null_instance(jsval_t v) |
| { |
| return is_null(v) || (is_object_instance(v) && !__JSVAL_OBJ(v)); |
| } |
| |
| static inline BOOL is_string(jsval_t v) |
| { |
| return __JSVAL_TYPE(v) == JSV_STRING; |
| } |
| |
| static inline BOOL is_number(jsval_t v) |
| { |
| #ifdef JSVAL_DOUBLE_LAYOUT_PTR32 |
| return (v.u.s.tag & 0x7ff80000) != 0x7ff80000; |
| #else |
| return v.type == JSV_NUMBER; |
| #endif |
| } |
| |
| static inline BOOL is_variant(jsval_t v) |
| { |
| return __JSVAL_TYPE(v) == JSV_VARIANT; |
| } |
| |
| static inline BOOL is_bool(jsval_t v) |
| { |
| return __JSVAL_TYPE(v) == JSV_BOOL; |
| } |
| |
| static inline jsval_type_t jsval_type(jsval_t v) |
| { |
| #ifdef JSVAL_DOUBLE_LAYOUT_PTR32 |
| return is_number(v) ? JSV_NUMBER : v.u.s.tag; |
| #else |
| return v.type; |
| #endif |
| } |
| |
| static inline IDispatch *get_object(jsval_t v) |
| { |
| return __JSVAL_OBJ(v); |
| } |
| |
| static inline double get_number(jsval_t v) |
| { |
| return v.u.n; |
| } |
| |
| static inline jsstr_t *get_string(jsval_t v) |
| { |
| return __JSVAL_STR(v); |
| } |
| |
| static inline VARIANT *get_variant(jsval_t v) |
| { |
| return __JSVAL_VAR(v); |
| } |
| |
| static inline BOOL get_bool(jsval_t v) |
| { |
| return __JSVAL_BOOL(v); |
| } |
| |
| HRESULT variant_to_jsval(VARIANT*,jsval_t*) DECLSPEC_HIDDEN; |
| HRESULT jsval_to_variant(jsval_t,VARIANT*) DECLSPEC_HIDDEN; |
| void jsval_release(jsval_t) DECLSPEC_HIDDEN; |
| HRESULT jsval_copy(jsval_t,jsval_t*) DECLSPEC_HIDDEN; |
| |
| #endif |