[JSCRIPT]
authorAmine Khaldi <amine.khaldi@reactos.org>
Wed, 3 Apr 2013 21:19:50 +0000 (21:19 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Wed, 3 Apr 2013 21:19:50 +0000 (21:19 +0000)
* Sync with Wine 1.5.26.
CORE-7049

svn path=/trunk/; revision=58663

40 files changed:
reactos/dll/win32/jscript/CMakeLists.txt
reactos/dll/win32/jscript/activex.c
reactos/dll/win32/jscript/array.c
reactos/dll/win32/jscript/bool.c
reactos/dll/win32/jscript/compile.c [new file with mode: 0644]
reactos/dll/win32/jscript/date.c
reactos/dll/win32/jscript/decode.c [new file with mode: 0644]
reactos/dll/win32/jscript/dispex.c
reactos/dll/win32/jscript/engine.c
reactos/dll/win32/jscript/engine.h
reactos/dll/win32/jscript/error.c
reactos/dll/win32/jscript/function.c
reactos/dll/win32/jscript/global.c
reactos/dll/win32/jscript/jscript.c
reactos/dll/win32/jscript/jscript.h
reactos/dll/win32/jscript/jscript.inf [deleted file]
reactos/dll/win32/jscript/jscript.rc [new file with mode: 0644]
reactos/dll/win32/jscript/jscript.rgs [new file with mode: 0644]
reactos/dll/win32/jscript/jscript_classes.idl [new file with mode: 0644]
reactos/dll/win32/jscript/jscript_classes.rgs [new file with mode: 0644]
reactos/dll/win32/jscript/jscript_main.c
reactos/dll/win32/jscript/jsregexp.c [new file with mode: 0644]
reactos/dll/win32/jscript/jsstr.c [new file with mode: 0644]
reactos/dll/win32/jscript/jsstr.h [new file with mode: 0644]
reactos/dll/win32/jscript/jsutils.c
reactos/dll/win32/jscript/jsval.h [new file with mode: 0644]
reactos/dll/win32/jscript/lex.c
reactos/dll/win32/jscript/math.c
reactos/dll/win32/jscript/number.c
reactos/dll/win32/jscript/object.c
reactos/dll/win32/jscript/parser.tab.c
reactos/dll/win32/jscript/parser.tab.h
reactos/dll/win32/jscript/parser.y
reactos/dll/win32/jscript/regexp.c
reactos/dll/win32/jscript/regexp.h [new file with mode: 0644]
reactos/dll/win32/jscript/resource.h
reactos/dll/win32/jscript/rsrc.rc
reactos/dll/win32/jscript/string.c
reactos/dll/win32/jscript/vbarray.c [new file with mode: 0644]
reactos/media/doc/README.WINE

index 20c11eb..87899dd 100644 (file)
@@ -16,7 +16,9 @@ list(APPEND SOURCE
     activex.c
     array.c
     bool.c
+    compile.c
     date.c
+    decode.c
     dispex.c
     engine.c
     error.c
@@ -24,6 +26,8 @@ list(APPEND SOURCE
     global.c
     jscript.c
     jscript_main.c
+    jsregexp.c
+    jsstr.c
     jsutils.c
     lex.c
     math.c
@@ -32,15 +36,18 @@ list(APPEND SOURCE
     parser.tab.c
     regexp.c
     string.c
+    vbarray.c
     rsrc.rc
     ${CMAKE_CURRENT_BINARY_DIR}/jscript.def)
 
 add_library(jscript SHARED ${SOURCE})
+add_idl_headers(jscript_idlheader jscript_classes.idl)
+allow_warnings(jscript)
 set_module_type(jscript win32dll)
 target_link_libraries(jscript wine)
 add_importlibs(jscript user32 ole32 oleaut32 advapi32 msvcrt kernel32 ntdll)
 add_pch(jscript jscript.h)
 # jsglobal.tlb needs stdole2.tlb
-add_dependencies(jscript stdole2)
+add_dependencies(jscript jscript_idlheader stdole2)
 add_cd_file(TARGET jscript DESTINATION reactos/system32 FOR all)
 set_source_files_properties(rsrc.rc PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/jsglobal.tlb)
index 8ca24b7..b8e9a71 100644 (file)
@@ -58,7 +58,7 @@ static IInternetHostSecurityManager *get_sec_mgr(script_ctx_t *ctx)
 
 static IUnknown *create_activex_object(script_ctx_t *ctx, const WCHAR *progid)
 {
-    IInternetHostSecurityManager *secmgr;
+    IInternetHostSecurityManager *secmgr = NULL;
     IObjectWithSite *obj_site;
     struct CONFIRMSAFETY cs;
     IClassFactoryEx *cfex;
@@ -70,21 +70,25 @@ static IUnknown *create_activex_object(script_ctx_t *ctx, const WCHAR *progid)
     GUID guid;
     HRESULT hres;
 
+    TRACE("%s\n", debugstr_w(progid));
+
     hres = CLSIDFromProgID(progid, &guid);
     if(FAILED(hres))
         return NULL;
 
     TRACE("GUID %s\n", debugstr_guid(&guid));
 
-    secmgr = get_sec_mgr(ctx);
-    if(!secmgr)
-        return NULL;
+    if(ctx->safeopt & INTERFACE_USES_SECURITY_MANAGER) {
+        secmgr = get_sec_mgr(ctx);
+        if(!secmgr)
+            return NULL;
 
-    policy = 0;
-    hres = IInternetHostSecurityManager_ProcessUrlAction(secmgr, URLACTION_ACTIVEX_RUN, (BYTE*)&policy, sizeof(policy),
-            (BYTE*)&guid, sizeof(GUID), 0, 0);
-    if(FAILED(hres) || policy != URLPOLICY_ALLOW)
-        return NULL;
+        policy = 0;
+        hres = IInternetHostSecurityManager_ProcessUrlAction(secmgr, URLACTION_ACTIVEX_RUN,
+                (BYTE*)&policy, sizeof(policy), (BYTE*)&guid, sizeof(GUID), 0, 0);
+        if(FAILED(hres) || policy != URLPOLICY_ALLOW)
+            return NULL;
+    }
 
     hres = CoGetClassObject(&guid, CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, NULL, &IID_IClassFactory, (void**)&cf);
     if(FAILED(hres))
@@ -100,19 +104,21 @@ static IUnknown *create_activex_object(script_ctx_t *ctx, const WCHAR *progid)
     if(FAILED(hres))
         return NULL;
 
-    cs.clsid = guid;
-    cs.pUnk = obj;
-    cs.dwFlags = 0;
-    hres = IInternetHostSecurityManager_QueryCustomPolicy(secmgr, &GUID_CUSTOM_CONFIRMOBJECTSAFETY, &bpolicy, &policy_size,
-            (BYTE*)&cs, sizeof(cs), 0);
-    if(SUCCEEDED(hres)) {
-        policy = policy_size >= sizeof(DWORD) ? *(DWORD*)bpolicy : URLPOLICY_DISALLOW;
-        CoTaskMemFree(bpolicy);
-    }
+    if(secmgr) {
+        cs.clsid = guid;
+        cs.pUnk = obj;
+        cs.dwFlags = 0;
+        hres = IInternetHostSecurityManager_QueryCustomPolicy(secmgr, &GUID_CUSTOM_CONFIRMOBJECTSAFETY,
+                &bpolicy, &policy_size, (BYTE*)&cs, sizeof(cs), 0);
+        if(SUCCEEDED(hres)) {
+            policy = policy_size >= sizeof(DWORD) ? *(DWORD*)bpolicy : URLPOLICY_DISALLOW;
+            CoTaskMemFree(bpolicy);
+        }
 
-    if(FAILED(hres) || policy != URLPOLICY_ALLOW) {
-        IUnknown_Release(obj);
-        return NULL;
+        if(FAILED(hres) || policy != URLPOLICY_ALLOW) {
+            IUnknown_Release(obj);
+            return NULL;
+        }
     }
 
     hres = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void**)&obj_site);
@@ -126,7 +132,6 @@ static IUnknown *create_activex_object(script_ctx_t *ctx, const WCHAR *progid)
         }
         IObjectWithSite_Release(obj_site);
         if(!ax_site || FAILED(hres)) {
-            IObjectWithSite_Release(obj_site);
             IUnknown_Release(obj);
             return NULL;
         }
@@ -135,12 +140,12 @@ static IUnknown *create_activex_object(script_ctx_t *ctx, const WCHAR *progid)
     return obj;
 }
 
-static HRESULT ActiveXObject_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT ActiveXObject_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
+    jsstr_t * progid;
     IDispatch *disp;
     IUnknown *obj;
-    BSTR progid;
     HRESULT hres;
 
     TRACE("\n");
@@ -150,24 +155,25 @@ static HRESULT ActiveXObject_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag
         return E_NOTIMPL;
     }
 
-    if(ctx->safeopt != (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER)) {
+    if(ctx->safeopt != (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER)
+        && ctx->safeopt != INTERFACE_USES_DISPEX) {
         FIXME("Unsupported safeopt %x\n", ctx->safeopt);
         return E_NOTIMPL;
     }
 
-    if(arg_cnt(dp) != 1) {
-        FIXME("unsupported arg_cnt %d\n", arg_cnt(dp));
+    if(argc != 1) {
+        FIXME("unsupported argc %d\n", argc);
         return E_NOTIMPL;
     }
 
-    hres = to_string(ctx, get_arg(dp,0), ei, &progid);
+    hres = to_string(ctx, argv[0], &progid);
     if(FAILED(hres))
         return hres;
 
-    obj = create_activex_object(ctx, progid);
-    SysFreeString(progid);
+    obj = create_activex_object(ctx, progid->str);
+    jsstr_release(progid);
     if(!obj)
-        return throw_generic_error(ctx, ei, IDS_CREATE_OBJ_ERROR, NULL);
+        return throw_generic_error(ctx, JS_E_CANNOT_CREATE_OBJ, NULL);
 
     hres = IUnknown_QueryInterface(obj, &IID_IDispatch, (void**)&disp);
     IUnknown_Release(obj);
@@ -176,14 +182,13 @@ static HRESULT ActiveXObject_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag
         return E_NOTIMPL;
     }
 
-    V_VT(retv) = VT_DISPATCH;
-    V_DISPATCH(retv) = disp;
+    *r = jsval_disp(disp);
     return S_OK;
 }
 
-HRESULT create_activex_constr(script_ctx_t *ctx, DispatchEx **ret)
+HRESULT create_activex_constr(script_ctx_t *ctx, jsdisp_t **ret)
 {
-    DispatchEx *prototype;
+    jsdisp_t *prototype;
     HRESULT hres;
 
     static const WCHAR ActiveXObjectW[] = {'A','c','t','i','v','e','X','O','b','j','e','c','t',0};
index cad795e..09b1a01 100644 (file)
@@ -19,7 +19,7 @@
 #include <wine/config.h>
 #include <wine/port.h>
 
-//#include <math.h>
+#include <math.h>
 
 #include "jscript.h"
 
@@ -28,7 +28,7 @@
 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 
 typedef struct {
-    DispatchEx dispex;
+    jsdisp_t dispex;
 
     DWORD length;
 } ArrayInstance;
@@ -59,10 +59,10 @@ static inline ArrayInstance *array_this(vdisp_t *jsthis)
     return is_vclass(jsthis, JSCLASS_ARRAY) ? array_from_vdisp(jsthis) : NULL;
 }
 
-static HRESULT get_length(script_ctx_t *ctx, vdisp_t *vdisp, jsexcept_t *ei, DispatchEx **jsthis, DWORD *ret)
+static HRESULT get_length(script_ctx_t *ctx, vdisp_t *vdisp, jsdisp_t **jsthis, DWORD *ret)
 {
     ArrayInstance *array;
-    VARIANT var;
+    jsval_t val;
     HRESULT hres;
 
     array = array_this(vdisp);
@@ -73,14 +73,14 @@ static HRESULT get_length(script_ctx_t *ctx, vdisp_t *vdisp, jsexcept_t *ei, Dis
     }
 
     if(!is_jsdisp(vdisp))
-        return throw_type_error(ctx, ei, IDS_JSCRIPT_EXPECTED, NULL);
+        return throw_type_error(ctx, JS_E_JSCRIPT_EXPECTED, NULL);
 
-    hres = jsdisp_propget_name(vdisp->u.jsdisp, lengthW, &var, ei, NULL/*FIXME*/);
+    hres = jsdisp_propget_name(vdisp->u.jsdisp, lengthW, &val);
     if(FAILED(hres))
         return hres;
 
-    hres = to_uint32(ctx, &var, ei, ret);
-    VariantClear(&var);
+    hres = to_uint32(ctx, val, ret);
+    jsval_release(val);
     if(FAILED(hres))
         return hres;
 
@@ -88,18 +88,14 @@ static HRESULT get_length(script_ctx_t *ctx, vdisp_t *vdisp, jsexcept_t *ei, Dis
     return S_OK;
 }
 
-static HRESULT set_length(DispatchEx *obj, jsexcept_t *ei, DWORD length)
+static HRESULT set_length(jsdisp_t *obj, DWORD length)
 {
-    VARIANT var;
-
     if(is_class(obj, JSCLASS_ARRAY)) {
         ((ArrayInstance*)obj)->length = length;
         return S_OK;
     }
 
-    V_VT(&var) = VT_I4;
-    V_I4(&var) = length;
-    return jsdisp_propput_name(obj, lengthW, &var, ei, NULL/*FIXME*/);
+    return jsdisp_propput_name(obj, lengthW, jsval_number(length));
 }
 
 static WCHAR *idx_to_str(DWORD idx, WCHAR *ptr)
@@ -117,8 +113,8 @@ static WCHAR *idx_to_str(DWORD idx, WCHAR *ptr)
     return ptr+1;
 }
 
-static HRESULT Array_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Array_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     ArrayInstance *This = array_from_vdisp(jsthis);
 
@@ -126,23 +122,20 @@ static HRESULT Array_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
 
     switch(flags) {
     case DISPATCH_PROPERTYGET:
-        V_VT(retv) = VT_I4;
-        V_I4(retv) = This->length;
+        *r = jsval_number(This->length);
         break;
     case DISPATCH_PROPERTYPUT: {
-        VARIANT num;
         DOUBLE len = -1;
         DWORD i;
         HRESULT hres;
 
-        hres = to_number(ctx, get_arg(dp, 0), ei, &num);
-        if(V_VT(&num) == VT_I4)
-            len = V_I4(&num);
-        else
-            len = floor(V_R8(&num));
+        hres = to_number(ctx, argv[0], &len);
+        if(FAILED(hres))
+            return hres;
 
+        len = floor(len);
         if(len!=(DWORD)len)
-            return throw_range_error(ctx, ei, IDS_INVALID_LENGTH, NULL);
+            return throw_range_error(ctx, JS_E_INVALID_LENGTH, NULL);
 
         for(i=len; i<This->length; i++) {
             hres = jsdisp_delete_idx(&This->dispex, i);
@@ -161,22 +154,21 @@ static HRESULT Array_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
     return S_OK;
 }
 
-static HRESULT concat_array(DispatchEx *array, ArrayInstance *obj, DWORD *len,
-        jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT concat_array(jsdisp_t *array, ArrayInstance *obj, DWORD *len)
 {
-    VARIANT var;
+    jsval_t val;
     DWORD i;
     HRESULT hres;
 
     for(i=0; i < obj->length; i++) {
-        hres = jsdisp_get_idx(&obj->dispex, i, &var, ei, caller);
+        hres = jsdisp_get_idx(&obj->dispex, i, &val);
         if(hres == DISP_E_UNKNOWNNAME)
             continue;
         if(FAILED(hres))
             return hres;
 
-        hres = jsdisp_propput_idx(array, *len+i, &var, ei, caller);
-        VariantClear(&var);
+        hres = jsdisp_propput_idx(array, *len+i, val);
+        jsval_release(val);
         if(FAILED(hres))
             return hres;
     }
@@ -185,31 +177,28 @@ static HRESULT concat_array(DispatchEx *array, ArrayInstance *obj, DWORD *len,
     return S_OK;
 }
 
-static HRESULT concat_obj(DispatchEx *array, IDispatch *obj, DWORD *len, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT concat_obj(jsdisp_t *array, IDispatch *obj, DWORD *len)
 {
-    DispatchEx *jsobj;
-    VARIANT var;
+    jsdisp_t *jsobj;
     HRESULT hres;
 
     jsobj = iface_to_jsdisp((IUnknown*)obj);
     if(jsobj) {
         if(is_class(jsobj, JSCLASS_ARRAY)) {
-            hres = concat_array(array, (ArrayInstance*)jsobj, len, ei, caller);
+            hres = concat_array(array, (ArrayInstance*)jsobj, len);
             jsdisp_release(jsobj);
             return hres;
         }
         jsdisp_release(jsobj);
     }
 
-    V_VT(&var) = VT_DISPATCH;
-    V_DISPATCH(&var) = obj;
-    return jsdisp_propput_idx(array, (*len)++, &var, ei, caller);
+    return jsdisp_propput_idx(array, (*len)++, jsval_disp(obj));
 }
 
-static HRESULT Array_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Array_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *ret;
+    jsdisp_t *ret;
     DWORD len = 0;
     HRESULT hres;
 
@@ -219,17 +208,15 @@ static HRESULT Array_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
     if(FAILED(hres))
         return hres;
 
-    hres = concat_obj(ret, jsthis->u.disp, &len, ei, caller);
+    hres = concat_obj(ret, jsthis->u.disp, &len);
     if(SUCCEEDED(hres)) {
-        VARIANT *arg;
         DWORD i;
 
-        for(i=0; i < arg_cnt(dp); i++) {
-            arg = get_arg(dp, i);
-            if(V_VT(arg) == VT_DISPATCH)
-                hres = concat_obj(ret, V_DISPATCH(arg), &len, ei, caller);
+        for(i=0; i < argc; i++) {
+            if(is_object_instance(argv[i]))
+                hres = concat_obj(ret, get_object(argv[i]), &len);
             else
-                hres = jsdisp_propput_idx(ret, len++, arg, ei, caller);
+                hres = jsdisp_propput_idx(ret, len++, argv[i]);
             if(FAILED(hres))
                 break;
         }
@@ -238,50 +225,44 @@ static HRESULT Array_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
     if(FAILED(hres))
         return hres;
 
-    if(retv) {
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(ret);
-    }else {
+    if(r)
+        *r = jsval_obj(ret);
+    else
         jsdisp_release(ret);
-    }
     return S_OK;
 }
 
-static HRESULT array_join(script_ctx_t *ctx, DispatchEx *array, DWORD length, const WCHAR *sep, VARIANT *retv,
-        jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT array_join(script_ctx_t *ctx, jsdisp_t *array, DWORD length, const WCHAR *sep, jsval_t *r)
 {
-    BSTR *str_tab, ret = NULL;
-    VARIANT var;
+    jsstr_t **str_tab, *ret = NULL;
+    jsval_t val;
     DWORD i;
     HRESULT hres = E_FAIL;
 
     if(!length) {
-        if(retv) {
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = SysAllocStringLen(NULL, 0);
-            if(!V_BSTR(retv))
-                return E_OUTOFMEMORY;
-        }
+        if(r)
+            *r = jsval_string(jsstr_empty());
         return S_OK;
     }
 
-    str_tab = heap_alloc_zero(length * sizeof(BSTR));
+    str_tab = heap_alloc_zero(length * sizeof(*str_tab));
     if(!str_tab)
         return E_OUTOFMEMORY;
 
     for(i=0; i < length; i++) {
-        hres = jsdisp_get_idx(array, i, &var, ei, caller);
+        hres = jsdisp_get_idx(array, i, &val);
         if(hres == DISP_E_UNKNOWNNAME) {
             hres = S_OK;
             continue;
         } else if(FAILED(hres))
             break;
 
-        if(V_VT(&var) != VT_EMPTY && V_VT(&var) != VT_NULL)
-            hres = to_string(ctx, &var, ei, str_tab+i);
-        VariantClear(&var);
-        if(FAILED(hres))
-            break;
+        if(!is_undefined(val) && !is_null(val)) {
+            hres = to_string(ctx, val, str_tab+i);
+            jsval_release(val);
+            if(FAILED(hres))
+                break;
+        }
     }
 
     if(SUCCEEDED(hres)) {
@@ -291,314 +272,296 @@ static HRESULT array_join(script_ctx_t *ctx, DispatchEx *array, DWORD length, co
         seplen = strlenW(sep);
 
         if(str_tab[0])
-            len = SysStringLen(str_tab[0]);
-        for(i=1; i < length; i++)
-            len += seplen + SysStringLen(str_tab[i]);
+            len = jsstr_length(str_tab[0]);
+        for(i=1; i < length; i++) {
+            len += seplen;
+            if(str_tab[i])
+                len += jsstr_length(str_tab[i]);
+            if(len > JSSTR_MAX_LENGTH) {
+                hres = E_OUTOFMEMORY;
+                break;
+            }
+        }
 
-        ret = SysAllocStringLen(NULL, len);
+        if(SUCCEEDED(hres))
+            ret = jsstr_alloc_buf(len);
         if(ret) {
-            DWORD tmplen = 0;
+            ptr = ret->str;
 
-            if(str_tab[0]) {
-                tmplen = SysStringLen(str_tab[0]);
-                memcpy(ret, str_tab[0], tmplen*sizeof(WCHAR));
-            }
+            if(str_tab[0])
+                ptr += jsstr_flush(str_tab[0], ptr);
 
-            ptr = ret + tmplen;
             for(i=1; i < length; i++) {
                 if(seplen) {
                     memcpy(ptr, sep, seplen*sizeof(WCHAR));
                     ptr += seplen;
                 }
 
-                if(str_tab[i]) {
-                    tmplen = SysStringLen(str_tab[i]);
-                    memcpy(ptr, str_tab[i], tmplen*sizeof(WCHAR));
-                    ptr += tmplen;
-                }
+                if(str_tab[i])
+                    ptr += jsstr_flush(str_tab[i], ptr);
             }
-            *ptr=0;
         }else {
             hres = E_OUTOFMEMORY;
         }
     }
 
-    for(i=0; i < length; i++)
-        SysFreeString(str_tab[i]);
+    for(i=0; i < length; i++) {
+        if(str_tab[i])
+            jsstr_release(str_tab[i]);
+    }
     heap_free(str_tab);
     if(FAILED(hres))
         return hres;
 
-    TRACE("= %s\n", debugstr_w(ret));
-
-    if(retv) {
-        if(!ret) {
-            ret = SysAllocStringLen(NULL, 0);
-            if(!ret)
-                return E_OUTOFMEMORY;
-        }
-
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
-    }else {
-        SysFreeString(ret);
-    }
+    TRACE("= %s\n", debugstr_jsstr(ret));
 
+    if(r)
+        *r = jsval_string(ret);
+    else
+        jsstr_release(ret);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.4.4.5 */
-static HRESULT Array_join(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Array_join(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *jsthis;
+    jsdisp_t *jsthis;
     DWORD length;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    hres = get_length(ctx, vthis, &jsthis, &length);
     if(FAILED(hres))
         return hres;
 
-    if(arg_cnt(dp)) {
-        BSTR sep;
+    if(argc) {
+        jsstr_t *sep;
 
-        hres = to_string(ctx, get_arg(dp,0), ei, &sep);
+        hres = to_string(ctx, argv[0], &sep);
         if(FAILED(hres))
             return hres;
 
-        hres = array_join(ctx, jsthis, length, sep, retv, ei, caller);
+        hres = array_join(ctx, jsthis, length, sep->str, r);
 
-        SysFreeString(sep);
+        jsstr_release(sep);
     }else {
-        hres = array_join(ctx, jsthis, length, default_separatorW, retv, ei, caller);
+        hres = array_join(ctx, jsthis, length, default_separatorW, r);
     }
 
     return hres;
 }
 
-static HRESULT Array_pop(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Array_pop(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *jsthis;
-    VARIANT val;
+    jsdisp_t *jsthis;
+    jsval_t val;
     DWORD length;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    hres = get_length(ctx, vthis, &jsthis, &length);
     if(FAILED(hres))
         return hres;
 
     if(!length) {
-        hres = set_length(jsthis, ei, 0);
+        hres = set_length(jsthis, 0);
         if(FAILED(hres))
             return hres;
 
-        if(retv)
-            V_VT(retv) = VT_EMPTY;
+        if(r)
+            *r = jsval_undefined();
         return S_OK;
     }
 
     length--;
-    hres = jsdisp_get_idx(jsthis, length, &val, ei, caller);
-    if(SUCCEEDED(hres)) {
+    hres = jsdisp_get_idx(jsthis, length, &val);
+    if(SUCCEEDED(hres))
         hres = jsdisp_delete_idx(jsthis, length);
-    } else if(hres == DISP_E_UNKNOWNNAME) {
-        V_VT(&val) = VT_EMPTY;
-        hres = S_OK;
-    } else
+    else if(hres == DISP_E_UNKNOWNNAME)
+        val = jsval_undefined();
+    else
         return hres;
 
     if(SUCCEEDED(hres))
-        hres = set_length(jsthis, ei, length);
+        hres = set_length(jsthis, length);
 
     if(FAILED(hres)) {
-        VariantClear(&val);
+        jsval_release(val);
         return hres;
     }
 
-    if(retv)
-        *retv = val;
+    if(r)
+        *r = val;
     else
-        VariantClear(&val);
-
-    return S_OK;
+        jsval_release(val);
+    return hres;
 }
 
 /* ECMA-262 3rd Edition    15.4.4.7 */
-static HRESULT Array_push(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Array_push(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *jsthis;
+    jsdisp_t *jsthis;
     DWORD length = 0;
-    int i, n;
+    unsigned i;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    hres = get_length(ctx, vthis, &jsthis, &length);
     if(FAILED(hres))
         return hres;
 
-    n = arg_cnt(dp);
-    for(i=0; i < n; i++) {
-        hres = jsdisp_propput_idx(jsthis, length+i, get_arg(dp, i), ei, sp);
+    for(i=0; i < argc; i++) {
+        hres = jsdisp_propput_idx(jsthis, length+i, argv[i]);
         if(FAILED(hres))
             return hres;
     }
 
-    hres = set_length(jsthis, ei, length+n);
+    hres = set_length(jsthis, length+argc);
     if(FAILED(hres))
         return hres;
 
-    if(retv) {
-        V_VT(retv) = VT_I4;
-        V_I4(retv) = length+n;
-    }
+    if(r)
+        *r = jsval_number(length+argc);
     return S_OK;
 }
 
-static HRESULT Array_reverse(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Array_reverse(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *jsthis;
+    jsdisp_t *jsthis;
     DWORD length, k, l;
-    VARIANT v1, v2;
+    jsval_t v1, v2;
     HRESULT hres1, hres2;
 
     TRACE("\n");
 
-    hres1 = get_length(ctx, vthis, ei, &jsthis, &length);
+    hres1 = get_length(ctx, vthis, &jsthis, &length);
     if(FAILED(hres1))
         return hres1;
 
     for(k=0; k<length/2; k++) {
         l = length-k-1;
 
-        hres1 = jsdisp_get_idx(jsthis, k, &v1, ei, sp);
+        hres1 = jsdisp_get_idx(jsthis, k, &v1);
         if(FAILED(hres1) && hres1!=DISP_E_UNKNOWNNAME)
             return hres1;
 
-        hres2 = jsdisp_get_idx(jsthis, l, &v2, ei, sp);
+        hres2 = jsdisp_get_idx(jsthis, l, &v2);
         if(FAILED(hres2) && hres2!=DISP_E_UNKNOWNNAME) {
-            VariantClear(&v1);
+            jsval_release(v1);
             return hres2;
         }
 
         if(hres1 == DISP_E_UNKNOWNNAME)
             hres1 = jsdisp_delete_idx(jsthis, l);
         else
-            hres1 = jsdisp_propput_idx(jsthis, l, &v1, ei, sp);
+            hres1 = jsdisp_propput_idx(jsthis, l, v1);
 
         if(FAILED(hres1)) {
-            VariantClear(&v1);
-            VariantClear(&v2);
+            jsval_release(v1);
+            jsval_release(v2);
             return hres1;
         }
 
         if(hres2 == DISP_E_UNKNOWNNAME)
             hres2 = jsdisp_delete_idx(jsthis, k);
         else
-            hres2 = jsdisp_propput_idx(jsthis, k, &v2, ei, sp);
+            hres2 = jsdisp_propput_idx(jsthis, k, v2);
 
         if(FAILED(hres2)) {
-            VariantClear(&v2);
+            jsval_release(v2);
             return hres2;
         }
     }
 
-    if(retv) {
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(jsthis);
-        IDispatch_AddRef(V_DISPATCH(retv));
-    }
-
+    if(r)
+        *r = jsval_obj(jsdisp_addref(jsthis));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.4.4.9 */
-static HRESULT Array_shift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Array_shift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *jsthis;
+    jsdisp_t *jsthis;
     DWORD length = 0, i;
-    VARIANT v, ret;
+    jsval_t v, ret;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    hres = get_length(ctx, vthis, &jsthis, &length);
     if(FAILED(hres))
         return hres;
 
     if(!length) {
-        hres = set_length(jsthis, ei, 0);
+        hres = set_length(jsthis, 0);
         if(FAILED(hres))
             return hres;
     }
 
     if(!length) {
-        if(retv)
-            V_VT(retv) = VT_EMPTY;
+        if(r)
+            *r = jsval_undefined();
         return S_OK;
     }
 
-    hres = jsdisp_get_idx(jsthis, 0, &ret, ei, caller);
+    hres = jsdisp_get_idx(jsthis, 0, &ret);
     if(hres == DISP_E_UNKNOWNNAME) {
-        V_VT(&ret) = VT_EMPTY;
+        ret = jsval_undefined();
         hres = S_OK;
     }
 
     for(i=1; SUCCEEDED(hres) && i<length; i++) {
-        hres = jsdisp_get_idx(jsthis, i, &v, ei, caller);
+        hres = jsdisp_get_idx(jsthis, i, &v);
         if(hres == DISP_E_UNKNOWNNAME)
             hres = jsdisp_delete_idx(jsthis, i-1);
         else if(SUCCEEDED(hres))
-            hres = jsdisp_propput_idx(jsthis, i-1, &v, ei, caller);
+            hres = jsdisp_propput_idx(jsthis, i-1, v);
     }
 
     if(SUCCEEDED(hres)) {
         hres = jsdisp_delete_idx(jsthis, length-1);
         if(SUCCEEDED(hres))
-            hres = set_length(jsthis, ei, length-1);
+            hres = set_length(jsthis, length-1);
     }
 
-    if(SUCCEEDED(hres) && retv)
-        *retv = ret;
+    if(FAILED(hres))
+        return hres;
+
+    if(r)
+        *r = ret;
     else
-        VariantClear(&ret);
+        jsval_release(ret);
     return hres;
 }
 
 /* ECMA-262 3rd Edition    15.4.4.10 */
-static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
-    DispatchEx *arr, *jsthis;
-    VARIANT v;
+    jsdisp_t *arr, *jsthis;
     DOUBLE range;
     DWORD length, start, end, idx;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    hres = get_length(ctx, vthis, &jsthis, &length);
     if(FAILED(hres))
         return hres;
 
-    if(arg_cnt(dp)) {
-        hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    if(argc) {
+        hres = to_number(ctx, argv[0], &range);
         if(FAILED(hres))
             return hres;
 
-        if(V_VT(&v) == VT_I4)
-            range = V_I4(&v);
-        else
-            range = floor(V_R8(&v));
-
+        range = floor(range);
         if(-range>length || isnan(range)) start = 0;
         else if(range < 0) start = range+length;
         else if(range <= length) start = range;
@@ -606,16 +569,12 @@ static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPA
     }
     else start = 0;
 
-    if(arg_cnt(dp)>1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &v);
+    if(argc > 1) {
+        hres = to_number(ctx, argv[1], &range);
         if(FAILED(hres))
             return hres;
 
-        if(V_VT(&v) == VT_I4)
-            range = V_I4(&v);
-        else
-            range = floor(V_R8(&v));
-
+        range = floor(range);
         if(-range>length) end = 0;
         else if(range < 0) end = range+length;
         else if(range <= length) end = range;
@@ -628,13 +587,15 @@ static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPA
         return hres;
 
     for(idx=start; idx<end; idx++) {
-        hres = jsdisp_get_idx(jsthis, idx, &v, ei, sp);
+        jsval_t v;
+
+        hres = jsdisp_get_idx(jsthis, idx, &v);
         if(hres == DISP_E_UNKNOWNNAME)
             continue;
 
         if(SUCCEEDED(hres)) {
-            hres = jsdisp_propput_idx(arr, idx-start, &v, ei, sp);
-            VariantClear(&v);
+            hres = jsdisp_propput_idx(arr, idx-start, v);
+            jsval_release(v);
         }
 
         if(FAILED(hres)) {
@@ -643,66 +604,61 @@ static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPA
         }
     }
 
-    if(retv) {
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(arr);
-    }
+    if(r)
+        *r = jsval_obj(arr);
     else
         jsdisp_release(arr);
 
     return S_OK;
 }
 
-static HRESULT sort_cmp(script_ctx_t *ctx, DispatchEx *cmp_func, VARIANT *v1, VARIANT *v2, jsexcept_t *ei,
-        IServiceProvider *caller, INT *cmp)
+static HRESULT sort_cmp(script_ctx_t *ctx, jsdisp_t *cmp_func, jsval_t v1, jsval_t v2, INT *cmp)
 {
     HRESULT hres;
 
     if(cmp_func) {
-        VARIANTARG args[2];
-        DISPPARAMS dp = {args, NULL, 2, 0};
-        VARIANT tmp;
-        VARIANT res;
+        jsval_t args[2];
+        jsval_t res;
+        double n;
 
-        args[0] = *v2;
-        args[1] = *v1;
+        args[0] = v1;
+        args[1] = v2;
 
-        hres = jsdisp_call_value(cmp_func, DISPATCH_METHOD, &dp, &res, ei, caller);
+        hres = jsdisp_call_value(cmp_func, NULL, DISPATCH_METHOD, 2, args, &res);
         if(FAILED(hres))
             return hres;
 
-        hres = to_number(ctx, &res, ei, &tmp);
-        VariantClear(&res);
+        hres = to_number(ctx, res, &n);
+        jsval_release(res);
         if(FAILED(hres))
             return hres;
 
-        if(V_VT(&tmp) == VT_I4)
-            *cmp = V_I4(&tmp);
-        else
-            *cmp = V_R8(&tmp) > 0.0 ? 1 : -1;
-    }else if(V_VT(v1) == VT_EMPTY) {
-        *cmp = V_VT(v2) == VT_EMPTY ? 0 : 1;
-    }else if(V_VT(v2) == VT_EMPTY) {
+        if(n == 0)
+            *cmp = 0;
+        *cmp = n > 0.0 ? 1 : -1;
+    }else if(is_undefined(v1)) {
+        *cmp = is_undefined(v2) ? 0 : 1;
+    }else if(is_undefined(v2)) {
         *cmp = -1;
-    }else if(is_num_vt(V_VT(v1)) && is_num_vt(V_VT(v2))) {
-        DOUBLE d = num_val(v1)-num_val(v2);
+    }else if(is_number(v1) && is_number(v2)) {
+        double d = get_number(v1)-get_number(v2);
         if(d > 0.0)
             *cmp = 1;
         else
             *cmp = d < -0.0 ? -1 : 0;
     }else {
-        BSTR x, y;
+        jsstr_t *x, *y;
 
-        hres = to_string(ctx, v1, ei, &x);
+        hres = to_string(ctx, v1, &x);
         if(FAILED(hres))
             return hres;
 
-        hres = to_string(ctx, v2, ei, &y);
+        hres = to_string(ctx, v2, &y);
         if(SUCCEEDED(hres)) {
-            *cmp = strcmpW(x, y);
-            SysFreeString(y);
+            *cmp = jsstr_cmp(x, y);
+            jsstr_release(y);
         }
-        SysFreeString(x);
+        jsstr_release(x);
         if(FAILED(hres))
             return hres;
     }
@@ -711,36 +667,33 @@ static HRESULT sort_cmp(script_ctx_t *ctx, DispatchEx *cmp_func, VARIANT *v1, VA
 }
 
 /* ECMA-262 3rd Edition    15.4.4.11 */
-static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *jsthis, *cmp_func = NULL;
-    VARIANT *vtab, **sorttab = NULL;
+    jsdisp_t *jsthis, *cmp_func = NULL;
+    jsval_t *vtab, **sorttab = NULL;
     DWORD length;
     DWORD i;
     HRESULT hres = S_OK;
 
     TRACE("\n");
 
-    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    hres = get_length(ctx, vthis, &jsthis, &length);
     if(FAILED(hres))
         return hres;
 
-    if(arg_cnt(dp) > 1) {
-        WARN("invalid arg_cnt %d\n", arg_cnt(dp));
+    if(argc > 1) {
+        WARN("invalid arg_cnt %d\n", argc);
         return E_FAIL;
     }
 
-    if(arg_cnt(dp) == 1) {
-        VARIANT *arg = get_arg(dp, 0);
-
-        if(V_VT(arg) != VT_DISPATCH) {
+    if(argc == 1) {
+        if(!is_object_instance(argv[0])) {
             WARN("arg is not dispatch\n");
             return E_FAIL;
         }
 
-
-        cmp_func = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg));
+        cmp_func = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
         if(!cmp_func || !is_class(cmp_func, JSCLASS_FUNCTION)) {
             WARN("cmp_func is not a function\n");
             if(cmp_func)
@@ -752,20 +705,17 @@ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPAR
     if(!length) {
         if(cmp_func)
             jsdisp_release(cmp_func);
-        if(retv) {
-            V_VT(retv) = VT_DISPATCH;
-            V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(jsthis);
-           IDispatch_AddRef(V_DISPATCH(retv));
-        }
+        if(r)
+            *r = jsval_obj(jsdisp_addref(jsthis));
         return S_OK;
     }
 
-    vtab = heap_alloc_zero(length * sizeof(VARIANT));
+    vtab = heap_alloc_zero(length * sizeof(*vtab));
     if(vtab) {
         for(i=0; i<length; i++) {
-            hres = jsdisp_get_idx(jsthis, i, vtab+i, ei, caller);
+            hres = jsdisp_get_idx(jsthis, i, vtab+i);
             if(hres == DISP_E_UNKNOWNNAME) {
-                V_VT(vtab+i) = VT_EMPTY;
+                vtab[i] = jsval_undefined();
                 hres = S_OK;
             } else if(FAILED(hres)) {
                 WARN("Could not get elem %d: %08x\n", i, hres);
@@ -777,14 +727,14 @@ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPAR
     }
 
     if(SUCCEEDED(hres)) {
-        sorttab = heap_alloc(length*2*sizeof(VARIANT*));
+        sorttab = heap_alloc(length*2*sizeof(*sorttab));
         if(!sorttab)
             hres = E_OUTOFMEMORY;
     }
 
     /* merge-sort */
     if(SUCCEEDED(hres)) {
-        VARIANT *tmpv, **tmpbuf;
+        jsval_t *tmpv, **tmpbuf;
         INT cmp;
 
         tmpbuf = sorttab + length;
@@ -792,7 +742,7 @@ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPAR
             sorttab[i] = vtab+i;
 
         for(i=0; i < length/2; i++) {
-            hres = sort_cmp(ctx, cmp_func, sorttab[2*i+1], sorttab[2*i], ei, caller, &cmp);
+            hres = sort_cmp(ctx, cmp_func, *sorttab[2*i+1], *sorttab[2*i], &cmp);
             if(FAILED(hres))
                 break;
 
@@ -814,10 +764,10 @@ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPAR
                     else
                         bend = length - (i+k);
 
-                    memcpy(tmpbuf, sorttab+i, k*sizeof(VARIANT*));
+                    memcpy(tmpbuf, sorttab+i, k*sizeof(jsval_t*));
 
                     while(a < k && b < bend) {
-                        hres = sort_cmp(ctx, cmp_func, tmpbuf[a], sorttab[i+k+b], ei, caller, &cmp);
+                        hres = sort_cmp(ctx, cmp_func, *tmpbuf[a], *sorttab[i+k+b], &cmp);
                         if(FAILED(hres))
                             break;
 
@@ -834,7 +784,7 @@ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPAR
                         break;
 
                     if(a < k)
-                        memcpy(sorttab+i+a+b, tmpbuf+a, (k-a)*sizeof(VARIANT*));
+                        memcpy(sorttab+i+a+b, tmpbuf+a, (k-a)*sizeof(jsval_t*));
                 }
 
                 if(FAILED(hres))
@@ -843,12 +793,12 @@ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPAR
         }
 
         for(i=0; SUCCEEDED(hres) && i < length; i++)
-            hres = jsdisp_propput_idx(jsthis, i, sorttab[i], ei, caller);
+            hres = jsdisp_propput_idx(jsthis, i, *sorttab[i]);
     }
 
     if(vtab) {
         for(i=0; i < length; i++)
-            VariantClear(vtab+i);
+            jsval_release(vtab[i]);
         heap_free(vtab);
     }
     heap_free(sorttab);
@@ -858,111 +808,107 @@ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPAR
     if(FAILED(hres))
         return hres;
 
-    if(retv) {
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(jsthis);
-        IDispatch_AddRef(V_DISPATCH(retv));
-    }
-
+    if(r)
+        *r = jsval_obj(jsdisp_addref(jsthis));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.4.4.12 */
-static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DWORD length, start=0, delete_cnt=0, argc, i, add_args = 0;
-    DispatchEx *ret_array = NULL, *jsthis;
-    VARIANT v;
+    DWORD length, start=0, delete_cnt=0, i, add_args = 0;
+    jsdisp_t *ret_array = NULL, *jsthis;
+    jsval_t val;
+    double d;
+    int n;
     HRESULT hres = S_OK;
 
     TRACE("\n");
 
-    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    hres = get_length(ctx, vthis, &jsthis, &length);
     if(FAILED(hres))
         return hres;
 
-    argc = arg_cnt(dp);
-    if(argc >= 1) {
-        hres = to_integer(ctx, get_arg(dp,0), ei, &v);
+    if(argc) {
+        hres = to_integer(ctx, argv[0], &d);
         if(FAILED(hres))
             return hres;
 
-        if(V_VT(&v) == VT_I4) {
-            if(V_I4(&v) >= 0)
-                start = min(V_I4(&v), length);
+        if(is_int32(d)) {
+            if((n = d) >= 0)
+                start = min(n, length);
             else
-                start = -V_I4(&v) > length ? 0 : length + V_I4(&v);
+                start = -n > length ? 0 : length + n;
         }else {
-            start = V_R8(&v) < 0.0 ? 0 : length;
+            start = d < 0.0 ? 0 : length;
         }
     }
 
     if(argc >= 2) {
-        hres = to_integer(ctx, get_arg(dp,1), ei, &v);
+        hres = to_integer(ctx, argv[1], &d);
         if(FAILED(hres))
             return hres;
 
-        if(V_VT(&v) == VT_I4) {
-            if(V_I4(&v) > 0)
-                delete_cnt = min(V_I4(&v), length-start);
-        }else if(V_R8(&v) > 0.0) {
+        if(is_int32(d)) {
+            if((n = d) > 0)
+                delete_cnt = min(n, length-start);
+        }else if(d > 0.0) {
             delete_cnt = length-start;
         }
 
         add_args = argc-2;
     }
 
-    if(retv) {
+    if(r) {
         hres = create_array(ctx, 0, &ret_array);
         if(FAILED(hres))
             return hres;
 
         for(i=0; SUCCEEDED(hres) && i < delete_cnt; i++) {
-            hres = jsdisp_get_idx(jsthis, start+i, &v, ei, caller);
-            if(hres == DISP_E_UNKNOWNNAME)
+            hres = jsdisp_get_idx(jsthis, start+i, &val);
+            if(hres == DISP_E_UNKNOWNNAME) {
                 hres = S_OK;
-            else if(SUCCEEDED(hres))
-                hres = jsdisp_propput_idx(ret_array, i, &v, ei, caller);
+            }else if(SUCCEEDED(hres)) {
+                hres = jsdisp_propput_idx(ret_array, i, val);
+                jsval_release(val);
+            }
         }
 
-        if(SUCCEEDED(hres)) {
-            V_VT(&v) = VT_I4;
-            V_I4(&v) = delete_cnt;
-
-            hres = jsdisp_propput_name(ret_array, lengthW, &v, ei, caller);
-        }
+        if(SUCCEEDED(hres))
+            hres = jsdisp_propput_name(ret_array, lengthW, jsval_number(delete_cnt));
     }
 
     if(add_args < delete_cnt) {
         for(i = start; SUCCEEDED(hres) && i < length-delete_cnt; i++) {
-            hres = jsdisp_get_idx(jsthis, i+delete_cnt, &v, ei, caller);
-            if(hres == DISP_E_UNKNOWNNAME)
+            hres = jsdisp_get_idx(jsthis, i+delete_cnt, &val);
+            if(hres == DISP_E_UNKNOWNNAME) {
                 hres = jsdisp_delete_idx(jsthis, i+add_args);
-            else if(SUCCEEDED(hres))
-                hres = jsdisp_propput_idx(jsthis, i+add_args, &v, ei, caller);
+            }else if(SUCCEEDED(hres)) {
+                hres = jsdisp_propput_idx(jsthis, i+add_args, val);
+                jsval_release(val);
+            }
         }
 
         for(i=length; SUCCEEDED(hres) && i != length-delete_cnt+add_args; i--)
             hres = jsdisp_delete_idx(jsthis, i-1);
     }else if(add_args > delete_cnt) {
         for(i=length-delete_cnt; SUCCEEDED(hres) && i != start; i--) {
-            hres = jsdisp_get_idx(jsthis, i+delete_cnt-1, &v, ei, caller);
-            if(hres == DISP_E_UNKNOWNNAME)
+            hres = jsdisp_get_idx(jsthis, i+delete_cnt-1, &val);
+            if(hres == DISP_E_UNKNOWNNAME) {
                 hres = jsdisp_delete_idx(jsthis, i+add_args-1);
-            else if(SUCCEEDED(hres))
-                hres = jsdisp_propput_idx(jsthis, i+add_args-1, &v, ei, caller);
+            }else if(SUCCEEDED(hres)) {
+                hres = jsdisp_propput_idx(jsthis, i+add_args-1, val);
+                jsval_release(val);
+            }
         }
     }
 
     for(i=0; SUCCEEDED(hres) && i < add_args; i++)
-        hres = jsdisp_propput_idx(jsthis, start+i, get_arg(dp,i+2), ei, caller);
+        hres = jsdisp_propput_idx(jsthis, start+i, argv[i+2]);
 
-    if(SUCCEEDED(hres)) {
-        V_VT(&v) = VT_I4;
-        V_I4(&v) = length-delete_cnt+add_args;
-        hres = jsdisp_propput_name(jsthis, lengthW, &v, ei, caller);
-    }
+    if(SUCCEEDED(hres))
+        hres = jsdisp_propput_name(jsthis, lengthW, jsval_number(length-delete_cnt+add_args));
 
     if(FAILED(hres)) {
         if(ret_array)
@@ -970,16 +916,14 @@ static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPP
         return hres;
     }
 
-    if(retv) {
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(ret_array);
-    }
+    if(r)
+        *r = jsval_obj(ret_array);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.4.4.2 */
-static HRESULT Array_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Array_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     ArrayInstance *array;
 
@@ -987,36 +931,35 @@ static HRESULT Array_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DI
 
     array = array_this(jsthis);
     if(!array)
-        return throw_type_error(ctx, ei, IDS_ARRAY_EXPECTED, NULL);
+        return throw_type_error(ctx, JS_E_ARRAY_EXPECTED, NULL);
 
-    return array_join(ctx, &array->dispex, array->length, default_separatorW, retv, ei, sp);
+    return array_join(ctx, &array->dispex, array->length, default_separatorW, r);
 }
 
-static HRESULT Array_toLocaleString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Array_toLocaleString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
 /* ECMA-262 3rd Edition    15.4.4.13 */
-static HRESULT Array_unshift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Array_unshift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *jsthis;
+    jsdisp_t *jsthis;
     WCHAR buf[14], *buf_end, *str;
-    DWORD argc, i, length;
-    VARIANT var;
+    DWORD i, length;
+    jsval_t val;
     DISPID id;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_length(ctx, vthis, ei, &jsthis, &length);
+    hres = get_length(ctx, vthis, &jsthis, &length);
     if(FAILED(hres))
         return hres;
 
-    argc = arg_cnt(dp);
     if(argc) {
         buf_end = buf + sizeof(buf)/sizeof(WCHAR)-1;
         *buf_end-- = 0;
@@ -1027,12 +970,12 @@ static HRESULT Array_unshift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISP
 
             hres = jsdisp_get_id(jsthis, str, 0, &id);
             if(SUCCEEDED(hres)) {
-                hres = jsdisp_propget(jsthis, id, &var, ei, caller);
+                hres = jsdisp_propget(jsthis, id, &val);
                 if(FAILED(hres))
                     return hres;
 
-                hres = jsdisp_propput_idx(jsthis, i+argc, &var, ei, caller);
-                VariantClear(&var);
+                hres = jsdisp_propput_idx(jsthis, i+argc, val);
+                jsval_release(val);
             }else if(hres == DISP_E_UNKNOWNNAME) {
                 hres = IDispatchEx_DeleteMemberByDispID(vthis->u.dispex, id);
             }
@@ -1043,39 +986,33 @@ static HRESULT Array_unshift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISP
     }
 
     for(i=0; i<argc; i++) {
-        hres = jsdisp_propput_idx(jsthis, i, get_arg(dp,i), ei, caller);
+        hres = jsdisp_propput_idx(jsthis, i, argv[i]);
         if(FAILED(hres))
             return hres;
     }
 
     if(argc) {
         length += argc;
-        hres = set_length(jsthis, ei, length);
+        hres = set_length(jsthis, length);
         if(FAILED(hres))
             return hres;
     }
 
-    if(retv) {
-        if(ctx->version < 2) {
-            V_VT(retv) = VT_EMPTY;
-        }else {
-            V_VT(retv) = VT_I4;
-            V_I4(retv) = length;
-        }
-    }
+    if(r)
+        *r = ctx->version < 2 ? jsval_undefined() : jsval_number(length);
     return S_OK;
 }
 
-static HRESULT Array_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Array_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
     switch(flags) {
     case INVOKE_FUNC:
-        return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
+        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
     case INVOKE_PROPERTYGET:
-        return array_join(ctx, jsthis->u.jsdisp, array_from_vdisp(jsthis)->length, default_separatorW, retv, ei, sp);
+        return array_join(ctx, jsthis->u.jsdisp, array_from_vdisp(jsthis)->length, default_separatorW, r);
     default:
         FIXME("unimplemented flags %x\n", flags);
         return E_NOTIMPL;
@@ -1084,12 +1021,12 @@ static HRESULT Array_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPP
     return S_OK;
 }
 
-static void Array_destructor(DispatchEx *dispex)
+static void Array_destructor(jsdisp_t *dispex)
 {
     heap_free(dispex);
 }
 
-static void Array_on_put(DispatchEx *dispex, const WCHAR *name)
+static void Array_on_put(jsdisp_t *dispex, const WCHAR *name)
 {
     ArrayInstance *array = (ArrayInstance*)dispex;
     const WCHAR *ptr = name;
@@ -1135,11 +1072,23 @@ static const builtin_info_t Array_info = {
     Array_on_put
 };
 
-static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static const builtin_prop_t ArrayInst_props[] = {
+    {lengthW,                Array_length,               0}
+};
+
+static const builtin_info_t ArrayInst_info = {
+    JSCLASS_ARRAY,
+    {NULL, Array_value, 0},
+    sizeof(ArrayInst_props)/sizeof(*ArrayInst_props),
+    ArrayInst_props,
+    Array_destructor,
+    Array_on_put
+};
+
+static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *obj;
-    VARIANT *arg_var;
+    jsdisp_t *obj;
     DWORD i;
     HRESULT hres;
 
@@ -1148,25 +1097,26 @@ static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags,
     switch(flags) {
     case DISPATCH_METHOD:
     case DISPATCH_CONSTRUCT: {
-        if(arg_cnt(dp) == 1 && V_VT((arg_var = get_arg(dp, 0))) == VT_I4) {
-            if(V_I4(arg_var) < 0)
-                return throw_range_error(ctx, ei, IDS_INVALID_LENGTH, NULL);
+        if(argc == 1 && is_number(argv[0])) {
+            double n = get_number(argv[0]);
+
+            if(n < 0 || !is_int32(n))
+                return throw_range_error(ctx, JS_E_INVALID_LENGTH, NULL);
 
-            hres = create_array(ctx, V_I4(arg_var), &obj);
+            hres = create_array(ctx, n, &obj);
             if(FAILED(hres))
                 return hres;
 
-            V_VT(retv) = VT_DISPATCH;
-            V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(obj);
+            *r = jsval_obj(obj);
             return S_OK;
         }
 
-        hres = create_array(ctx, arg_cnt(dp), &obj);
+        hres = create_array(ctx, argc, &obj);
         if(FAILED(hres))
             return hres;
 
-        for(i=0; i < arg_cnt(dp); i++) {
-            hres = jsdisp_propput_idx(obj, i, get_arg(dp, i), ei, caller);
+        for(i=0; i < argc; i++) {
+            hres = jsdisp_propput_idx(obj, i, argv[i]);
             if(FAILED(hres))
                 break;
         }
@@ -1175,8 +1125,7 @@ static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags,
             return hres;
         }
 
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(obj);
+        *r = jsval_obj(obj);
         break;
     }
     default:
@@ -1187,7 +1136,7 @@ static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags,
     return S_OK;
 }
 
-static HRESULT alloc_array(script_ctx_t *ctx, DispatchEx *object_prototype, ArrayInstance **ret)
+static HRESULT alloc_array(script_ctx_t *ctx, jsdisp_t *object_prototype, ArrayInstance **ret)
 {
     ArrayInstance *array;
     HRESULT hres;
@@ -1199,7 +1148,7 @@ static HRESULT alloc_array(script_ctx_t *ctx, DispatchEx *object_prototype, Arra
     if(object_prototype)
         hres = init_dispex(&array->dispex, ctx, &Array_info, object_prototype);
     else
-        hres = init_dispex_from_constr(&array->dispex, ctx, &Array_info, ctx->array_constr);
+        hres = init_dispex_from_constr(&array->dispex, ctx, &ArrayInst_info, ctx->array_constr);
 
     if(FAILED(hres)) {
         heap_free(array);
@@ -1210,7 +1159,7 @@ static HRESULT alloc_array(script_ctx_t *ctx, DispatchEx *object_prototype, Arra
     return S_OK;
 }
 
-HRESULT create_array_constr(script_ctx_t *ctx, DispatchEx *object_prototype, DispatchEx **ret)
+HRESULT create_array_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
 {
     ArrayInstance *array;
     HRESULT hres;
@@ -1221,13 +1170,13 @@ HRESULT create_array_constr(script_ctx_t *ctx, DispatchEx *object_prototype, Dis
     if(FAILED(hres))
         return hres;
 
-    hres = create_builtin_function(ctx, ArrayConstr_value, ArrayW, NULL, PROPF_CONSTR|1, &array->dispex, ret);
+    hres = create_builtin_constructor(ctx, ArrayConstr_value, ArrayW, NULL, PROPF_CONSTR|1, &array->dispex, ret);
 
     jsdisp_release(&array->dispex);
     return hres;
 }
 
-HRESULT create_array(script_ctx_t *ctx, DWORD length, DispatchEx **ret)
+HRESULT create_array(script_ctx_t *ctx, DWORD length, jsdisp_t **ret)
 {
     ArrayInstance *array;
     HRESULT hres;
index 5d3aea2..2a96b6c 100644 (file)
@@ -24,9 +24,9 @@
 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 
 typedef struct {
-    DispatchEx dispex;
+    jsdisp_t dispex;
 
-    VARIANT_BOOL val;
+    BOOL val;
 } BoolInstance;
 
 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
@@ -38,8 +38,7 @@ static inline BoolInstance *bool_this(vdisp_t *jsthis)
 }
 
 /* ECMA-262 3rd Edition    15.6.4.2 */
-static HRESULT Bool_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Bool_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
     BoolInstance *bool;
 
@@ -49,51 +48,44 @@ static HRESULT Bool_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DIS
     TRACE("\n");
 
     if(!(bool = bool_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_BOOL, NULL);
+        return throw_type_error(ctx, JS_E_BOOLEAN_EXPECTED, NULL);
 
-    if(retv) {
-        BSTR val;
-
-        if(bool->val) val = SysAllocString(trueW);
-        else val = SysAllocString(falseW);
+    if(r) {
+        jsstr_t *val;
 
+        val = jsstr_alloc(bool->val ? trueW : falseW);
         if(!val)
             return E_OUTOFMEMORY;
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = val;
+        *r = jsval_string(val);
     }
 
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.6.4.3 */
-static HRESULT Bool_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Bool_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
     BoolInstance *bool;
 
     TRACE("\n");
 
     if(!(bool = bool_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_BOOL, NULL);
-
-    if(retv) {
-        V_VT(retv) = VT_BOOL;
-        V_BOOL(retv) = bool->val;
-    }
+        return throw_type_error(ctx, JS_E_BOOLEAN_EXPECTED, NULL);
 
+    if(r)
+        *r = jsval_bool(bool->val);
     return S_OK;
 }
 
-static HRESULT Bool_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Bool_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
     switch(flags) {
     case INVOKE_FUNC:
-        return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
+        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
     default:
         FIXME("unimplemented flags %x\n", flags);
         return E_NOTIMPL;
@@ -117,36 +109,41 @@ static const builtin_info_t Bool_info = {
     NULL
 };
 
-static HRESULT BoolConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static const builtin_info_t BoolInst_info = {
+    JSCLASS_BOOLEAN,
+    {NULL, Bool_value, 0},
+    0, NULL,
+    NULL,
+    NULL
+};
+
+static HRESULT BoolConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
+    BOOL value = FALSE;
     HRESULT hres;
-    VARIANT_BOOL value = VARIANT_FALSE;
 
-    if(arg_cnt(dp)) {
-        hres = to_boolean(get_arg(dp,0), &value);
+    if(argc) {
+        hres = to_boolean(argv[0], &value);
         if(FAILED(hres))
             return hres;
     }
 
     switch(flags) {
     case DISPATCH_CONSTRUCT: {
-        DispatchEx *bool;
+        jsdisp_t *bool;
 
         hres = create_bool(ctx, value, &bool);
         if(FAILED(hres))
             return hres;
 
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(bool);
+        *r = jsval_obj(bool);
         return S_OK;
     }
 
     case INVOKE_FUNC:
-        if(retv) {
-            V_VT(retv) = VT_BOOL;
-            V_BOOL(retv) = value;
-        }
+        if(r)
+            *r = jsval_bool(value);
         return S_OK;
 
     default:
@@ -157,7 +154,7 @@ static HRESULT BoolConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
     return S_OK;
 }
 
-static HRESULT alloc_bool(script_ctx_t *ctx, DispatchEx *object_prototype, BoolInstance **ret)
+static HRESULT alloc_bool(script_ctx_t *ctx, jsdisp_t *object_prototype, BoolInstance **ret)
 {
     BoolInstance *bool;
     HRESULT hres;
@@ -169,7 +166,7 @@ static HRESULT alloc_bool(script_ctx_t *ctx, DispatchEx *object_prototype, BoolI
     if(object_prototype)
         hres = init_dispex(&bool->dispex, ctx, &Bool_info, object_prototype);
     else
-        hres = init_dispex_from_constr(&bool->dispex, ctx, &Bool_info, ctx->bool_constr);
+        hres = init_dispex_from_constr(&bool->dispex, ctx, &BoolInst_info, ctx->bool_constr);
 
     if(FAILED(hres)) {
         heap_free(bool);
@@ -180,7 +177,7 @@ static HRESULT alloc_bool(script_ctx_t *ctx, DispatchEx *object_prototype, BoolI
     return S_OK;
 }
 
-HRESULT create_bool_constr(script_ctx_t *ctx, DispatchEx *object_prototype, DispatchEx **ret)
+HRESULT create_bool_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
 {
     BoolInstance *bool;
     HRESULT hres;
@@ -191,14 +188,14 @@ HRESULT create_bool_constr(script_ctx_t *ctx, DispatchEx *object_prototype, Disp
     if(FAILED(hres))
         return hres;
 
-    hres = create_builtin_function(ctx, BoolConstr_value, BooleanW, NULL,
+    hres = create_builtin_constructor(ctx, BoolConstr_value, BooleanW, NULL,
             PROPF_CONSTR|1, &bool->dispex, ret);
 
     jsdisp_release(&bool->dispex);
     return hres;
 }
 
-HRESULT create_bool(script_ctx_t *ctx, VARIANT_BOOL b, DispatchEx **ret)
+HRESULT create_bool(script_ctx_t *ctx, BOOL b, jsdisp_t **ret)
 {
     BoolInstance *bool;
     HRESULT hres;
diff --git a/reactos/dll/win32/jscript/compile.c b/reactos/dll/win32/jscript/compile.c
new file mode 100644 (file)
index 0000000..10bed1c
--- /dev/null
@@ -0,0 +1,2029 @@
+/*
+ * Copyright 2011 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
+ */
+
+#include <math.h>
+#include <assert.h>
+
+#include "jscript.h"
+#include "engine.h"
+
+#include <wine/debug.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(jscript);
+WINE_DECLARE_DEBUG_CHANNEL(jscript_disas);
+
+typedef struct _statement_ctx_t {
+    unsigned stack_use;
+    BOOL using_scope;
+    BOOL using_except;
+
+    unsigned break_label;
+    unsigned continue_label;
+
+    const labelled_statement_t *labelled_stat;
+
+    struct _statement_ctx_t *next;
+} statement_ctx_t;
+
+typedef struct {
+    parser_ctx_t *parser;
+    bytecode_t *code;
+
+    BOOL from_eval;
+
+    unsigned code_off;
+    unsigned code_size;
+
+    unsigned *labels;
+    unsigned labels_size;
+    unsigned labels_cnt;
+
+    statement_ctx_t *stat_ctx;
+    function_code_t *func;
+
+    variable_declaration_t *var_head;
+    variable_declaration_t *var_tail;
+
+    function_expression_t *func_head;
+    function_expression_t *func_tail;
+} compiler_ctx_t;
+
+static const struct {
+    const char *op_str;
+    instr_arg_type_t arg1_type;
+    instr_arg_type_t arg2_type;
+} instr_info[] = {
+#define X(n,a,b,c) {#n,b,c},
+OP_LIST
+#undef X
+};
+
+static void dump_instr_arg(instr_arg_type_t type, instr_arg_t *arg)
+{
+    switch(type) {
+    case ARG_STR:
+        TRACE_(jscript_disas)("\t%s", debugstr_jsstr(arg->str));
+        break;
+    case ARG_BSTR:
+        TRACE_(jscript_disas)("\t%s", debugstr_wn(arg->bstr, SysStringLen(arg->bstr)));
+        break;
+    case ARG_INT:
+        TRACE_(jscript_disas)("\t%d", arg->uint);
+        break;
+    case ARG_UINT:
+    case ARG_ADDR:
+        TRACE_(jscript_disas)("\t%u", arg->uint);
+        break;
+    case ARG_FUNC:
+    case ARG_NONE:
+        break;
+    DEFAULT_UNREACHABLE;
+    }
+}
+
+static void dump_code(compiler_ctx_t *ctx, unsigned off)
+{
+    instr_t *instr;
+
+    for(instr = ctx->code->instrs+off; instr < ctx->code->instrs+ctx->code_off; instr++) {
+        TRACE_(jscript_disas)("%d:\t%s", (int)(instr-ctx->code->instrs), instr_info[instr->op].op_str);
+        if(instr_info[instr->op].arg1_type == ARG_DBL) {
+            TRACE_(jscript_disas)("\t%lf", instr->u.dbl);
+        }else {
+            dump_instr_arg(instr_info[instr->op].arg1_type, instr->u.arg);
+            dump_instr_arg(instr_info[instr->op].arg2_type, instr->u.arg+1);
+        }
+        TRACE_(jscript_disas)("\n");
+    }
+}
+
+static HRESULT compile_expression(compiler_ctx_t*,expression_t*,BOOL);
+static HRESULT compile_statement(compiler_ctx_t*,statement_ctx_t*,statement_t*);
+
+static inline void *compiler_alloc(bytecode_t *code, size_t size)
+{
+    return heap_pool_alloc(&code->heap, size);
+}
+
+static jsstr_t *compiler_alloc_string_len(compiler_ctx_t *ctx, const WCHAR *str, unsigned len)
+{
+    jsstr_t *new_str;
+
+    if(!ctx->code->str_pool_size) {
+        ctx->code->str_pool = heap_alloc(8 * sizeof(jsstr_t*));
+        if(!ctx->code->str_pool)
+            return NULL;
+        ctx->code->str_pool_size = 8;
+    }else if(ctx->code->str_pool_size == ctx->code->str_cnt) {
+        jsstr_t **new_pool;
+
+        new_pool = heap_realloc(ctx->code->str_pool, ctx->code->str_pool_size*2*sizeof(jsstr_t*));
+        if(!new_pool)
+            return NULL;
+
+        ctx->code->str_pool = new_pool;
+        ctx->code->str_pool_size *= 2;
+    }
+
+    new_str = jsstr_alloc_len(str, len);
+    if(!new_str)
+        return NULL;
+
+    ctx->code->str_pool[ctx->code->str_cnt++] = new_str;
+    return new_str;
+}
+
+static jsstr_t *compiler_alloc_string(compiler_ctx_t *ctx, const WCHAR *str)
+{
+    return compiler_alloc_string_len(ctx, str, strlenW(str));
+}
+
+static BOOL ensure_bstr_slot(compiler_ctx_t *ctx)
+{
+    if(!ctx->code->bstr_pool_size) {
+        ctx->code->bstr_pool = heap_alloc(8 * sizeof(BSTR));
+        if(!ctx->code->bstr_pool)
+            return FALSE;
+        ctx->code->bstr_pool_size = 8;
+    }else if(ctx->code->bstr_pool_size == ctx->code->bstr_cnt) {
+        BSTR *new_pool;
+
+        new_pool = heap_realloc(ctx->code->bstr_pool, ctx->code->bstr_pool_size*2*sizeof(BSTR));
+        if(!new_pool)
+            return FALSE;
+
+        ctx->code->bstr_pool = new_pool;
+        ctx->code->bstr_pool_size *= 2;
+    }
+
+    return TRUE;
+}
+
+static BSTR compiler_alloc_bstr(compiler_ctx_t *ctx, const WCHAR *str)
+{
+    if(!ensure_bstr_slot(ctx))
+        return NULL;
+
+    ctx->code->bstr_pool[ctx->code->bstr_cnt] = SysAllocString(str);
+    if(!ctx->code->bstr_pool[ctx->code->bstr_cnt])
+        return NULL;
+
+    return ctx->code->bstr_pool[ctx->code->bstr_cnt++];
+}
+
+static BSTR compiler_alloc_bstr_len(compiler_ctx_t *ctx, const WCHAR *str, size_t len)
+{
+    if(!ensure_bstr_slot(ctx))
+        return NULL;
+
+    ctx->code->bstr_pool[ctx->code->bstr_cnt] = SysAllocStringLen(str, len);
+    if(!ctx->code->bstr_pool[ctx->code->bstr_cnt])
+        return NULL;
+
+    return ctx->code->bstr_pool[ctx->code->bstr_cnt++];
+}
+
+static unsigned push_instr(compiler_ctx_t *ctx, jsop_t op)
+{
+    assert(ctx->code_size >= ctx->code_off);
+
+    if(ctx->code_size == ctx->code_off) {
+        instr_t *new_instrs;
+
+        new_instrs = heap_realloc(ctx->code->instrs, ctx->code_size*2*sizeof(instr_t));
+        if(!new_instrs)
+            return 0;
+
+        ctx->code->instrs = new_instrs;
+        ctx->code_size *= 2;
+    }
+
+    ctx->code->instrs[ctx->code_off].op = op;
+    return ctx->code_off++;
+}
+
+static inline instr_t *instr_ptr(compiler_ctx_t *ctx, unsigned off)
+{
+    assert(off < ctx->code_off);
+    return ctx->code->instrs + off;
+}
+
+static HRESULT push_instr_int(compiler_ctx_t *ctx, jsop_t op, LONG arg)
+{
+    unsigned instr;
+
+    instr = push_instr(ctx, op);
+    if(!instr)
+        return E_OUTOFMEMORY;
+
+    instr_ptr(ctx, instr)->u.arg->lng = arg;
+    return S_OK;
+}
+
+static HRESULT push_instr_str(compiler_ctx_t *ctx, jsop_t op, const WCHAR *arg)
+{
+    unsigned instr;
+    jsstr_t *str;
+
+    str = compiler_alloc_string(ctx, arg);
+    if(!str)
+        return E_OUTOFMEMORY;
+
+    instr = push_instr(ctx, op);
+    if(!instr)
+        return E_OUTOFMEMORY;
+
+    instr_ptr(ctx, instr)->u.arg->str = str;
+    return S_OK;
+}
+
+static HRESULT push_instr_bstr(compiler_ctx_t *ctx, jsop_t op, const WCHAR *arg)
+{
+    unsigned instr;
+    WCHAR *str;
+
+    str = compiler_alloc_bstr(ctx, arg);
+    if(!str)
+        return E_OUTOFMEMORY;
+
+    instr = push_instr(ctx, op);
+    if(!instr)
+        return E_OUTOFMEMORY;
+
+    instr_ptr(ctx, instr)->u.arg->bstr = str;
+    return S_OK;
+}
+
+static HRESULT push_instr_bstr_uint(compiler_ctx_t *ctx, jsop_t op, const WCHAR *arg1, unsigned arg2)
+{
+    unsigned instr;
+    WCHAR *str;
+
+    str = compiler_alloc_bstr(ctx, arg1);
+    if(!str)
+        return E_OUTOFMEMORY;
+
+    instr = push_instr(ctx, op);
+    if(!instr)
+        return E_OUTOFMEMORY;
+
+    instr_ptr(ctx, instr)->u.arg[0].bstr = str;
+    instr_ptr(ctx, instr)->u.arg[1].uint = arg2;
+    return S_OK;
+}
+
+static HRESULT push_instr_uint_str(compiler_ctx_t *ctx, jsop_t op, unsigned arg1, const WCHAR *arg2)
+{
+    unsigned instr;
+    jsstr_t *str;
+
+    str = compiler_alloc_string(ctx, arg2);
+    if(!str)
+        return E_OUTOFMEMORY;
+
+    instr = push_instr(ctx, op);
+    if(!instr)
+        return E_OUTOFMEMORY;
+
+    instr_ptr(ctx, instr)->u.arg[0].uint = arg1;
+    instr_ptr(ctx, instr)->u.arg[1].str = str;
+    return S_OK;
+}
+
+static HRESULT push_instr_double(compiler_ctx_t *ctx, jsop_t op, double arg)
+{
+    unsigned instr;
+
+    instr = push_instr(ctx, op);
+    if(!instr)
+        return E_OUTOFMEMORY;
+
+    instr_ptr(ctx, instr)->u.dbl = arg;
+    return S_OK;
+}
+
+static inline void set_arg_uint(compiler_ctx_t *ctx, unsigned instr, unsigned arg)
+{
+    instr_ptr(ctx, instr)->u.arg->uint = arg;
+}
+
+static HRESULT push_instr_uint(compiler_ctx_t *ctx, jsop_t op, unsigned arg)
+{
+    unsigned instr;
+
+    instr = push_instr(ctx, op);
+    if(!instr)
+        return E_OUTOFMEMORY;
+
+    set_arg_uint(ctx, instr, arg);
+    return S_OK;
+}
+
+static HRESULT compile_binary_expression(compiler_ctx_t *ctx, binary_expression_t *expr, jsop_t op)
+{
+    HRESULT hres;
+
+    hres = compile_expression(ctx, expr->expression1, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    hres = compile_expression(ctx, expr->expression2, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    return push_instr(ctx, op) ? S_OK : E_OUTOFMEMORY;
+}
+
+static HRESULT compile_unary_expression(compiler_ctx_t *ctx, unary_expression_t *expr, jsop_t op)
+{
+    HRESULT hres;
+
+    hres = compile_expression(ctx, expr->expression, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    return push_instr(ctx, op) ? S_OK : E_OUTOFMEMORY;
+}
+
+/* ECMA-262 3rd Edition    11.2.1 */
+static HRESULT compile_member_expression(compiler_ctx_t *ctx, member_expression_t *expr)
+{
+    HRESULT hres;
+
+    hres = compile_expression(ctx, expr->expression, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    return push_instr_bstr(ctx, OP_member, expr->identifier);
+}
+
+#define LABEL_FLAG 0x80000000
+
+static unsigned alloc_label(compiler_ctx_t *ctx)
+{
+    if(!ctx->labels_size) {
+        ctx->labels = heap_alloc(8 * sizeof(*ctx->labels));
+        if(!ctx->labels)
+            return 0;
+        ctx->labels_size = 8;
+    }else if(ctx->labels_size == ctx->labels_cnt) {
+        unsigned *new_labels;
+
+        new_labels = heap_realloc(ctx->labels, 2*ctx->labels_size*sizeof(*ctx->labels));
+        if(!new_labels)
+            return 0;
+
+        ctx->labels = new_labels;
+        ctx->labels_size *= 2;
+    }
+
+    return ctx->labels_cnt++ | LABEL_FLAG;
+}
+
+static void label_set_addr(compiler_ctx_t *ctx, unsigned label)
+{
+    assert(label & LABEL_FLAG);
+    ctx->labels[label & ~LABEL_FLAG] = ctx->code_off;
+}
+
+static inline BOOL is_memberid_expr(expression_type_t type)
+{
+    return type == EXPR_IDENT || type == EXPR_MEMBER || type == EXPR_ARRAY;
+}
+
+static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *expr, unsigned flags)
+{
+    HRESULT hres = S_OK;
+
+    switch(expr->type) {
+    case EXPR_IDENT: {
+        identifier_expression_t *ident_expr = (identifier_expression_t*)expr;
+
+        hres = push_instr_bstr_uint(ctx, OP_identid, ident_expr->identifier, flags);
+        break;
+    }
+    case EXPR_ARRAY: {
+        binary_expression_t *array_expr = (binary_expression_t*)expr;
+
+        hres = compile_expression(ctx, array_expr->expression1, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        hres = compile_expression(ctx, array_expr->expression2, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        hres = push_instr_uint(ctx, OP_memberid, flags);
+        break;
+    }
+    case EXPR_MEMBER: {
+        member_expression_t *member_expr = (member_expression_t*)expr;
+
+        hres = compile_expression(ctx, member_expr->expression, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        /* FIXME: Potential optimization */
+        hres = push_instr_str(ctx, OP_str, member_expr->identifier);
+        if(FAILED(hres))
+            return hres;
+
+        hres = push_instr_uint(ctx, OP_memberid, flags);
+        break;
+    }
+    DEFAULT_UNREACHABLE;
+    }
+
+    return hres;
+}
+
+static HRESULT compile_increment_expression(compiler_ctx_t *ctx, unary_expression_t *expr, jsop_t op, int n)
+{
+    HRESULT hres;
+
+    if(!is_memberid_expr(expr->expression->type)) {
+        hres = compile_expression(ctx, expr->expression, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        return push_instr_uint(ctx, OP_throw_ref, JS_E_ILLEGAL_ASSIGN);
+    }
+
+    hres = compile_memberid_expression(ctx, expr->expression, fdexNameEnsure);
+    if(FAILED(hres))
+        return hres;
+
+    return push_instr_int(ctx, op, n);
+}
+
+/* ECMA-262 3rd Edition    11.14 */
+static HRESULT compile_comma_expression(compiler_ctx_t *ctx, binary_expression_t *expr, BOOL emit_ret)
+{
+    HRESULT hres;
+
+    hres = compile_expression(ctx, expr->expression1, FALSE);
+    if(FAILED(hres))
+        return hres;
+
+    return compile_expression(ctx, expr->expression2, emit_ret);
+}
+
+/* ECMA-262 3rd Edition    11.11 */
+static HRESULT compile_logical_expression(compiler_ctx_t *ctx, binary_expression_t *expr, jsop_t op)
+{
+    unsigned instr;
+    HRESULT hres;
+
+    hres = compile_expression(ctx, expr->expression1, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    instr = push_instr(ctx, op);
+    if(!instr)
+        return E_OUTOFMEMORY;
+
+    hres = compile_expression(ctx, expr->expression2, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    set_arg_uint(ctx, instr, ctx->code_off);
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    11.12 */
+static HRESULT compile_conditional_expression(compiler_ctx_t *ctx, conditional_expression_t *expr)
+{
+    unsigned jmp_false, jmp_end;
+    HRESULT hres;
+
+    hres = compile_expression(ctx, expr->expression, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    jmp_false = push_instr(ctx, OP_cnd_z);
+    if(!jmp_false)
+        return E_OUTOFMEMORY;
+
+    hres = compile_expression(ctx, expr->true_expression, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    jmp_end = push_instr(ctx, OP_jmp);
+    if(!jmp_end)
+        return E_OUTOFMEMORY;
+
+    set_arg_uint(ctx, jmp_false, ctx->code_off);
+    hres = push_instr_uint(ctx, OP_pop, 1);
+    if(FAILED(hres))
+        return hres;
+
+    hres = compile_expression(ctx, expr->false_expression, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    set_arg_uint(ctx, jmp_end, ctx->code_off);
+    return S_OK;
+}
+
+static HRESULT compile_new_expression(compiler_ctx_t *ctx, call_expression_t *expr)
+{
+    unsigned arg_cnt = 0;
+    argument_t *arg;
+    HRESULT hres;
+
+    hres = compile_expression(ctx, expr->expression, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    for(arg = expr->argument_list; arg; arg = arg->next) {
+        hres = compile_expression(ctx, arg->expr, TRUE);
+        if(FAILED(hres))
+            return hres;
+        arg_cnt++;
+    }
+
+    return push_instr_uint(ctx, OP_new, arg_cnt);
+}
+
+static HRESULT compile_call_expression(compiler_ctx_t *ctx, call_expression_t *expr, BOOL emit_ret)
+{
+    unsigned arg_cnt = 0;
+    argument_t *arg;
+    unsigned instr;
+    jsop_t op;
+    HRESULT hres;
+
+    if(is_memberid_expr(expr->expression->type)) {
+        op = OP_call_member;
+        hres = compile_memberid_expression(ctx, expr->expression, 0);
+    }else {
+        op = OP_call;
+        hres = compile_expression(ctx, expr->expression, TRUE);
+    }
+
+    if(FAILED(hres))
+        return hres;
+
+    for(arg = expr->argument_list; arg; arg = arg->next) {
+        hres = compile_expression(ctx, arg->expr, TRUE);
+        if(FAILED(hres))
+            return hres;
+        arg_cnt++;
+    }
+
+    instr = push_instr(ctx, op);
+    if(!instr)
+        return E_OUTOFMEMORY;
+
+    instr_ptr(ctx, instr)->u.arg[0].uint = arg_cnt;
+    instr_ptr(ctx, instr)->u.arg[1].lng = emit_ret;
+    return S_OK;
+}
+
+static HRESULT compile_delete_expression(compiler_ctx_t *ctx, unary_expression_t *expr)
+{
+    HRESULT hres;
+
+    switch(expr->expression->type) {
+    case EXPR_ARRAY: {
+        binary_expression_t *array_expr = (binary_expression_t*)expr->expression;
+
+        hres = compile_expression(ctx, array_expr->expression1, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        hres = compile_expression(ctx, array_expr->expression2, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        if(!push_instr(ctx, OP_delete))
+            return E_OUTOFMEMORY;
+        break;
+    }
+    case EXPR_MEMBER: {
+        member_expression_t *member_expr = (member_expression_t*)expr->expression;
+
+        hres = compile_expression(ctx, member_expr->expression, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        /* FIXME: Potential optimization */
+        hres = push_instr_str(ctx, OP_str, member_expr->identifier);
+        if(FAILED(hres))
+            return hres;
+
+        if(!push_instr(ctx, OP_delete))
+            return E_OUTOFMEMORY;
+        break;
+    }
+    case EXPR_IDENT:
+        return push_instr_bstr(ctx, OP_delete_ident, ((identifier_expression_t*)expr->expression)->identifier);
+    default: {
+        const WCHAR fixmeW[] = {'F','I','X','M','E',0};
+
+        WARN("invalid delete, unimplemented exception message\n");
+
+        hres = compile_expression(ctx, expr->expression, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        return push_instr_uint_str(ctx, OP_throw_type, JS_E_INVALID_DELETE, fixmeW);
+    }
+    }
+
+    return S_OK;
+}
+
+static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_t *expr, jsop_t op)
+{
+    BOOL use_throw_path = FALSE;
+    unsigned arg_cnt = 0;
+    HRESULT hres;
+
+    if(expr->expression1->type == EXPR_CALL) {
+        call_expression_t *call_expr = (call_expression_t*)expr->expression1;
+        argument_t *arg;
+
+        if(op != OP_LAST) {
+            FIXME("op %d not supported on parametrized assign expressions\n", op);
+            return E_NOTIMPL;
+        }
+
+        if(is_memberid_expr(call_expr->expression->type) && call_expr->argument_list) {
+            hres = compile_memberid_expression(ctx, call_expr->expression, fdexNameEnsure);
+            if(FAILED(hres))
+                return hres;
+
+            for(arg = call_expr->argument_list; arg; arg = arg->next) {
+                hres = compile_expression(ctx, arg->expr, TRUE);
+                if(FAILED(hres))
+                    return hres;
+                arg_cnt++;
+            }
+        }else {
+            use_throw_path = TRUE;
+        }
+    }else if(is_memberid_expr(expr->expression1->type)) {
+        hres = compile_memberid_expression(ctx, expr->expression1, fdexNameEnsure);
+        if(FAILED(hres))
+            return hres;
+    }else {
+        use_throw_path = TRUE;
+    }
+
+    if(use_throw_path) {
+        /* Illegal assignment: evaluate and throw */
+        hres = compile_expression(ctx, expr->expression1, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        hres = compile_expression(ctx, expr->expression2, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        if(op != OP_LAST && !push_instr(ctx, op))
+            return E_OUTOFMEMORY;
+
+        return push_instr_uint(ctx, OP_throw_ref, JS_E_ILLEGAL_ASSIGN);
+    }
+
+    if(op != OP_LAST && !push_instr(ctx, OP_refval))
+        return E_OUTOFMEMORY;
+
+    hres = compile_expression(ctx, expr->expression2, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    if(op != OP_LAST && !push_instr(ctx, op))
+        return E_OUTOFMEMORY;
+
+    if(arg_cnt)
+        return push_instr_uint(ctx, OP_assign_call, arg_cnt);
+
+    if(!push_instr(ctx, OP_assign))
+        return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+static HRESULT compile_typeof_expression(compiler_ctx_t *ctx, unary_expression_t *expr)
+{
+    jsop_t op;
+    HRESULT hres;
+
+    if(is_memberid_expr(expr->expression->type)) {
+        if(expr->expression->type == EXPR_IDENT)
+            return push_instr_bstr(ctx, OP_typeofident, ((identifier_expression_t*)expr->expression)->identifier);
+
+        op = OP_typeofid;
+        hres = compile_memberid_expression(ctx, expr->expression, 0);
+    }else {
+        op = OP_typeof;
+        hres = compile_expression(ctx, expr->expression, TRUE);
+    }
+    if(FAILED(hres))
+        return hres;
+
+    return push_instr(ctx, op) ? S_OK : E_OUTOFMEMORY;
+}
+
+static HRESULT compile_literal(compiler_ctx_t *ctx, literal_t *literal)
+{
+    switch(literal->type) {
+    case LT_BOOL:
+        return push_instr_int(ctx, OP_bool, literal->u.bval);
+    case LT_DOUBLE:
+        return push_instr_double(ctx, OP_double, literal->u.dval);
+    case LT_NULL:
+        return push_instr(ctx, OP_null) ? S_OK : E_OUTOFMEMORY;
+    case LT_STRING:
+        return push_instr_str(ctx, OP_str, literal->u.wstr);
+    case LT_REGEXP: {
+        unsigned instr;
+        jsstr_t *str;
+
+        str = compiler_alloc_string_len(ctx, literal->u.regexp.str, literal->u.regexp.str_len);
+        if(!str)
+            return E_OUTOFMEMORY;
+
+        instr = push_instr(ctx, OP_regexp);
+        if(!instr)
+            return E_OUTOFMEMORY;
+
+        instr_ptr(ctx, instr)->u.arg[0].str = str;
+        instr_ptr(ctx, instr)->u.arg[1].uint = literal->u.regexp.flags;
+        return S_OK;
+    }
+    DEFAULT_UNREACHABLE;
+    }
+}
+
+static HRESULT literal_as_bstr(compiler_ctx_t *ctx, literal_t *literal, BSTR *str)
+{
+    switch(literal->type) {
+    case LT_STRING:
+        *str = compiler_alloc_bstr(ctx, literal->u.wstr);
+        break;
+    case LT_DOUBLE: {
+        jsstr_t *jsstr;
+        HRESULT hres;
+
+        hres = double_to_string(literal->u.dval, &jsstr);
+        if(FAILED(hres))
+            return hres;
+
+        *str = compiler_alloc_bstr_len(ctx, NULL, jsstr_length(jsstr));
+        if(*str)
+            jsstr_flush(jsstr, *str);
+        jsstr_release(jsstr);
+        break;
+    }
+    DEFAULT_UNREACHABLE;
+    }
+
+    return *str ? S_OK : E_OUTOFMEMORY;
+}
+
+static HRESULT compile_array_literal(compiler_ctx_t *ctx, array_literal_expression_t *expr)
+{
+    unsigned i, elem_cnt = expr->length;
+    array_element_t *iter;
+    HRESULT hres;
+
+    for(iter = expr->element_list; iter; iter = iter->next) {
+        elem_cnt += iter->elision+1;
+
+        for(i=0; i < iter->elision; i++) {
+            if(!push_instr(ctx, OP_undefined))
+                return E_OUTOFMEMORY;
+        }
+
+        hres = compile_expression(ctx, iter->expr, TRUE);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    for(i=0; i < expr->length; i++) {
+        if(!push_instr(ctx, OP_undefined))
+            return E_OUTOFMEMORY;
+    }
+
+    return push_instr_uint(ctx, OP_carray, elem_cnt);
+}
+
+static HRESULT compile_object_literal(compiler_ctx_t *ctx, property_value_expression_t *expr)
+{
+    prop_val_t *iter;
+    unsigned instr;
+    BSTR name;
+    HRESULT hres;
+
+    if(!push_instr(ctx, OP_new_obj))
+        return E_OUTOFMEMORY;
+
+    for(iter = expr->property_list; iter; iter = iter->next) {
+        hres = literal_as_bstr(ctx, iter->name, &name);
+        if(FAILED(hres))
+            return hres;
+
+        hres = compile_expression(ctx, iter->value, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        instr = push_instr(ctx, OP_obj_prop);
+        if(!instr)
+            return E_OUTOFMEMORY;
+
+        instr_ptr(ctx, instr)->u.arg->bstr = name;
+    }
+
+    return S_OK;
+}
+
+static HRESULT compile_function_expression(compiler_ctx_t *ctx, function_expression_t *expr)
+{
+    ctx->func_tail = ctx->func_tail ? (ctx->func_tail->next = expr) : (ctx->func_head = expr);
+
+    /* FIXME: not exactly right */
+    if(expr->identifier) {
+        ctx->func->func_cnt++;
+        return push_instr_bstr(ctx, OP_ident, expr->identifier);
+    }
+
+    return push_instr_uint(ctx, OP_func, ctx->func->func_cnt++);
+}
+
+static HRESULT compile_expression(compiler_ctx_t *ctx, expression_t *expr, BOOL emit_ret)
+{
+    HRESULT hres;
+
+    switch(expr->type) {
+    case EXPR_ADD:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_add);
+        break;
+    case EXPR_AND:
+        hres = compile_logical_expression(ctx, (binary_expression_t*)expr, OP_cnd_z);
+        break;
+    case EXPR_ARRAY:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_array);
+        break;
+    case EXPR_ARRAYLIT:
+        hres = compile_array_literal(ctx, (array_literal_expression_t*)expr);
+        break;
+    case EXPR_ASSIGN:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_LAST);
+        break;
+    case EXPR_ASSIGNADD:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_add);
+        break;
+    case EXPR_ASSIGNAND:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_and);
+        break;
+    case EXPR_ASSIGNSUB:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_sub);
+        break;
+    case EXPR_ASSIGNMUL:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_mul);
+        break;
+    case EXPR_ASSIGNDIV:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_div);
+        break;
+    case EXPR_ASSIGNMOD:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_mod);
+        break;
+    case EXPR_ASSIGNOR:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_or);
+        break;
+    case EXPR_ASSIGNLSHIFT:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_lshift);
+        break;
+    case EXPR_ASSIGNRSHIFT:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_rshift);
+        break;
+    case EXPR_ASSIGNRRSHIFT:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_rshift2);
+        break;
+    case EXPR_ASSIGNXOR:
+        hres = compile_assign_expression(ctx, (binary_expression_t*)expr, OP_xor);
+        break;
+    case EXPR_BAND:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_and);
+        break;
+    case EXPR_BITNEG:
+        hres = compile_unary_expression(ctx, (unary_expression_t*)expr, OP_bneg);
+        break;
+    case EXPR_BOR:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_or);
+        break;
+    case EXPR_CALL:
+        return compile_call_expression(ctx, (call_expression_t*)expr, emit_ret);
+    case EXPR_COMMA:
+        return compile_comma_expression(ctx, (binary_expression_t*)expr, emit_ret);
+    case EXPR_COND:
+        hres = compile_conditional_expression(ctx, (conditional_expression_t*)expr);
+        break;
+    case EXPR_DELETE:
+        hres = compile_delete_expression(ctx, (unary_expression_t*)expr);
+        break;
+    case EXPR_DIV:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_div);
+        break;
+    case EXPR_EQ:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_eq);
+        break;
+    case EXPR_EQEQ:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_eq2);
+        break;
+    case EXPR_FUNC:
+        hres = compile_function_expression(ctx, (function_expression_t*)expr);
+        break;
+    case EXPR_GREATER:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_gt);
+        break;
+    case EXPR_GREATEREQ:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_gteq);
+        break;
+    case EXPR_IDENT:
+        hres = push_instr_bstr(ctx, OP_ident, ((identifier_expression_t*)expr)->identifier);
+        break;
+    case EXPR_IN:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_in);
+        break;
+    case EXPR_INSTANCEOF:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_instanceof);
+        break;
+    case EXPR_LESS:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_lt);
+        break;
+    case EXPR_LESSEQ:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_lteq);
+        break;
+    case EXPR_LITERAL:
+        hres = compile_literal(ctx, ((literal_expression_t*)expr)->literal);
+        break;
+    case EXPR_LOGNEG:
+        hres = compile_unary_expression(ctx, (unary_expression_t*)expr, OP_neg);
+        break;
+    case EXPR_LSHIFT:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_lshift);
+        break;
+    case EXPR_MEMBER:
+        hres = compile_member_expression(ctx, (member_expression_t*)expr);
+        break;
+    case EXPR_MINUS:
+        hres = compile_unary_expression(ctx, (unary_expression_t*)expr, OP_minus);
+        break;
+    case EXPR_MOD:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_mod);
+        break;
+    case EXPR_MUL:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_mul);
+        break;
+    case EXPR_NEW:
+        hres = compile_new_expression(ctx, (call_expression_t*)expr);
+        break;
+    case EXPR_NOTEQ:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_neq);
+        break;
+    case EXPR_NOTEQEQ:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_neq2);
+        break;
+    case EXPR_OR:
+        hres = compile_logical_expression(ctx, (binary_expression_t*)expr, OP_cnd_nz);
+        break;
+    case EXPR_PLUS:
+        hres = compile_unary_expression(ctx, (unary_expression_t*)expr, OP_tonum);
+        break;
+    case EXPR_POSTDEC:
+        hres = compile_increment_expression(ctx, (unary_expression_t*)expr, OP_postinc, -1);
+        break;
+    case EXPR_POSTINC:
+        hres = compile_increment_expression(ctx, (unary_expression_t*)expr, OP_postinc, 1);
+        break;
+    case EXPR_PREDEC:
+        hres = compile_increment_expression(ctx, (unary_expression_t*)expr, OP_preinc, -1);
+        break;
+    case EXPR_PREINC:
+        hres = compile_increment_expression(ctx, (unary_expression_t*)expr, OP_preinc, 1);
+        break;
+    case EXPR_PROPVAL:
+        hres = compile_object_literal(ctx, (property_value_expression_t*)expr);
+        break;
+    case EXPR_RSHIFT:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_rshift);
+        break;
+    case EXPR_RRSHIFT:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_rshift2);
+        break;
+    case EXPR_SUB:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_sub);
+        break;
+    case EXPR_THIS:
+        return !emit_ret || push_instr(ctx, OP_this) ? S_OK : E_OUTOFMEMORY;
+    case EXPR_TYPEOF:
+        hres = compile_typeof_expression(ctx, (unary_expression_t*)expr);
+        break;
+    case EXPR_VOID:
+        hres = compile_unary_expression(ctx, (unary_expression_t*)expr, OP_void);
+        break;
+    case EXPR_BXOR:
+        hres = compile_binary_expression(ctx, (binary_expression_t*)expr, OP_xor);
+        break;
+    DEFAULT_UNREACHABLE;
+    }
+
+    if(FAILED(hres))
+        return hres;
+
+    return emit_ret ? S_OK : push_instr_uint(ctx, OP_pop, 1);
+}
+
+static inline BOOL is_loop_statement(statement_type_t type)
+{
+    return type == STAT_FOR || type == STAT_FORIN || type == STAT_WHILE;
+}
+
+/* ECMA-262 3rd Edition    12.1 */
+static HRESULT compile_block_statement(compiler_ctx_t *ctx, statement_t *iter)
+{
+    HRESULT hres;
+
+    while(iter) {
+        hres = compile_statement(ctx, NULL, iter);
+        if(FAILED(hres))
+            return hres;
+
+        iter = iter->next;
+    }
+
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    12.2 */
+static HRESULT compile_variable_list(compiler_ctx_t *ctx, variable_declaration_t *list)
+{
+    variable_declaration_t *iter;
+    HRESULT hres;
+
+    assert(list != NULL);
+
+    if(ctx->var_tail)
+        ctx->var_tail->global_next = list;
+    else
+        ctx->var_head = list;
+
+    for(iter = list; iter; iter = iter->next) {
+        ctx->func->var_cnt++;
+        iter->global_next = iter->next;
+        if(!iter->next)
+            ctx->var_tail = iter;
+
+        if(!iter->expr)
+            continue;
+
+        hres = compile_expression(ctx, iter->expr, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        hres = push_instr_bstr(ctx, OP_var_set, iter->identifier);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    12.2 */
+static HRESULT compile_var_statement(compiler_ctx_t *ctx, var_statement_t *stat)
+{
+    return compile_variable_list(ctx, stat->variable_list);
+}
+
+/* ECMA-262 3rd Edition    12.4 */
+static HRESULT compile_expression_statement(compiler_ctx_t *ctx, expression_statement_t *stat)
+{
+    HRESULT hres;
+
+    hres = compile_expression(ctx, stat->expr, ctx->from_eval);
+    if(FAILED(hres))
+        return hres;
+
+    return !ctx->from_eval || push_instr(ctx, OP_setret) ? S_OK : E_OUTOFMEMORY;
+}
+
+/* ECMA-262 3rd Edition    12.5 */
+static HRESULT compile_if_statement(compiler_ctx_t *ctx, if_statement_t *stat)
+{
+    unsigned jmp_else;
+    HRESULT hres;
+
+    hres = compile_expression(ctx, stat->expr, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    jmp_else = push_instr(ctx, OP_jmp_z);
+    if(!jmp_else)
+        return E_OUTOFMEMORY;
+
+    hres = compile_statement(ctx, NULL, stat->if_stat);
+    if(FAILED(hres))
+        return hres;
+
+    if(stat->else_stat) {
+        unsigned jmp_end;
+
+        jmp_end = push_instr(ctx, OP_jmp);
+        if(!jmp_end)
+            return E_OUTOFMEMORY;
+
+        set_arg_uint(ctx, jmp_else, ctx->code_off);
+
+        hres = compile_statement(ctx, NULL, stat->else_stat);
+        if(FAILED(hres))
+            return hres;
+
+        set_arg_uint(ctx, jmp_end, ctx->code_off);
+    }else {
+        set_arg_uint(ctx, jmp_else, ctx->code_off);
+    }
+
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    12.6.2 */
+static HRESULT compile_while_statement(compiler_ctx_t *ctx, while_statement_t *stat)
+{
+    statement_ctx_t stat_ctx = {0, FALSE, FALSE};
+    unsigned jmp_off;
+    HRESULT hres;
+
+    stat_ctx.break_label = alloc_label(ctx);
+    if(!stat_ctx.break_label)
+        return E_OUTOFMEMORY;
+
+    stat_ctx.continue_label = alloc_label(ctx);
+    if(!stat_ctx.continue_label)
+        return E_OUTOFMEMORY;
+
+    jmp_off = ctx->code_off;
+
+    if(!stat->do_while) {
+        label_set_addr(ctx, stat_ctx.continue_label);
+        hres = compile_expression(ctx, stat->expr, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        hres = push_instr_uint(ctx, OP_jmp_z, stat_ctx.break_label);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    hres = compile_statement(ctx, &stat_ctx, stat->statement);
+    if(FAILED(hres))
+        return hres;
+
+    if(stat->do_while) {
+        label_set_addr(ctx, stat_ctx.continue_label);
+        hres = compile_expression(ctx, stat->expr, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        hres = push_instr_uint(ctx, OP_jmp_z, stat_ctx.break_label);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    hres = push_instr_uint(ctx, OP_jmp, jmp_off);
+    if(FAILED(hres))
+        return hres;
+
+    label_set_addr(ctx, stat_ctx.break_label);
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    12.6.3 */
+static HRESULT compile_for_statement(compiler_ctx_t *ctx, for_statement_t *stat)
+{
+    statement_ctx_t stat_ctx = {0, FALSE, FALSE};
+    unsigned expr_off;
+    HRESULT hres;
+
+    if(stat->variable_list) {
+        hres = compile_variable_list(ctx, stat->variable_list);
+        if(FAILED(hres))
+            return hres;
+    }else if(stat->begin_expr) {
+        hres = compile_expression(ctx, stat->begin_expr, FALSE);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    stat_ctx.break_label = alloc_label(ctx);
+    if(!stat_ctx.break_label)
+        return E_OUTOFMEMORY;
+
+    stat_ctx.continue_label = alloc_label(ctx);
+    if(!stat_ctx.continue_label)
+        return E_OUTOFMEMORY;
+
+    expr_off = ctx->code_off;
+
+    if(stat->expr) {
+        hres = compile_expression(ctx, stat->expr, TRUE);
+        if(FAILED(hres))
+            return hres;
+
+        hres = push_instr_uint(ctx, OP_jmp_z, stat_ctx.break_label);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    hres = compile_statement(ctx, &stat_ctx, stat->statement);
+    if(FAILED(hres))
+        return hres;
+
+    label_set_addr(ctx, stat_ctx.continue_label);
+
+    if(stat->end_expr) {
+        hres = compile_expression(ctx, stat->end_expr, FALSE);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    hres = push_instr_uint(ctx, OP_jmp, expr_off);
+    if(FAILED(hres))
+        return hres;
+
+    label_set_addr(ctx, stat_ctx.break_label);
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    12.6.4 */
+static HRESULT compile_forin_statement(compiler_ctx_t *ctx, forin_statement_t *stat)
+{
+    statement_ctx_t stat_ctx = {4, FALSE, FALSE};
+    HRESULT hres;
+
+    if(stat->variable) {
+        hres = compile_variable_list(ctx, stat->variable);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    stat_ctx.break_label = alloc_label(ctx);
+    if(!stat_ctx.break_label)
+        return E_OUTOFMEMORY;
+
+    stat_ctx.continue_label = alloc_label(ctx);
+    if(!stat_ctx.continue_label)
+        return E_OUTOFMEMORY;
+
+    hres = compile_expression(ctx, stat->in_expr, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    if(stat->variable) {
+        hres = push_instr_bstr_uint(ctx, OP_identid, stat->variable->identifier, fdexNameEnsure);
+        if(FAILED(hres))
+            return hres;
+    }else if(is_memberid_expr(stat->expr->type)) {
+        hres = compile_memberid_expression(ctx, stat->expr, fdexNameEnsure);
+        if(FAILED(hres))
+            return hres;
+    }else {
+        hres = push_instr_uint(ctx, OP_throw_ref, JS_E_ILLEGAL_ASSIGN);
+        if(FAILED(hres))
+            return hres;
+
+        /* FIXME: compile statement anyways when we depend on compiler to check errors */
+        return S_OK;
+    }
+
+    hres = push_instr_int(ctx, OP_int, DISPID_STARTENUM);
+    if(FAILED(hres))
+        return hres;
+
+    label_set_addr(ctx, stat_ctx.continue_label);
+    hres = push_instr_uint(ctx, OP_forin, stat_ctx.break_label);
+    if(FAILED(hres))
+        return E_OUTOFMEMORY;
+
+    hres = compile_statement(ctx, &stat_ctx, stat->statement);
+    if(FAILED(hres))
+        return hres;
+
+    hres = push_instr_uint(ctx, OP_jmp, stat_ctx.continue_label);
+    if(FAILED(hres))
+        return hres;
+
+    label_set_addr(ctx, stat_ctx.break_label);
+    return S_OK;
+}
+
+static HRESULT pop_to_stat(compiler_ctx_t *ctx, BOOL var_stack, BOOL scope_stack, statement_ctx_t *stat_ctx)
+{
+    unsigned stack_pop = 0;
+    statement_ctx_t *iter;
+
+    for(iter = ctx->stat_ctx; iter != stat_ctx; iter = iter->next) {
+        if(scope_stack) {
+            if(iter->using_scope && !push_instr(ctx, OP_pop_scope))
+                return E_OUTOFMEMORY;
+            if(iter->using_except && !push_instr(ctx, OP_pop_except))
+                return E_OUTOFMEMORY;
+        }
+        stack_pop += iter->stack_use;
+    }
+
+    if(var_stack && stack_pop) {
+        HRESULT hres;
+
+        hres = push_instr_uint(ctx, OP_pop, stack_pop);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    12.7 */
+static HRESULT compile_continue_statement(compiler_ctx_t *ctx, branch_statement_t *stat)
+{
+    statement_ctx_t *pop_ctx;
+    HRESULT hres;
+
+    if(stat->identifier) {
+        statement_t *label_stat;
+        statement_ctx_t *iter;
+
+        pop_ctx = NULL;
+
+        for(iter = ctx->stat_ctx; iter; iter = iter->next) {
+            if(iter->continue_label)
+                pop_ctx = iter;
+            if(iter->labelled_stat && !strcmpW(iter->labelled_stat->identifier, stat->identifier))
+                break;
+        }
+
+        if(!iter) {
+            WARN("Label not found\n");
+            return JS_E_LABEL_NOT_FOUND;
+        }
+
+        /* Labelled continue are allowed only on loops */
+        for(label_stat = iter->labelled_stat->statement;
+            label_stat->type == STAT_LABEL;
+            label_stat = ((labelled_statement_t*)label_stat)->statement);
+        if(!is_loop_statement(label_stat->type)) {
+            WARN("Label is not a loop\n");
+            return JS_E_INVALID_CONTINUE;
+        }
+
+        assert(pop_ctx != NULL);
+    }else {
+        for(pop_ctx = ctx->stat_ctx; pop_ctx; pop_ctx = pop_ctx->next) {
+            if(pop_ctx->continue_label)
+                break;
+        }
+
+        if(!pop_ctx) {
+            WARN("continue outside loop\n");
+            return JS_E_INVALID_CONTINUE;
+        }
+    }
+
+    hres = pop_to_stat(ctx, TRUE, TRUE, pop_ctx);
+    if(FAILED(hres))
+        return hres;
+
+    return push_instr_uint(ctx, OP_jmp, pop_ctx->continue_label);
+}
+
+/* ECMA-262 3rd Edition    12.8 */
+static HRESULT compile_break_statement(compiler_ctx_t *ctx, branch_statement_t *stat)
+{
+    statement_ctx_t *pop_ctx;
+    HRESULT hres;
+
+    if(stat->identifier) {
+        for(pop_ctx = ctx->stat_ctx; pop_ctx; pop_ctx = pop_ctx->next) {
+            if(pop_ctx->labelled_stat && !strcmpW(pop_ctx->labelled_stat->identifier, stat->identifier)) {
+                assert(pop_ctx->break_label);
+                break;
+            }
+        }
+
+        if(!pop_ctx) {
+            WARN("Label not found\n");
+            return JS_E_LABEL_NOT_FOUND;
+        }
+    }else {
+        for(pop_ctx = ctx->stat_ctx; pop_ctx; pop_ctx = pop_ctx->next) {
+            if(pop_ctx->break_label && !pop_ctx->labelled_stat)
+                break;
+        }
+
+        if(!pop_ctx) {
+            WARN("Break outside loop\n");
+            return JS_E_INVALID_BREAK;
+        }
+    }
+
+    hres = pop_to_stat(ctx, TRUE, TRUE, pop_ctx->next);
+    if(FAILED(hres))
+        return hres;
+
+    return push_instr_uint(ctx, OP_jmp, pop_ctx->break_label);
+}
+
+/* ECMA-262 3rd Edition    12.9 */
+static HRESULT compile_return_statement(compiler_ctx_t *ctx, expression_statement_t *stat)
+{
+    HRESULT hres;
+
+    if(ctx->from_eval) {
+        WARN("misplaced return statement\n");
+        return JS_E_MISPLACED_RETURN;
+    }
+
+    hres = pop_to_stat(ctx, TRUE, FALSE, NULL);
+    if(FAILED(hres))
+        return hres;
+
+    if(stat->expr) {
+        hres = compile_expression(ctx, stat->expr, TRUE);
+        if(FAILED(hres))
+            return hres;
+        if(!push_instr(ctx, OP_setret))
+            return E_OUTOFMEMORY;
+    }
+
+    hres = pop_to_stat(ctx, FALSE, TRUE, NULL);
+    if(FAILED(hres))
+        return hres;
+
+    return push_instr(ctx, OP_ret) ? S_OK : E_OUTOFMEMORY;
+}
+
+/* ECMA-262 3rd Edition    12.10 */
+static HRESULT compile_with_statement(compiler_ctx_t *ctx, with_statement_t *stat)
+{
+    statement_ctx_t stat_ctx = {0, TRUE, FALSE};
+    HRESULT hres;
+
+    hres = compile_expression(ctx, stat->expr, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    if(!push_instr(ctx, OP_push_scope))
+        return E_OUTOFMEMORY;
+
+    hres = compile_statement(ctx, &stat_ctx, stat->statement);
+    if(FAILED(hres))
+        return hres;
+
+    if(!push_instr(ctx, OP_pop_scope))
+        return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    12.10 */
+static HRESULT compile_labelled_statement(compiler_ctx_t *ctx, labelled_statement_t *stat)
+{
+    statement_ctx_t stat_ctx = {0, FALSE, FALSE, 0, 0, stat}, *iter;
+    HRESULT hres;
+
+    for(iter = ctx->stat_ctx; iter; iter = iter->next) {
+        if(iter->labelled_stat && !strcmpW(iter->labelled_stat->identifier, stat->identifier)) {
+            WARN("Label %s redefined\n", debugstr_w(stat->identifier));
+            return JS_E_LABEL_REDEFINED;
+        }
+    }
+
+    /* Labelled breaks are allowed for any labelled statements, not only loops (violating spec) */
+    stat_ctx.break_label = alloc_label(ctx);
+    if(!stat_ctx.break_label)
+        return E_OUTOFMEMORY;
+
+    hres = compile_statement(ctx, &stat_ctx, stat->statement);
+    if(FAILED(hres))
+        return hres;
+
+    label_set_addr(ctx, stat_ctx.break_label);
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    12.13 */
+static HRESULT compile_switch_statement(compiler_ctx_t *ctx, switch_statement_t *stat)
+{
+    statement_ctx_t stat_ctx = {0, FALSE, FALSE};
+    unsigned case_cnt = 0, *case_jmps, i, default_jmp;
+    BOOL have_default = FALSE;
+    statement_t *stat_iter;
+    case_clausule_t *iter;
+    HRESULT hres;
+
+    hres = compile_expression(ctx, stat->expr, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    stat_ctx.break_label = alloc_label(ctx);
+    if(!stat_ctx.break_label)
+        return E_OUTOFMEMORY;
+
+    for(iter = stat->case_list; iter; iter = iter->next) {
+        if(iter->expr)
+            case_cnt++;
+    }
+
+    case_jmps = heap_alloc(case_cnt * sizeof(*case_jmps));
+    if(!case_jmps)
+        return E_OUTOFMEMORY;
+
+    i = 0;
+    for(iter = stat->case_list; iter; iter = iter->next) {
+        if(!iter->expr) {
+            have_default = TRUE;
+            continue;
+        }
+
+        hres = compile_expression(ctx, iter->expr, TRUE);
+        if(FAILED(hres))
+            break;
+
+        case_jmps[i] = push_instr(ctx, OP_case);
+        if(!case_jmps[i]) {
+            hres = E_OUTOFMEMORY;
+            break;
+        }
+        i++;
+    }
+
+    if(SUCCEEDED(hres)) {
+        hres = push_instr_uint(ctx, OP_pop, 1);
+        if(SUCCEEDED(hres)) {
+            default_jmp = push_instr(ctx, OP_jmp);
+            if(!default_jmp)
+                hres = E_OUTOFMEMORY;
+        }
+    }
+
+    if(FAILED(hres)) {
+        heap_free(case_jmps);
+        return hres;
+    }
+
+    i = 0;
+    for(iter = stat->case_list; iter; iter = iter->next) {
+        while(iter->next && iter->next->stat == iter->stat) {
+            set_arg_uint(ctx, iter->expr ? case_jmps[i++] : default_jmp, ctx->code_off);
+            iter = iter->next;
+        }
+
+        set_arg_uint(ctx, iter->expr ? case_jmps[i++] : default_jmp, ctx->code_off);
+
+        for(stat_iter = iter->stat; stat_iter && (!iter->next || iter->next->stat != stat_iter);
+            stat_iter = stat_iter->next) {
+            hres = compile_statement(ctx, &stat_ctx, stat_iter);
+            if(FAILED(hres))
+                break;
+        }
+        if(FAILED(hres))
+            break;
+    }
+
+    heap_free(case_jmps);
+    if(FAILED(hres))
+        return hres;
+    assert(i == case_cnt);
+
+    if(!have_default) {
+        hres = push_instr_uint(ctx, OP_jmp, stat_ctx.break_label);
+        if(FAILED(hres))
+            return hres;
+        set_arg_uint(ctx, default_jmp, ctx->code_off);
+    }
+
+    label_set_addr(ctx, stat_ctx.break_label);
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    12.13 */
+static HRESULT compile_throw_statement(compiler_ctx_t *ctx, expression_statement_t *stat)
+{
+    HRESULT hres;
+
+    hres = compile_expression(ctx, stat->expr, TRUE);
+    if(FAILED(hres))
+        return hres;
+
+    return push_instr(ctx, OP_throw) ? S_OK : E_OUTOFMEMORY;
+}
+
+/* ECMA-262 3rd Edition    12.14 */
+static HRESULT compile_try_statement(compiler_ctx_t *ctx, try_statement_t *stat)
+{
+    statement_ctx_t try_ctx = {0, FALSE, TRUE}, catch_ctx = {0, TRUE, FALSE};
+    statement_ctx_t finally_ctx = {2, FALSE, FALSE};
+    unsigned push_except;
+    BSTR ident;
+    HRESULT hres;
+
+    push_except = push_instr(ctx, OP_push_except);
+    if(!push_except)
+        return E_OUTOFMEMORY;
+
+    if(stat->catch_block) {
+        ident = compiler_alloc_bstr(ctx, stat->catch_block->identifier);
+        if(!ident)
+            return E_OUTOFMEMORY;
+    }else {
+        ident = NULL;
+    }
+
+    instr_ptr(ctx, push_except)->u.arg[1].bstr = ident;
+
+    if(!stat->catch_block)
+        try_ctx.stack_use = 2;
+
+    hres = compile_statement(ctx, &try_ctx, stat->try_statement);
+    if(FAILED(hres))
+        return hres;
+
+    if(!push_instr(ctx, OP_pop_except))
+        return E_OUTOFMEMORY;
+
+    if(stat->catch_block) {
+        unsigned jmp_finally;
+
+        jmp_finally = push_instr(ctx, OP_jmp);
+        if(!jmp_finally)
+            return E_OUTOFMEMORY;
+
+        instr_ptr(ctx, push_except)->u.arg[0].uint = ctx->code_off;
+
+        hres = compile_statement(ctx, &catch_ctx, stat->catch_block->statement);
+        if(FAILED(hres))
+            return hres;
+
+        if(!push_instr(ctx, OP_pop_scope))
+            return E_OUTOFMEMORY;
+
+        set_arg_uint(ctx, jmp_finally, ctx->code_off);
+    }else {
+        set_arg_uint(ctx, push_except, ctx->code_off);
+    }
+
+    if(stat->finally_statement) {
+        hres = compile_statement(ctx, stat->catch_block ? NULL : &finally_ctx, stat->finally_statement);
+        if(FAILED(hres))
+            return hres;
+
+        if(!stat->catch_block && !push_instr(ctx, OP_end_finally))
+            return E_OUTOFMEMORY;
+    }
+
+    return S_OK;
+}
+
+static HRESULT compile_statement(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx, statement_t *stat)
+{
+    HRESULT hres;
+
+    if(stat_ctx) {
+        stat_ctx->next = ctx->stat_ctx;
+        ctx->stat_ctx = stat_ctx;
+    }
+
+    switch(stat->type) {
+    case STAT_BLOCK:
+        hres = compile_block_statement(ctx, ((block_statement_t*)stat)->stat_list);
+        break;
+    case STAT_BREAK:
+        hres = compile_break_statement(ctx, (branch_statement_t*)stat);
+        break;
+    case STAT_CONTINUE:
+        hres = compile_continue_statement(ctx, (branch_statement_t*)stat);
+        break;
+    case STAT_EMPTY:
+        /* nothing to do */
+        hres = S_OK;
+        break;
+    case STAT_EXPR:
+        hres = compile_expression_statement(ctx, (expression_statement_t*)stat);
+        break;
+    case STAT_FOR:
+        hres = compile_for_statement(ctx, (for_statement_t*)stat);
+        break;
+    case STAT_FORIN:
+        hres = compile_forin_statement(ctx, (forin_statement_t*)stat);
+        break;
+    case STAT_IF:
+        hres = compile_if_statement(ctx, (if_statement_t*)stat);
+        break;
+    case STAT_LABEL:
+        hres = compile_labelled_statement(ctx, (labelled_statement_t*)stat);
+        break;
+    case STAT_RETURN:
+        hres = compile_return_statement(ctx, (expression_statement_t*)stat);
+        break;
+    case STAT_SWITCH:
+        hres = compile_switch_statement(ctx, (switch_statement_t*)stat);
+        break;
+    case STAT_THROW:
+        hres = compile_throw_statement(ctx, (expression_statement_t*)stat);
+        break;
+    case STAT_TRY:
+        hres = compile_try_statement(ctx, (try_statement_t*)stat);
+        break;
+    case STAT_VAR:
+        hres = compile_var_statement(ctx, (var_statement_t*)stat);
+        break;
+    case STAT_WHILE:
+        hres = compile_while_statement(ctx, (while_statement_t*)stat);
+        break;
+    case STAT_WITH:
+        hres = compile_with_statement(ctx, (with_statement_t*)stat);
+        break;
+    DEFAULT_UNREACHABLE;
+    }
+
+    if(stat_ctx) {
+        assert(ctx->stat_ctx == stat_ctx);
+        ctx->stat_ctx = stat_ctx->next;
+    }
+
+    return hres;
+}
+
+static void resolve_labels(compiler_ctx_t *ctx, unsigned off)
+{
+    instr_t *instr;
+
+    for(instr = ctx->code->instrs+off; instr < ctx->code->instrs+ctx->code_off; instr++) {
+        if(instr_info[instr->op].arg1_type == ARG_ADDR && (instr->u.arg->uint & LABEL_FLAG)) {
+            assert((instr->u.arg->uint & ~LABEL_FLAG) < ctx->labels_cnt);
+            instr->u.arg->uint = ctx->labels[instr->u.arg->uint & ~LABEL_FLAG];
+        }
+        assert(instr_info[instr->op].arg2_type != ARG_ADDR);
+    }
+
+    ctx->labels_cnt = 0;
+}
+
+void release_bytecode(bytecode_t *code)
+{
+    unsigned i;
+
+    if(--code->ref)
+        return;
+
+    for(i=0; i < code->bstr_cnt; i++)
+        SysFreeString(code->bstr_pool[i]);
+    for(i=0; i < code->str_cnt; i++)
+        jsstr_release(code->str_pool[i]);
+
+    heap_free(code->source);
+    heap_pool_free(&code->heap);
+    heap_free(code->bstr_pool);
+    heap_free(code->str_pool);
+    heap_free(code->instrs);
+    heap_free(code);
+}
+
+static HRESULT init_code(compiler_ctx_t *compiler, const WCHAR *source)
+{
+    compiler->code = heap_alloc_zero(sizeof(bytecode_t));
+    if(!compiler->code)
+        return E_OUTOFMEMORY;
+
+    compiler->code->ref = 1;
+    heap_pool_init(&compiler->code->heap);
+
+    compiler->code->source = heap_strdupW(source);
+    if(!compiler->code->source) {
+        release_bytecode(compiler->code);
+        return E_OUTOFMEMORY;
+    }
+
+    compiler->code->instrs = heap_alloc(64 * sizeof(instr_t));
+    if(!compiler->code->instrs) {
+        release_bytecode(compiler->code);
+        return E_OUTOFMEMORY;
+    }
+
+    compiler->code_size = 64;
+    compiler->code_off = 1;
+    return S_OK;
+}
+
+static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source, function_expression_t *func_expr,
+        BOOL from_eval, function_code_t *func)
+{
+    variable_declaration_t *var_iter;
+    function_expression_t *iter;
+    unsigned off, i;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    ctx->var_head = ctx->var_tail = NULL;
+    ctx->func_head = ctx->func_tail = NULL;
+    ctx->from_eval = from_eval;
+
+    off = ctx->code_off;
+    ctx->func = func;
+    hres = compile_block_statement(ctx, source->statement);
+    if(FAILED(hres))
+        return hres;
+
+    resolve_labels(ctx, off);
+
+    if(!push_instr(ctx, OP_ret))
+        return E_OUTOFMEMORY;
+
+    if(TRACE_ON(jscript_disas))
+        dump_code(ctx, off);
+
+    func->instr_off = off;
+
+    if(func_expr && func_expr->identifier) {
+        func->name = compiler_alloc_bstr(ctx, func_expr->identifier);
+        if(!func->name)
+            return E_OUTOFMEMORY;
+    }
+
+    if(func_expr) {
+        parameter_t *param_iter;
+
+        func->source = func_expr->src_str;
+        func->source_len = func_expr->src_len;
+
+        for(param_iter = func_expr->parameter_list; param_iter; param_iter = param_iter->next)
+            func->param_cnt++;
+
+        func->params = compiler_alloc(ctx->code, func->param_cnt * sizeof(*func->params));
+        if(!func->params)
+            return E_OUTOFMEMORY;
+
+        for(param_iter = func_expr->parameter_list, i=0; param_iter; param_iter = param_iter->next, i++) {
+            func->params[i] = compiler_alloc_bstr(ctx, param_iter->identifier);
+            if(!func->params[i])
+                return E_OUTOFMEMORY;
+        }
+    }
+
+    func->variables = compiler_alloc(ctx->code, func->var_cnt * sizeof(*func->variables));
+    if(!func->variables)
+        return E_OUTOFMEMORY;
+
+    for(var_iter = ctx->var_head, i=0; var_iter; var_iter = var_iter->global_next, i++) {
+        func->variables[i] = compiler_alloc_bstr(ctx, var_iter->identifier);
+        if(!func->variables[i])
+            return E_OUTOFMEMORY;
+    }
+
+    assert(i == func->var_cnt);
+
+    func->funcs = compiler_alloc(ctx->code, func->func_cnt * sizeof(*func->funcs));
+    if(!func->funcs)
+        return E_OUTOFMEMORY;
+    memset(func->funcs, 0, func->func_cnt * sizeof(*func->funcs));
+
+    for(iter = ctx->func_head, i=0; iter; iter = iter->next, i++) {
+        hres = compile_function(ctx, iter->source_elements, iter, FALSE, func->funcs+i);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    assert(i == func->func_cnt);
+
+    return S_OK;
+}
+
+static HRESULT parse_arguments(compiler_ctx_t *ctx, const WCHAR *args, BSTR *arg_array, unsigned *args_size)
+{
+    const WCHAR *ptr = args, *ptr2;
+    unsigned arg_cnt = 0;
+
+    while(isspaceW(*ptr))
+        ptr++;
+    if(!*ptr) {
+        if(args_size)
+            *args_size = 0;
+        return S_OK;
+    }
+
+    while(1) {
+        if(!isalphaW(*ptr) && *ptr != '_') {
+            FIXME("expected alpha or '_': %s\n", debugstr_w(ptr));
+            return E_FAIL;
+        }
+
+        ptr2 = ptr;
+        while(isalnumW(*ptr) || *ptr == '_')
+            ptr++;
+
+        if(*ptr && *ptr != ',' && !isspaceW(*ptr)) {
+            FIXME("unexpected har %s\n", debugstr_w(ptr));
+            return E_FAIL;
+        }
+
+        if(arg_array) {
+            arg_array[arg_cnt] = compiler_alloc_bstr_len(ctx, ptr2, ptr-ptr2);
+            if(!arg_array[arg_cnt])
+                return E_OUTOFMEMORY;
+        }
+        arg_cnt++;
+
+        while(isspaceW(*ptr))
+            ptr++;
+        if(!*ptr)
+            break;
+        if(*ptr != ',') {
+            FIXME("expected ',': %s\n", debugstr_w(ptr));
+            return E_FAIL;
+        }
+
+        ptr++;
+        while(isspaceW(*ptr))
+            ptr++;
+    }
+
+    if(args_size)
+        *args_size = arg_cnt;
+    return S_OK;
+}
+
+static HRESULT compile_arguments(compiler_ctx_t *ctx, const WCHAR *args)
+{
+    HRESULT hres;
+
+    hres = parse_arguments(ctx, args, NULL, &ctx->code->global_code.param_cnt);
+    if(FAILED(hres))
+        return hres;
+
+    ctx->code->global_code.params = compiler_alloc(ctx->code,
+            ctx->code->global_code.param_cnt * sizeof(*ctx->code->global_code.params));
+    if(!ctx->code->global_code.params)
+        return E_OUTOFMEMORY;
+
+    return parse_arguments(ctx, args, ctx->code->global_code.params, NULL);
+}
+
+HRESULT compile_script(script_ctx_t *ctx, const WCHAR *code, const WCHAR *args, const WCHAR *delimiter,
+        BOOL from_eval, BOOL use_decode, bytecode_t **ret)
+{
+    compiler_ctx_t compiler = {0};
+    HRESULT hres;
+
+    hres = init_code(&compiler, code);
+    if(FAILED(hres))
+        return hres;
+
+    if(args) {
+        hres = compile_arguments(&compiler, args);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    if(use_decode) {
+        hres = decode_source(compiler.code->source);
+        if(FAILED(hres)) {
+            WARN("Decoding failed\n");
+            return hres;
+        }
+    }
+
+    hres = script_parse(ctx, compiler.code->source, delimiter, from_eval, &compiler.parser);
+    if(FAILED(hres)) {
+        release_bytecode(compiler.code);
+        return hres;
+    }
+
+    hres = compile_function(&compiler, compiler.parser->source, NULL, from_eval, &compiler.code->global_code);
+    parser_release(compiler.parser);
+    if(FAILED(hres)) {
+        release_bytecode(compiler.code);
+        return hres;
+    }
+
+    *ret = compiler.code;
+    return S_OK;
+}
index ebd5012..01db2c9 100644 (file)
@@ -22,6 +22,7 @@
 
 //#include <limits.h>
 //#include <math.h>
+#include <assert.h>
 
 #include "jscript.h"
 
@@ -33,7 +34,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 #define TIME_EPOCH  ((ULONGLONG)(369 * 365 + 89) * 86400 * 1000)
 
 typedef struct {
-    DispatchEx dispex;
+    jsdisp_t dispex;
 
     /* ECMA-262 3rd Edition    15.9.1.1 */
     DOUBLE time;
@@ -91,6 +92,7 @@ static const WCHAR setUTCMonthW[] = {'s','e','t','U','T','C','M','o','n','t','h'
 static const WCHAR setFullYearW[] = {'s','e','t','F','u','l','l','Y','e','a','r',0};
 static const WCHAR setUTCFullYearW[] = {'s','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
 static const WCHAR getYearW[] = {'g','e','t','Y','e','a','r',0};
+static const WCHAR setYearW[] = {'s','e','t','Y','e','a','r',0};
 
 static const WCHAR UTCW[] = {'U','T','C',0};
 static const WCHAR parseW[] = {'p','a','r','s','e',0};
@@ -129,7 +131,7 @@ static inline DOUBLE days_in_year(DOUBLE year)
     int y;
 
     if(year != (int)year)
-        return ret_nan();
+        return NAN;
 
     y = year;
     if(y%4 != 0) return 365;
@@ -142,7 +144,7 @@ static inline DOUBLE days_in_year(DOUBLE year)
 static inline DOUBLE day_from_year(DOUBLE year)
 {
     if(year != (int)year)
-        return ret_nan();
+        return NAN;
 
     return floor(365.0*(year-1970) + floor((year-1969)/4)
         - floor((year-1901)/100) + floor((year-1601)/400));
@@ -191,7 +193,7 @@ static inline DOUBLE year_from_time(DOUBLE time)
     int y;
 
     if(isnan(time))
-        return ret_nan();
+        return NAN;
 
     y = 1970 + time/365.25/MS_PER_DAY;
 
@@ -224,7 +226,7 @@ static inline DOUBLE month_from_time(DOUBLE time)
     int dwy = day_within_year(time);
 
     if(isnan(time))
-        return ret_nan();
+        return NAN;
 
     if(0<=dwy && dwy<31) return 0;
     if(dwy < 59+ily) return 1;
@@ -248,7 +250,7 @@ static inline DOUBLE date_from_time(DOUBLE time)
     int mft = month_from_time(time);
 
     if(isnan(time))
-        return ret_nan();
+        return NAN;
 
     if(mft==0) return dwy+1;
     if(mft==1) return dwy-30;
@@ -270,7 +272,7 @@ static inline DOUBLE week_day(DOUBLE time)
     DOUBLE ret;
 
     if(isnan(time))
-        return ret_nan();
+        return NAN;
 
     ret = fmod(day(time)+4, 7);
     if(ret<0) ret += 7;
@@ -284,7 +286,7 @@ static inline DOUBLE convert_time(int year, SYSTEMTIME st)
     int set_week_day;
 
     if(st.wMonth == 0)
-        return ret_nan();
+        return NAN;
 
     if(st.wYear != 0)
         year = st.wYear;
@@ -358,7 +360,7 @@ static inline DOUBLE hour_from_time(DOUBLE time)
     DOUBLE ret;
 
     if(isnan(time))
-        return ret_nan();
+        return NAN;
 
     ret = fmod(floor(time/MS_PER_HOUR), 24);
     if(ret<0) ret += 24;
@@ -372,7 +374,7 @@ static inline DOUBLE min_from_time(DOUBLE time)
     DOUBLE ret;
 
     if(isnan(time))
-        return ret_nan();
+        return NAN;
 
     ret = fmod(floor(time/MS_PER_MINUTE), 60);
     if(ret<0) ret += 60;
@@ -386,7 +388,7 @@ static inline DOUBLE sec_from_time(DOUBLE time)
     DOUBLE ret;
 
     if(isnan(time))
-        return ret_nan();
+        return NAN;
 
     ret = fmod(floor(time/1000), 60);
     if(ret<0) ret += 60;
@@ -400,7 +402,7 @@ static inline DOUBLE ms_from_time(DOUBLE time)
     DOUBLE ret;
 
     if(isnan(time))
-        return ret_nan();
+        return NAN;
 
     ret = fmod(time, 1000);
     if(ret<0) ret += 1000;
@@ -442,7 +444,7 @@ static inline DOUBLE make_date(DOUBLE day, DOUBLE time)
 static inline DOUBLE time_clip(DOUBLE time)
 {
     if(8.64e15 < time || time < -8.64e15) {
-        return ret_nan();
+        return NAN;
     }
 
     return floor(time);
@@ -464,9 +466,8 @@ static SYSTEMTIME create_systemtime(DOUBLE time)
     return st;
 }
 
-static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, VARIANT *retv)
+static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, jsval_t *r)
 {
-    static const WCHAR NaNW[] = { 'N','a','N',0 };
     static const WCHAR formatW[] = { '%','s',' ','%','s',' ','%','d',' ',
         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
         'U','T','C','%','c','%','0','2','d','%','0','2','d',' ','%','d','%','s',0 };
@@ -490,43 +491,28 @@ static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset,
         LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
 
     BOOL formatAD = TRUE;
-    BSTR week, month;
-    BSTR date_str;
+    WCHAR week[64], month[64];
+    jsstr_t *date_str;
     int len, size, year, day;
-    DWORD lcid_en, week_id, month_id;
+    DWORD lcid_en;
     WCHAR sign = '-';
 
     if(isnan(time)) {
-        if(retv) {
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = SysAllocString(NaNW);
-            if(!V_BSTR(retv))
-                return E_OUTOFMEMORY;
-        }
+        if(r)
+            *r = jsval_string(jsstr_nan());
         return S_OK;
     }
 
-    if(retv) {
+    if(r) {
         len = 21;
 
         lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
 
-        week_id = week_ids[(int)week_day(time)];
-        size = GetLocaleInfoW(lcid_en, week_id, NULL, 0);
-        week = SysAllocStringLen(NULL, size);
-        if(!week)
-            return E_OUTOFMEMORY;
-        GetLocaleInfoW(lcid_en, week_id, week, size);
+        size = GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, sizeof(week)/sizeof(*week));
+        assert(size);
         len += size-1;
 
-        month_id = month_ids[(int)month_from_time(time)];
-        size = GetLocaleInfoW(lcid_en, month_id, NULL, 0);
-        month = SysAllocStringLen(NULL, size);
-        if(!month) {
-            SysFreeString(week);
-            return E_OUTOFMEMORY;
-        }
-        GetLocaleInfoW(lcid_en, month_id, month, size);
+        size = GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, sizeof(month)/sizeof(*month));
         len += size-1;
 
         year = year_from_time(time);
@@ -558,38 +544,31 @@ static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset,
             offset = -offset;
         }
 
-        date_str = SysAllocStringLen(NULL, len);
-        if(!date_str) {
-            SysFreeString(week);
-            SysFreeString(month);
+        date_str = jsstr_alloc_buf(len);
+        if(!date_str)
             return E_OUTOFMEMORY;
-        }
 
         if(!show_offset)
-            sprintfW(date_str, formatNoOffsetW, week, month, day,
+            sprintfW(date_str->str, formatNoOffsetW, week, month, day,
                     (int)hour_from_time(time), (int)min_from_time(time),
                     (int)sec_from_time(time), year, formatAD?ADW:BCW);
         else if(offset)
-            sprintfW(date_str, formatW, week, month, day,
+            sprintfW(date_str->str, formatW, week, month, day,
                     (int)hour_from_time(time), (int)min_from_time(time),
                     (int)sec_from_time(time), sign, offset/60, offset%60,
                     year, formatAD?ADW:BCW);
         else
-            sprintfW(date_str, formatUTCW, week, month, day,
+            sprintfW(date_str->str, formatUTCW, week, month, day,
                     (int)hour_from_time(time), (int)min_from_time(time),
                     (int)sec_from_time(time), year, formatAD?ADW:BCW);
 
-        SysFreeString(week);
-        SysFreeString(month);
-
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = date_str;
+        *r = jsval_string(date_str);
     }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.1.2 */
-static HRESULT dateobj_to_string(DateInstance *date, VARIANT *retv)
+static HRESULT dateobj_to_string(DateInstance *date, jsval_t *r)
 {
     DOUBLE time;
     int offset;
@@ -598,87 +577,78 @@ static HRESULT dateobj_to_string(DateInstance *date, VARIANT *retv)
     offset = date->bias +
         daylight_saving_ta(time, date);
 
-    return date_to_string(time, TRUE, offset, retv);
+    return date_to_string(time, TRUE, offset, r);
 }
 
-static HRESULT Date_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    return dateobj_to_string(date, retv);
+    return dateobj_to_string(date, r);
 }
 
 /* ECMA-262 3rd Edition    15.9.1.5 */
-static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    static const WCHAR NaNW[] = { 'N','a','N',0 };
     SYSTEMTIME st;
     DateInstance *date;
-    BSTR date_str;
+    jsstr_t *date_str;
     int date_len, time_len;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
     if(isnan(date->time)) {
-        if(retv) {
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = SysAllocString(NaNW);
-            if(!V_BSTR(retv))
-                return E_OUTOFMEMORY;
-        }
+        if(r)
+            *r = jsval_string(jsstr_nan());
         return S_OK;
     }
 
     st = create_systemtime(local_time(date->time, date));
 
     if(st.wYear<1601 || st.wYear>9999)
-        return dateobj_to_string(date, retv);
+        return dateobj_to_string(date, r);
 
-    if(retv) {
+    if(r) {
         date_len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
         time_len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
-        date_str = SysAllocStringLen(NULL, date_len+time_len-1);
+        date_str = jsstr_alloc_buf(date_len+time_len-1);
         if(!date_str)
             return E_OUTOFMEMORY;
-        GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, date_str, date_len);
-        GetTimeFormatW(ctx->lcid, 0, &st, NULL, &date_str[date_len], time_len);
-        date_str[date_len-1] = ' ';
+        GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, date_str->str, date_len);
+        GetTimeFormatW(ctx->lcid, 0, &st, NULL, date_str->str+date_len, time_len);
+        date_str->str[date_len-1] = ' ';
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = date_str;
+        *r = jsval_string(date_str);
     }
     return S_OK;
 }
 
-static HRESULT Date_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv)
-        num_set_val(retv, date->time);
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
-static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis,
-        VARIANT *retv, jsexcept_t *ei)
+static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r)
 {
-    static const WCHAR NaNW[] = { 'N','a','N',0 };
     static const WCHAR formatADW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ',
         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
     static const WCHAR formatBCW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ','B','.','C','.',' ',
@@ -695,46 +665,30 @@ static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis,
         LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
 
     BOOL formatAD = TRUE;
-    BSTR week, month;
+    WCHAR week[64], month[64];
     DateInstance *date;
-    BSTR date_str;
+    jsstr_t *date_str;
     int len, size, year, day;
-    DWORD lcid_en, week_id, month_id;
+    DWORD lcid_en;
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
     if(isnan(date->time)) {
-        if(retv) {
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = SysAllocString(NaNW);
-            if(!V_BSTR(retv))
-                return E_OUTOFMEMORY;
-        }
+        if(r)
+            *r = jsval_string(jsstr_nan());
         return S_OK;
     }
 
-    if(retv) {
+    if(r) {
         len = 17;
 
         lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
 
-        week_id = week_ids[(int)week_day(date->time)];
-        size = GetLocaleInfoW(lcid_en, week_id, NULL, 0);
-        week = SysAllocStringLen(NULL, size);
-        if(!week)
-            return E_OUTOFMEMORY;
-        GetLocaleInfoW(lcid_en, week_id, week, size);
+        size = GetLocaleInfoW(lcid_en, week_ids[(int)week_day(date->time)], week, sizeof(week)/sizeof(*week));
         len += size-1;
 
-        month_id = month_ids[(int)month_from_time(date->time)];
-        size = GetLocaleInfoW(lcid_en, month_id, NULL, 0);
-        month = SysAllocStringLen(NULL, size);
-        if(!month) {
-            SysFreeString(week);
-            return E_OUTOFMEMORY;
-        }
-        GetLocaleInfoW(lcid_en, month_id, month, size);
+        size = GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(date->time)], month, sizeof(month)/sizeof(*month));
         len += size-1;
 
         year = year_from_time(date->time);
@@ -759,44 +713,37 @@ static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis,
         } while(day);
         day = date_from_time(date->time);
 
-        date_str = SysAllocStringLen(NULL, len);
-        if(!date_str) {
-            SysFreeString(week);
-            SysFreeString(month);
+        date_str = jsstr_alloc_buf(len);
+        if(!date_str)
             return E_OUTOFMEMORY;
-        }
-        sprintfW(date_str, formatAD?formatADW:formatBCW, week, day, month, year,
+
+        sprintfW(date_str->str, formatAD?formatADW:formatBCW, week, day, month, year,
                 (int)hour_from_time(date->time), (int)min_from_time(date->time),
                 (int)sec_from_time(date->time));
 
-        SysFreeString(week);
-        SysFreeString(month);
-
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = date_str;
+        *r = jsval_string(date_str);
     }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.42 */
-static HRESULT Date_toUTCString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_toUTCString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
-    return create_utc_string(ctx, jsthis, retv, ei);
+    return create_utc_string(ctx, jsthis, r);
 }
 
-static HRESULT Date_toGMTString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_toGMTString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
-    return create_utc_string(ctx, jsthis, retv, ei);
+    return create_utc_string(ctx, jsthis, r);
 }
 
 /* ECMA-262 3rd Edition    15.9.5.3 */
-static HRESULT dateobj_to_date_string(DateInstance *date, VARIANT *retv)
+static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r)
 {
-    static const WCHAR NaNW[] = { 'N','a','N',0 };
     static const WCHAR formatADW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',0 };
     static const WCHAR formatBCW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',' ','B','.','C','.',0 };
 
@@ -811,45 +758,31 @@ static HRESULT dateobj_to_date_string(DateInstance *date, VARIANT *retv)
         LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
 
     BOOL formatAD = TRUE;
-    BSTR week, month;
-    BSTR date_str;
+    WCHAR week[64], month[64];
+    jsstr_t *date_str;
     DOUBLE time;
     int len, size, year, day;
-    DWORD lcid_en, week_id, month_id;
+    DWORD lcid_en;
 
     if(isnan(date->time)) {
-        if(retv) {
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = SysAllocString(NaNW);
-            if(!V_BSTR(retv))
-                return E_OUTOFMEMORY;
-        }
+        if(r)
+            *r = jsval_string(jsstr_nan());
         return S_OK;
     }
 
     time = local_time(date->time, date);
 
-    if(retv) {
+    if(r) {
         len = 5;
 
         lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
 
-        week_id = week_ids[(int)week_day(time)];
-        size = GetLocaleInfoW(lcid_en, week_id, NULL, 0);
-        week = SysAllocStringLen(NULL, size);
-        if(!week)
-            return E_OUTOFMEMORY;
-        GetLocaleInfoW(lcid_en, week_id, week, size);
+        size = GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, sizeof(week)/sizeof(*week));
+        assert(size);
         len += size-1;
 
-        month_id = month_ids[(int)month_from_time(time)];
-        size = GetLocaleInfoW(lcid_en, month_id, NULL, 0);
-        month = SysAllocStringLen(NULL, size);
-        if(!month) {
-            SysFreeString(week);
-            return E_OUTOFMEMORY;
-        }
-        GetLocaleInfoW(lcid_en, month_id, month, size);
+        size = GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, sizeof(month)/sizeof(*month));
+        assert(size);
         len += size-1;
 
         year = year_from_time(time);
@@ -874,45 +807,37 @@ static HRESULT dateobj_to_date_string(DateInstance *date, VARIANT *retv)
         } while(day);
         day = date_from_time(time);
 
-        date_str = SysAllocStringLen(NULL, len);
-        if(!date_str) {
-            SysFreeString(week);
-            SysFreeString(month);
+        date_str = jsstr_alloc_buf(len);
+        if(!date_str)
             return E_OUTOFMEMORY;
-        }
-        sprintfW(date_str, formatAD?formatADW:formatBCW, week, month, day, year);
+        sprintfW(date_str->str, formatAD?formatADW:formatBCW, week, month, day, year);
 
-        SysFreeString(week);
-        SysFreeString(month);
-
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = date_str;
+        *r = jsval_string(date_str);
     }
     return S_OK;
 }
 
-static HRESULT Date_toDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_toDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    return dateobj_to_date_string(date, retv);
+    return dateobj_to_date_string(date, r);
 }
 
 /* ECMA-262 3rd Edition    15.9.5.4 */
-static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    static const WCHAR NaNW[] = { 'N','a','N',0 };
     static const WCHAR formatW[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',
         ' ','U','T','C','%','c','%','0','2','d','%','0','2','d',0 };
     static const WCHAR formatUTCW[] = { '%','0','2','d',':','%','0','2','d',
         ':','%','0','2','d',' ','U','T','C',0 };
     DateInstance *date;
-    BSTR date_str;
+    jsstr_t *date_str;
     DOUBLE time;
     WCHAR sign;
     int offset;
@@ -920,22 +845,18 @@ static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
     if(isnan(date->time)) {
-        if(retv) {
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = SysAllocString(NaNW);
-            if(!V_BSTR(retv))
-                return E_OUTOFMEMORY;
-        }
+        if(r)
+            *r = jsval_string(jsstr_nan());
         return S_OK;
     }
 
     time = local_time(date->time, date);
 
-    if(retv) {
-        date_str = SysAllocStringLen(NULL, 17);
+    if(r) {
+        date_str = jsstr_alloc_buf(17);
         if(!date_str)
             return E_OUTOFMEMORY;
 
@@ -949,1057 +870,978 @@ static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         else sign = '-';
 
         if(offset)
-            sprintfW(date_str, formatW, (int)hour_from_time(time),
+            sprintfW(date_str->str, formatW, (int)hour_from_time(time),
                     (int)min_from_time(time), (int)sec_from_time(time),
                     sign, offset/60, offset%60);
         else
-            sprintfW(date_str, formatUTCW, (int)hour_from_time(time),
+            sprintfW(date_str->str, formatUTCW, (int)hour_from_time(time),
                     (int)min_from_time(time), (int)sec_from_time(time));
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = date_str;
+        *r = jsval_string(date_str);
     }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.6 */
-static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    static const WCHAR NaNW[] = { 'N','a','N',0 };
     SYSTEMTIME st;
     DateInstance *date;
-    BSTR date_str;
+    jsstr_t *date_str;
     int len;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
     if(isnan(date->time)) {
-        if(retv) {
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = SysAllocString(NaNW);
-            if(!V_BSTR(retv))
-                return E_OUTOFMEMORY;
-        }
+        if(r)
+            *r = jsval_string(jsstr_nan());
         return S_OK;
     }
 
     st = create_systemtime(local_time(date->time, date));
 
     if(st.wYear<1601 || st.wYear>9999)
-        return dateobj_to_date_string(date, retv);
+        return dateobj_to_date_string(date, r);
 
-    if(retv) {
+    if(r) {
         len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
-        date_str = SysAllocStringLen(NULL, len);
+        date_str = jsstr_alloc_buf(len);
         if(!date_str)
             return E_OUTOFMEMORY;
-        GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, date_str, len);
+        GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, date_str->str, len);
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = date_str;
+        *r = jsval_string(date_str);
     }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.7 */
-static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    static const WCHAR NaNW[] = { 'N','a','N',0 };
     SYSTEMTIME st;
     DateInstance *date;
-    BSTR date_str;
+    jsstr_t *date_str;
     int len;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
     if(isnan(date->time)) {
-        if(retv) {
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = SysAllocString(NaNW);
-            if(!V_BSTR(retv))
-                return E_OUTOFMEMORY;
-        }
+        if(r)
+            *r = jsval_string(jsstr_nan());
         return S_OK;
     }
 
     st = create_systemtime(local_time(date->time, date));
 
     if(st.wYear<1601 || st.wYear>9999)
-        return Date_toTimeString(ctx, jsthis, flags, dp, retv, ei, caller);
+        return Date_toTimeString(ctx, jsthis, flags, argc, argv, r);
 
-    if(retv) {
+    if(r) {
         len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
-        date_str = SysAllocStringLen(NULL, len);
+        date_str = jsstr_alloc_buf(len);
         if(!date_str)
             return E_OUTOFMEMORY;
-        GetTimeFormatW(ctx->lcid, 0, &st, NULL, date_str, len);
+        GetTimeFormatW(ctx->lcid, 0, &st, NULL, date_str->str, len);
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = date_str;
+        *r = jsval_string(date_str);
     }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.9 */
-static HRESULT Date_getTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv)
-        num_set_val(retv, date->time);
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.10 */
-static HRESULT Date_getFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv) {
+    if(r) {
         DOUBLE time = local_time(date->time, date);
 
-        num_set_val(retv, year_from_time(time));
+        *r = jsval_number(year_from_time(time));
     }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.11 */
-static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv)
-        num_set_val(retv, year_from_time(date->time));
+    if(r)
+        *r = jsval_number(year_from_time(date->time));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.12 */
-static HRESULT Date_getMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv) {
-        DOUBLE time = local_time(date->time, date);
-
-        num_set_val(retv, month_from_time(time));
-    }
+    if(r)
+        *r = jsval_number(month_from_time(local_time(date->time, date)));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.13 */
-static HRESULT Date_getUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv)
-        num_set_val(retv, month_from_time(date->time));
+    if(r)
+        *r = jsval_number(month_from_time(date->time));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.14 */
-static HRESULT Date_getDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv) {
-        DOUBLE time = local_time(date->time, date);
-
-        num_set_val(retv, date_from_time(time));
-    }
+    if(r)
+        *r = jsval_number(date_from_time(local_time(date->time, date)));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.15 */
-static HRESULT Date_getUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv)
-        num_set_val(retv, date_from_time(date->time));
+    if(r)
+        *r = jsval_number(date_from_time(date->time));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.16 */
-static HRESULT Date_getDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
-
-    if(retv) {
-        DOUBLE time = local_time(date->time, date);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-        num_set_val(retv, week_day(time));
-    }
+    if(r)
+        *r = jsval_number(week_day(local_time(date->time, date)));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.17 */
-static HRESULT Date_getUTCDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getUTCDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv)
-        num_set_val(retv, week_day(date->time));
+    if(r)
+        *r = jsval_number(week_day(date->time));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.18 */
-static HRESULT Date_getHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv) {
-        DOUBLE time = local_time(date->time, date);
-
-        num_set_val(retv, hour_from_time(time));
-    }
+    if(r)
+        *r = jsval_number(hour_from_time(local_time(date->time, date)));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.19 */
-static HRESULT Date_getUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv)
-        num_set_val(retv, hour_from_time(date->time));
+    if(r)
+        *r = jsval_number(hour_from_time(date->time));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.20 */
-static HRESULT Date_getMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv) {
-        DOUBLE time = local_time(date->time, date);
-
-        num_set_val(retv, min_from_time(time));
-    }
+    if(r)
+        *r = jsval_number(min_from_time(local_time(date->time, date)));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.21 */
-static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv)
-        num_set_val(retv, min_from_time(date->time));
+    if(r)
+        *r = jsval_number(min_from_time(date->time));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.22 */
-static HRESULT Date_getSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
-
-    if(retv) {
-        DOUBLE time = local_time(date->time, date);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-        num_set_val(retv, sec_from_time(time));
-    }
+    if(r)
+        *r = jsval_number(sec_from_time(local_time(date->time, date)));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.23 */
-static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv)
-        num_set_val(retv, sec_from_time(date->time));
+    if(r)
+        *r = jsval_number(sec_from_time(date->time));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.24 */
-static HRESULT Date_getMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv) {
-        DOUBLE time = local_time(date->time, date);
-
-        num_set_val(retv, ms_from_time(time));
-    }
+    if(r)
+        *r = jsval_number(ms_from_time(local_time(date->time, date)));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.25 */
-static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv)
-        num_set_val(retv, ms_from_time(date->time));
+    if(r)
+        *r = jsval_number(ms_from_time(date->time));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.26 */
-static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(retv)
-        num_set_val(retv, floor(
-                    (date->time-local_time(date->time, date))/MS_PER_MINUTE));
+    if(r)
+        *r = jsval_number(floor((date->time-local_time(date->time, date))/MS_PER_MINUTE));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.27 */
-static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double n;
     HRESULT hres;
     DateInstance *date;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &n);
     if(FAILED(hres))
         return hres;
 
-    date->time = time_clip(num_val(&v));
-
-    if(retv)
-        num_set_val(retv, date->time);
+    date->time = time_clip(n);
 
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.28 */
-static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t;
+    double n, t;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &n);
     if(FAILED(hres))
         return hres;
 
     t = local_time(date->time, date);
     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
-                sec_from_time(t), num_val(&v)));
+                sec_from_time(t), n));
     date->time = time_clip(utc(t, date));
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.29 */
-static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t;
+    double n, t;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &n);
     if(FAILED(hres))
         return hres;
 
     t = date->time;
     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
-                sec_from_time(t), num_val(&v)));
+                sec_from_time(t), n));
     date->time = time_clip(t);
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.30 */
-static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t, sec, ms;
+    double t, sec, ms;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
     t = local_time(date->time, date);
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &sec);
     if(FAILED(hres))
         return hres;
-    sec = num_val(&v);
 
-    if(arg_cnt(dp) > 1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &v);
+    if(argc > 1) {
+        hres = to_number(ctx, argv[1], &ms);
         if(FAILED(hres))
             return hres;
-        ms = num_val(&v);
+    }else {
+        ms = ms_from_time(t);
     }
-    else ms = ms_from_time(t);
 
     t = make_date(day(t), make_time(hour_from_time(t),
                 min_from_time(t), sec, ms));
     date->time = time_clip(utc(t, date));
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.31 */
-static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t, sec, ms;
+    double t, sec, ms;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
     t = date->time;
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &sec);
     if(FAILED(hres))
         return hres;
-    sec = num_val(&v);
 
-    if(arg_cnt(dp) > 1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &v);
+    if(argc > 1) {
+        hres = to_number(ctx, argv[1], &ms);
         if(FAILED(hres))
             return hres;
-        ms = num_val(&v);
+    }else {
+        ms = ms_from_time(t);
     }
-    else ms = ms_from_time(t);
 
     t = make_date(day(t), make_time(hour_from_time(t),
                 min_from_time(t), sec, ms));
     date->time = time_clip(t);
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.33 */
-static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t, min, sec, ms;
+    double t, min, sec, ms;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
     t = local_time(date->time, date);
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &min);
     if(FAILED(hres))
         return hres;
-    min = num_val(&v);
 
-    if(arg_cnt(dp) > 1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &v);
+    if(argc > 1) {
+        hres = to_number(ctx, argv[1], &sec);
         if(FAILED(hres))
             return hres;
-        sec = num_val(&v);
+    }else {
+        sec = sec_from_time(t);
     }
-    else sec = sec_from_time(t);
 
-    if(arg_cnt(dp) > 2) {
-        hres = to_number(ctx, get_arg(dp, 2), ei, &v);
+    if(argc > 2) {
+        hres = to_number(ctx, argv[2], &ms);
         if(FAILED(hres))
             return hres;
-        ms = num_val(&v);
+    }else {
+        ms = ms_from_time(t);
     }
-    else ms = ms_from_time(t);
 
     t = make_date(day(t), make_time(hour_from_time(t),
                 min, sec, ms));
     date->time = time_clip(utc(t, date));
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.34 */
-static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t, min, sec, ms;
+    double t, min, sec, ms;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
     t = date->time;
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &min);
     if(FAILED(hres))
         return hres;
-    min = num_val(&v);
 
-    if(arg_cnt(dp) > 1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &v);
+    if(argc > 1) {
+        hres = to_number(ctx, argv[1], &sec);
         if(FAILED(hres))
             return hres;
-        sec = num_val(&v);
+    }else {
+        sec = sec_from_time(t);
     }
-    else sec = sec_from_time(t);
 
-    if(arg_cnt(dp) > 2) {
-        hres = to_number(ctx, get_arg(dp, 2), ei, &v);
+    if(argc > 2) {
+        hres = to_number(ctx, argv[2], &ms);
         if(FAILED(hres))
             return hres;
-        ms = num_val(&v);
+    }else {
+        ms = ms_from_time(t);
     }
-    else ms = ms_from_time(t);
 
     t = make_date(day(t), make_time(hour_from_time(t),
                 min, sec, ms));
     date->time = time_clip(t);
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.35 */
-static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t, hour, min, sec, ms;
+    double t, hour, min, sec, ms;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
     t = local_time(date->time, date);
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &hour);
     if(FAILED(hres))
         return hres;
-    hour = num_val(&v);
 
-    if(arg_cnt(dp) > 1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &v);
+    if(argc > 1) {
+        hres = to_number(ctx, argv[1], &min);
         if(FAILED(hres))
             return hres;
-        min = num_val(&v);
+    }else {
+        min = min_from_time(t);
     }
-    else min = min_from_time(t);
 
-    if(arg_cnt(dp) > 2) {
-        hres = to_number(ctx, get_arg(dp, 2), ei, &v);
+    if(argc > 2) {
+        hres = to_number(ctx, argv[2], &sec);
         if(FAILED(hres))
             return hres;
-        sec = num_val(&v);
+    }else {
+        sec = sec_from_time(t);
     }
-    else sec = sec_from_time(t);
 
-    if(arg_cnt(dp) > 3) {
-        hres = to_number(ctx, get_arg(dp, 3), ei, &v);
+    if(argc > 3) {
+        hres = to_number(ctx, argv[3], &ms);
         if(FAILED(hres))
             return hres;
-        ms = num_val(&v);
+    }else {
+        ms = ms_from_time(t);
     }
-    else ms = ms_from_time(t);
 
     t = make_date(day(t), make_time(hour, min, sec, ms));
     date->time = time_clip(utc(t, date));
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.36 */
-static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
-    VARIANT v;
+    double t, hour, min, sec, ms;
     HRESULT hres;
-    DOUBLE t, hour, min, sec, ms;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
     t = date->time;
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &hour);
     if(FAILED(hres))
         return hres;
-    hour = num_val(&v);
 
-    if(arg_cnt(dp) > 1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &v);
+    if(argc > 1) {
+        hres = to_number(ctx, argv[1], &min);
         if(FAILED(hres))
             return hres;
-        min = num_val(&v);
+    }else {
+        min = min_from_time(t);
     }
-    else min = min_from_time(t);
 
-    if(arg_cnt(dp) > 2) {
-        hres = to_number(ctx, get_arg(dp, 2), ei, &v);
+    if(argc > 2) {
+        hres = to_number(ctx, argv[2], &sec);
         if(FAILED(hres))
             return hres;
-        sec = num_val(&v);
+    }else {
+        sec = sec_from_time(t);
     }
-    else sec = sec_from_time(t);
 
-    if(arg_cnt(dp) > 3) {
-        hres = to_number(ctx, get_arg(dp, 3), ei, &v);
+    if(argc > 3) {
+        hres = to_number(ctx, argv[3], &ms);
         if(FAILED(hres))
             return hres;
-        ms = num_val(&v);
+    }else {
+        ms = ms_from_time(t);
     }
-    else ms = ms_from_time(t);
 
     t = make_date(day(t), make_time(hour, min, sec, ms));
     date->time = time_clip(t);
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.36 */
-static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t;
+    double t, n;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &n);
     if(FAILED(hres))
         return hres;
 
     t = local_time(date->time, date);
-    t = make_date(make_day(year_from_time(t), month_from_time(t),
-                num_val(&v)), time_within_day(t));
+    t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
     date->time = time_clip(utc(t, date));
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.37 */
-static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t;
+    double t, n;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &n);
     if(FAILED(hres))
         return hres;
 
     t = date->time;
-    t = make_date(make_day(year_from_time(t), month_from_time(t),
-                num_val(&v)), time_within_day(t));
+    t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
     date->time = time_clip(t);
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.38 */
-static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
     DOUBLE t, month, ddate;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
     t = local_time(date->time, date);
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &month);
     if(FAILED(hres))
         return hres;
-    month = num_val(&v);
 
-    if(arg_cnt(dp) > 1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &v);
+    if(argc > 1) {
+        hres = to_number(ctx, argv[1], &ddate);
         if(FAILED(hres))
             return hres;
-        ddate = num_val(&v);
+    }else {
+        ddate = date_from_time(t);
     }
-    else ddate = date_from_time(t);
 
     t = make_date(make_day(year_from_time(t), month, ddate),
             time_within_day(t));
     date->time = time_clip(utc(t, date));
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.39 */
-static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t, month, ddate;
+    double t, month, ddate;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
     t = date->time;
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &month);
     if(FAILED(hres))
         return hres;
-    month = num_val(&v);
 
-    if(arg_cnt(dp) > 1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &v);
+    if(argc > 1) {
+        hres = to_number(ctx, argv[1], &ddate);
         if(FAILED(hres))
             return hres;
-        ddate = num_val(&v);
+    }else {
+        ddate = date_from_time(t);
     }
-    else ddate = date_from_time(t);
 
     t = make_date(make_day(year_from_time(t), month, ddate),
             time_within_day(t));
     date->time = time_clip(t);
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.40 */
-static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t, year, month, ddate;
+    double t, year, month, ddate;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
     t = local_time(date->time, date);
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &year);
     if(FAILED(hres))
         return hres;
-    year = num_val(&v);
 
-    if(arg_cnt(dp) > 1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &v);
+    if(argc > 1) {
+        hres = to_number(ctx, argv[1], &month);
         if(FAILED(hres))
             return hres;
-        month = num_val(&v);
+    }else {
+        month = month_from_time(t);
     }
-    else month = month_from_time(t);
 
-    if(arg_cnt(dp) > 2) {
-        hres = to_number(ctx, get_arg(dp, 2), ei, &v);
+    if(argc > 2) {
+        hres = to_number(ctx, argv[2], &ddate);
         if(FAILED(hres))
             return hres;
-        ddate = num_val(&v);
+    }else {
+        ddate = date_from_time(t);
     }
-    else ddate = date_from_time(t);
 
     t = make_date(make_day(year, month, ddate), time_within_day(t));
     date->time = time_clip(utc(t, date));
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.9.5.41 */
-static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    HRESULT hres;
     DateInstance *date;
-    DOUBLE t, year, month, ddate;
+    double t, year, month, ddate;
+    HRESULT hres;
 
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
-    if(!arg_cnt(dp))
-        return throw_type_error(ctx, ei, IDS_ARG_NOT_OPT, NULL);
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
 
     t = date->time;
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &year);
     if(FAILED(hres))
         return hres;
-    year = num_val(&v);
 
-    if(arg_cnt(dp) > 1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &v);
+    if(argc > 1) {
+        hres = to_number(ctx, argv[1], &month);
         if(FAILED(hres))
             return hres;
-        month = num_val(&v);
+    }else {
+        month = month_from_time(t);
     }
-    else month = month_from_time(t);
 
-    if(arg_cnt(dp) > 2) {
-        hres = to_number(ctx, get_arg(dp, 2), ei, &v);
+    if(argc > 2) {
+        hres = to_number(ctx, argv[2], &ddate);
         if(FAILED(hres))
             return hres;
-        ddate = num_val(&v);
+    }else {
+        ddate = date_from_time(t);
     }
-    else ddate = date_from_time(t);
 
     t = make_date(make_day(year, month, ddate), time_within_day(t));
     date->time = time_clip(t);
 
-    if(retv)
-        num_set_val(retv, date->time);
-
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    B2.4 */
-static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DateInstance *date;
     DOUBLE t, year;
@@ -2007,30 +1849,69 @@ static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
     TRACE("\n");
 
     if(!(date = date_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_DATE, NULL);
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
 
     t = local_time(date->time, date);
     if(isnan(t)) {
-        if(retv)
-            num_set_nan(retv);
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
     year = year_from_time(t);
-    if(retv)
-        num_set_val(retv, (1900<=year && year<2000)?year-1900:year);
+    if(r)
+        *r = jsval_number((1900<=year && year<2000)?year-1900:year);
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    B2.5 */
+static HRESULT Date_setYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    DateInstance *date;
+    DOUBLE t, year;
+    HRESULT hres;
 
+    TRACE("\n");
+
+    if(!(date = date_this(jsthis)))
+        return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
+
+    if(!argc)
+        return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
+
+    t = local_time(date->time, date);
+
+    hres = to_number(ctx, argv[0], &year);
+    if(FAILED(hres))
+        return hres;
+
+    if(isnan(year)) {
+        date->time = year;
+        if(r)
+            *r = jsval_number(NAN);
+        return S_OK;
+    }
+
+    year = year >= 0.0 ? floor(year) : -floor(-year);
+    if(-1.0 < year && year < 100.0)
+        year += 1900.0;
+
+    date->time = time_clip(utc(make_date(make_day(year, month_from_time(t), date_from_time(t)), time_within_day(t)), date));
+
+    if(r)
+        *r = jsval_number(date->time);
     return S_OK;
 }
 
-static HRESULT Date_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Date_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
     switch(flags) {
     case INVOKE_FUNC:
-        return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
+        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
     default:
         FIXME("unimplemented flags %x\n", flags);
         return E_NOTIMPL;
@@ -2074,6 +1955,7 @@ static const builtin_prop_t Date_props[] = {
     {setUTCMinutesW,         Date_setUTCMinutes,         PROPF_METHOD|3},
     {setUTCMonthW,           Date_setUTCMonth,           PROPF_METHOD|2},
     {setUTCSecondsW,         Date_setUTCSeconds,         PROPF_METHOD|2},
+    {setYearW,               Date_setYear,               PROPF_METHOD|1},
     {toDateStringW,          Date_toDateString,          PROPF_METHOD},
     {toGMTStringW,           Date_toGMTString,           PROPF_METHOD},
     {toLocaleDateStringW,    Date_toLocaleDateString,    PROPF_METHOD},
@@ -2094,7 +1976,15 @@ static const builtin_info_t Date_info = {
     NULL
 };
 
-static HRESULT create_date(script_ctx_t *ctx, DispatchEx *object_prototype, DOUBLE time, DispatchEx **ret)
+static const builtin_info_t DateInst_info = {
+    JSCLASS_DATE,
+    {NULL, Date_value, 0},
+    0, NULL,
+    NULL,
+    NULL
+};
+
+static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, jsdisp_t **ret)
 {
     DateInstance *date;
     HRESULT hres;
@@ -2109,7 +1999,7 @@ static HRESULT create_date(script_ctx_t *ctx, DispatchEx *object_prototype, DOUB
     if(object_prototype)
         hres = init_dispex(&date->dispex, ctx, &Date_info, object_prototype);
     else
-        hres = init_dispex_from_constr(&date->dispex, ctx, &Date_info, ctx->date_constr);
+        hres = init_dispex_from_constr(&date->dispex, ctx, &DateInst_info, ctx->date_constr);
     if(FAILED(hres)) {
         heap_free(date);
         return hres;
@@ -2126,7 +2016,7 @@ static HRESULT create_date(script_ctx_t *ctx, DispatchEx *object_prototype, DOUB
     return S_OK;
 }
 
-static inline HRESULT date_parse(BSTR input, VARIANT *retv) {
+static inline HRESULT date_parse(jsstr_t *input_str, double *ret) {
     static const DWORD string_ids[] = { LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME11,
         LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME8,
         LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME5,
@@ -2134,9 +2024,8 @@ static inline HRESULT date_parse(BSTR input, VARIANT *retv) {
         LOCALE_SMONTHNAME1, LOCALE_SDAYNAME7, LOCALE_SDAYNAME1,
         LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
         LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 };
-    BSTR strings[sizeof(string_ids)/sizeof(DWORD)];
-
-    BSTR parse;
+    WCHAR *strings[sizeof(string_ids)/sizeof(DWORD)];
+    WCHAR *parse;
     int input_len, parse_len = 0, nest_level = 0, i, size;
     int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
     int ms = 0, offset = 0, hour_adjust = 0;
@@ -2144,23 +2033,26 @@ static inline HRESULT date_parse(BSTR input, VARIANT *retv) {
     BOOL set_offset = FALSE, set_era = FALSE, ad = TRUE, set_am = FALSE, am = TRUE;
     BOOL set_hour_adjust = TRUE;
     TIME_ZONE_INFORMATION tzi;
+    const WCHAR *input;
     DateInstance di;
     DWORD lcid_en;
 
-    if(retv) num_set_nan(retv);
+    input_len = jsstr_length(input_str);
+    input = input_str->str;
 
-    input_len = SysStringLen(input);
     for(i=0; i<input_len; i++) {
         if(input[i] == '(') nest_level++;
         else if(input[i] == ')') {
             nest_level--;
-            if(nest_level<0)
+            if(nest_level<0) {
+                *ret = NAN;
                 return S_OK;
+            }
         }
         else if(!nest_level) parse_len++;
     }
 
-    parse = SysAllocStringLen(NULL, parse_len);
+    parse = heap_alloc((parse_len+1)*sizeof(WCHAR));
     if(!parse)
         return E_OUTOFMEMORY;
     nest_level = 0;
@@ -2170,6 +2062,7 @@ static inline HRESULT date_parse(BSTR input, VARIANT *retv) {
         else if(input[i] == ')') nest_level--;
         else if(!nest_level) parse[parse_len++] = toupperW(input[i]);
     }
+    parse[parse_len] = 0;
 
     GetTimeZoneInformation(&tzi);
     di.bias = tzi.Bias;
@@ -2178,15 +2071,16 @@ static inline HRESULT date_parse(BSTR input, VARIANT *retv) {
     di.daylightDate = tzi.DaylightDate;
     di.daylightBias = tzi.DaylightBias;
 
+    /* FIXME: Cache strings */
     lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
     for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++) {
         size = GetLocaleInfoW(lcid_en, string_ids[i], NULL, 0);
-        strings[i] = SysAllocStringLen(NULL, size);
+        strings[i] = heap_alloc((size+1)*sizeof(WCHAR));
         if(!strings[i]) {
             i--;
             while(i-- >= 0)
-                SysFreeString(strings[i]);
-            SysFreeString(parse);
+                heap_free(strings[i]);
+            heap_free(parse);
             return E_OUTOFMEMORY;
         }
         GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size);
@@ -2342,13 +2236,13 @@ static inline HRESULT date_parse(BSTR input, VARIANT *retv) {
             }
             else {
                 /* Month or garbage */
-                int j;
+                unsigned int j;
 
                 for(size=i; parse[size]>='A' && parse[size]<='Z'; size++);
                 size -= i;
 
                 for(j=0; j<sizeof(string_ids)/sizeof(DWORD); j++)
-                    if(!memicmpW(&parse[i], strings[j], size)) break;
+                    if(!strncmpiW(&parse[i], strings[j], size)) break;
 
                 if(j < 12) {
                     if(set_month) break;
@@ -2362,8 +2256,7 @@ static inline HRESULT date_parse(BSTR input, VARIANT *retv) {
         }
     }
 
-    if(retv && i==parse_len && set_year && set_month
-            && set_day && (!set_am || hour<13)) {
+    if(i == parse_len && set_year && set_month && set_day && (!set_am || hour<13)) {
         if(set_am) {
             if(hour == 12) hour = 0;
             if(!am) hour += 12;
@@ -2372,153 +2265,145 @@ static inline HRESULT date_parse(BSTR input, VARIANT *retv) {
         if(!ad) year = -year+1;
         else if(year<100) year += 1900;
 
-        V_VT(retv) = VT_R8;
-        V_R8(retv) = time_clip(make_date(make_day(year, month, day),
+        *ret = time_clip(make_date(make_day(year, month, day),
                     make_time(hour+hour_adjust, min, sec, ms)) + offset*MS_PER_MINUTE);
 
-        if(set_hour_adjust) V_R8(retv) = utc(V_R8(retv), &di);
+        if(set_hour_adjust)
+            *ret = utc(*ret, &di);
+    }else {
+        *ret = NAN;
     }
 
     for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++)
-        SysFreeString(strings[i]);
-    SysFreeString(parse);
+        heap_free(strings[i]);
+    heap_free(parse);
 
     return S_OK;
 }
 
-static HRESULT DateConstr_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT DateConstr_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    BSTR parse_str;
+    jsstr_t *parse_str;
+    double n;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv)
-            num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_string(ctx, get_arg(dp,0), ei, &parse_str);
+    hres = to_string(ctx, argv[0], &parse_str);
     if(FAILED(hres))
         return hres;
 
-    hres = date_parse(parse_str, retv);
+    hres = date_parse(parse_str, &n);
+    jsstr_release(parse_str);
+    if(FAILED(hres))
+        return hres;
 
-    SysFreeString(parse_str);
-    return hres;
+    *r = jsval_number(n);
+    return S_OK;
 }
 
-static HRESULT date_utc(script_ctx_t *ctx, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei)
+static HRESULT date_utc(script_ctx_t *ctx, unsigned argc, jsval_t *argv, double *ret)
 {
-    VARIANT year, month, vdate, hours, minutes, seconds, ms;
-    DOUBLE y;
-    int arg_no = arg_cnt(dp);
+    double year, month, vdate, hours, minutes, seconds, ms;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(arg_no>0) {
-        hres = to_number(ctx, get_arg(dp, 0), ei, &year);
+    if(argc) {
+        hres = to_number(ctx, argv[0], &year);
         if(FAILED(hres))
             return hres;
-        y = num_val(&year);
-        if(0<=y && y<=99)
-            y += 1900;
+        if(0 <= year && year <= 99)
+            year += 1900;
+    }else {
+        year = 1900;
     }
-    else y = 1900;
 
-    if(arg_no>1) {
-        hres = to_number(ctx, get_arg(dp, 1), ei, &month);
+    if(argc>1) {
+        hres = to_number(ctx, argv[1], &month);
         if(FAILED(hres))
             return hres;
-    }
-    else {
-        V_VT(&month) = VT_R8;
-        V_R8(&month) = 0;
+    }else {
+        month = 0;
     }
 
-    if(arg_no>2) {
-        hres = to_number(ctx, get_arg(dp, 2), ei, &vdate);
+    if(argc>2) {
+        hres = to_number(ctx, argv[2], &vdate);
         if(FAILED(hres))
             return hres;
-    }
-    else {
-        V_VT(&vdate) = VT_R8;
-        V_R8(&vdate) = 1;
+    }else {
+        vdate = 1;
     }
 
-    if(arg_no>3) {
-        hres = to_number(ctx, get_arg(dp, 3), ei, &hours);
+    if(argc>3) {
+        hres = to_number(ctx, argv[3], &hours);
         if(FAILED(hres))
             return hres;
-    }
-    else {
-        V_VT(&hours) = VT_R8;
-        V_R8(&hours) = 0;
+    }else {
+        hours = 0;
     }
 
-    if(arg_no>4) {
-        hres = to_number(ctx, get_arg(dp, 4), ei, &minutes);
+    if(argc>4) {
+        hres = to_number(ctx, argv[4], &minutes);
         if(FAILED(hres))
             return hres;
-    }
-    else {
-        V_VT(&minutes) = VT_R8;
-        V_R8(&minutes) = 0;
+    }else {
+        minutes = 0;
     }
 
-    if(arg_no>5) {
-        hres = to_number(ctx, get_arg(dp, 5), ei, &seconds);
+    if(argc>5) {
+        hres = to_number(ctx, argv[5], &seconds);
         if(FAILED(hres))
             return hres;
-    }
-    else {
-        V_VT(&seconds) = VT_R8;
-        V_R8(&seconds) = 0;
+    }else {
+        seconds = 0;
     }
 
-    if(arg_no>6) {
-        hres = to_number(ctx, get_arg(dp, 6), ei, &ms);
+    if(argc>6) {
+        hres = to_number(ctx, argv[6], &ms);
         if(FAILED(hres))
             return hres;
-    }
-    else {
-        V_VT(&ms) = VT_R8;
-        V_R8(&ms) = 0;
-    }
-
-    if(retv) {
-        V_VT(retv) = VT_R8;
-        V_R8(retv) = time_clip(make_date(
-                    make_day(y, num_val(&month), num_val(&vdate)),
-                    make_time(num_val(&hours), num_val(&minutes),
-                    num_val(&seconds), num_val(&ms))));
+    } else {
+        ms = 0;
     }
 
+    *ret = time_clip(make_date(make_day(year, month, vdate),
+            make_time(hours, minutes,seconds, ms)));
     return S_OK;
 }
 
-static HRESULT DateConstr_UTC(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT DateConstr_UTC(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
+    double n;
+    HRESULT hres;
+
     TRACE("\n");
 
-    return date_utc(ctx, dp, retv, ei);
+    hres = date_utc(ctx, argc, argv, &n);
+    if(SUCCEEDED(hres) && r)
+        *r = jsval_number(n);
+    return hres;
 }
 
-static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *date;
+    jsdisp_t *date;
     HRESULT hres;
 
     TRACE("\n");
 
     switch(flags) {
     case DISPATCH_CONSTRUCT:
-        switch(arg_cnt(dp)) {
+        switch(argc) {
         /* ECMA-262 3rd Edition    15.9.3.3 */
         case 0: {
             FILETIME time;
@@ -2536,22 +2421,23 @@ static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
 
         /* ECMA-262 3rd Edition    15.9.3.2 */
         case 1: {
-            VARIANT prim, num;
+            jsval_t prim;
+            double n;
 
-            hres = to_primitive(ctx, get_arg(dp,0), ei, &prim, NO_HINT);
+            hres = to_primitive(ctx, argv[0], &prim, NO_HINT);
             if(FAILED(hres))
                 return hres;
 
-            if(V_VT(&prim) == VT_BSTR)
-                hres = date_parse(V_BSTR(&prim), &num);
+            if(is_string(prim))
+                hres = date_parse(get_string(prim), &n);
             else
-                hres = to_number(ctx, &prim, ei, &num);
+                hres = to_number(ctx, prim, &n);
 
-            VariantClear(&prim);
+            jsval_release(prim);
             if(FAILED(hres))
                 return hres;
 
-            hres = create_date(ctx, NULL, time_clip(num_val(&num)), &date);
+            hres = create_date(ctx, NULL, time_clip(n), &date);
             if(FAILED(hres))
                 return hres;
             break;
@@ -2559,14 +2445,14 @@ static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
 
         /* ECMA-262 3rd Edition    15.9.3.1 */
         default: {
-            VARIANT ret_date;
+            double ret_date;
             DateInstance *di;
 
-            hres = date_utc(ctx, dp, &ret_date, ei);
+            hres = date_utc(ctx, argc, argv, &ret_date);
             if(FAILED(hres))
                 return hres;
 
-            hres = create_date(ctx, NULL, num_val(&ret_date), &date);
+            hres = create_date(ctx, NULL, ret_date, &date);
             if(FAILED(hres))
                 return hres;
 
@@ -2575,8 +2461,7 @@ static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         }
         }
 
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(date);
+        *r = jsval_obj(date);
         return S_OK;
 
     case INVOKE_FUNC: {
@@ -2588,7 +2473,7 @@ static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         lltime = ((LONGLONG)local_time.dwHighDateTime<<32)
             + local_time.dwLowDateTime;
 
-        return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, retv);
+        return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, r);
     }
 
     default:
@@ -2613,9 +2498,9 @@ static const builtin_info_t DateConstr_info = {
     NULL
 };
 
-HRESULT create_date_constr(script_ctx_t *ctx, DispatchEx *object_prototype, DispatchEx **ret)
+HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
 {
-    DispatchEx *date;
+    jsdisp_t *date;
     HRESULT hres;
 
     static const WCHAR DateW[] = {'D','a','t','e',0};
@@ -2624,7 +2509,7 @@ HRESULT create_date_constr(script_ctx_t *ctx, DispatchEx *object_prototype, Disp
     if(FAILED(hres))
         return hres;
 
-    hres = create_builtin_function(ctx, DateConstr_value, DateW, &DateConstr_info,
+    hres = create_builtin_constructor(ctx, DateConstr_value, DateW, &DateConstr_info,
             PROPF_CONSTR|7, date, ret);
 
     jsdisp_release(date);
diff --git a/reactos/dll/win32/jscript/decode.c b/reactos/dll/win32/jscript/decode.c
new file mode 100644 (file)
index 0000000..bae0a39
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * 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
+ */
+
+#include "jscript.h"
+
+#include <wine/debug.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(jscript);
+
+/*
+ * This file implements algorithm for decoding scripts encoded by
+ * screnc.exe. The 'secret' algorithm that's well documented here:
+ * http://www.virtualconspiracy.com/content/articles/breaking-screnc
+ */
+
+static const unsigned char pick_encoding[64] = {
+    1,2,0,1,2,0,2,0,0,2,0,2,1,0,2,0,
+    1,0,2,0,1,1,2,0,0,2,1,0,2,0,0,2,
+    1,1,0,2,0,2,0,1,0,1,1,2,0,1,0,2,
+    1,0,2,0,1,1,2,0,0,1,1,2,0,1,0,2};
+
+static const unsigned char dictionary[][3] = {
+    {0x00,0x00,0x00}, {0x01,0x01,0x01}, {0x02,0x02,0x02}, {0x03,0x03,0x03},
+    {0x04,0x04,0x04}, {0x05,0x05,0x05}, {0x06,0x06,0x06}, {0x07,0x07,0x07},
+    {0x08,0x08,0x08}, {0x7b,0x57,0x6e}, {0x0a,0x0a,0x0a}, {0x0b,0x0b,0x0b},
+    {0x0c,0x0c,0x0c}, {0x0d,0x0d,0x0d}, {0x0e,0x0e,0x0e}, {0x0f,0x0f,0x0f},
+    {0x10,0x10,0x10}, {0x11,0x11,0x11}, {0x12,0x12,0x12}, {0x13,0x13,0x13},
+    {0x14,0x14,0x14}, {0x15,0x15,0x15}, {0x16,0x16,0x16}, {0x17,0x17,0x17},
+    {0x18,0x18,0x18}, {0x19,0x19,0x19}, {0x1a,0x1a,0x1a}, {0x1b,0x1b,0x1b},
+    {0x1c,0x1c,0x1c}, {0x1d,0x1d,0x1d}, {0x1e,0x1e,0x1e}, {0x1f,0x1f,0x1f},
+    {0x32,0x2e,0x2d}, {0x30,0x47,0x75}, {0x21,0x7a,0x52}, {0x29,0x56,0x60},
+    {0x5b,0x42,0x71}, {0x38,0x6a,0x5e}, {0x33,0x2f,0x49}, {0x3d,0x26,0x5c},
+    {0x58,0x49,0x62}, {0x3a,0x41,0x7d}, {0x35,0x34,0x29}, {0x65,0x32,0x36},
+    {0x39,0x5b,0x20}, {0x5c,0x76,0x7c}, {0x56,0x72,0x7a}, {0x73,0x43,0x7f},
+    {0x66,0x38,0x6b}, {0x4e,0x39,0x63}, {0x45,0x70,0x33}, {0x6b,0x45,0x2b},
+    {0x62,0x68,0x68}, {0x59,0x71,0x51}, {0x78,0x4f,0x66}, {0x5e,0x09,0x76},
+    {0x7d,0x62,0x31}, {0x4a,0x44,0x64}, {0x6d,0x23,0x54}, {0x71,0x75,0x43},
+    {0x00,0x00,0x00}, {0x60,0x7e,0x3a}, {0x00,0x00,0x00}, {0x53,0x5e,0x7e},
+    {0x00,0x00,0x00}, {0x42,0x77,0x45}, {0x27,0x4a,0x2c}, {0x48,0x61,0x2a},
+    {0x72,0x5d,0x74}, {0x75,0x22,0x27}, {0x31,0x4b,0x37}, {0x37,0x6f,0x44},
+    {0x4d,0x4e,0x79}, {0x52,0x3b,0x59}, {0x22,0x4c,0x2f}, {0x54,0x50,0x6f},
+    {0x6a,0x67,0x26}, {0x47,0x2a,0x72}, {0x64,0x7d,0x6a}, {0x2d,0x74,0x39},
+    {0x20,0x54,0x7b}, {0x7f,0x2b,0x3f}, {0x2e,0x2d,0x38}, {0x4c,0x2c,0x77},
+    {0x5d,0x30,0x67}, {0x7e,0x6e,0x53}, {0x6c,0x6b,0x47}, {0x6f,0x66,0x34},
+    {0x79,0x35,0x78}, {0x74,0x25,0x5d}, {0x43,0x21,0x30}, {0x26,0x64,0x23},
+    {0x76,0x4d,0x5a}, {0x25,0x52,0x5b}, {0x24,0x63,0x6c}, {0x2b,0x3f,0x48},
+    {0x28,0x7b,0x55}, {0x23,0x78,0x70}, {0x41,0x29,0x69}, {0x34,0x28,0x2e},
+    {0x09,0x73,0x4c}, {0x2a,0x59,0x21}, {0x44,0x33,0x24}, {0x3f,0x7f,0x4e},
+    {0x77,0x6d,0x50}, {0x3b,0x55,0x09}, {0x55,0x53,0x56}, {0x69,0x7c,0x73},
+    {0x61,0x3a,0x35}, {0x63,0x5f,0x61}, {0x50,0x65,0x4b}, {0x67,0x46,0x58},
+    {0x51,0x58,0x3b}, {0x49,0x31,0x57}, {0x4f,0x69,0x22}, {0x46,0x6c,0x6d},
+    {0x68,0x5a,0x4d}, {0x7c,0x48,0x25}, {0x36,0x27,0x28}, {0x70,0x5c,0x46},
+    {0x6e,0x3d,0x4a}, {0x7a,0x24,0x32}, {0x2f,0x79,0x41}, {0x5f,0x37,0x3d},
+    {0x4b,0x60,0x5f}, {0x5a,0x51,0x4f}, {0x2c,0x20,0x42}, {0x57,0x36,0x65}};
+
+static const int digits[] = {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+    0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+    0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+    0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+    0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+    0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+    0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+static BOOL decode_dword(const WCHAR *p, DWORD *ret)
+{
+    DWORD i;
+
+    for(i=0; i<6; i++) {
+        if(p[i] > sizeof(digits)/sizeof(*digits) || digits[p[i]] == 0xff)
+            return FALSE;
+    }
+    if(p[6] != '=' || p[7] != '=')
+        return FALSE;
+
+    *ret = (digits[p[0]] << 2)
+        + (digits[p[1]] >> 4)
+        + ((digits[p[1]] & 0xf) << 12)
+        + ((digits[p[2]] >> 2) << 8)
+        + ((digits[p[2]] & 0x3) << 22)
+        + (digits[p[3]] << 16)
+        + ((digits[p[4]] << 2) << 24)
+        + ((digits[p[5]] >> 4) << 24);
+    return TRUE;
+}
+
+HRESULT decode_source(WCHAR *code)
+{
+    const WCHAR *src = code;
+    WCHAR *dst = code;
+
+    static const WCHAR decode_beginW[] = {'#','@','~','^'};
+    static const WCHAR decode_endW[] = {'^','#','~','@'};
+
+    while(*src) {
+        if(!strncmpW(src, decode_beginW, sizeof(decode_beginW)/sizeof(*decode_beginW))) {
+            DWORD len, i, j=0, csum, s=0;
+
+            src += sizeof(decode_beginW)/sizeof(*decode_beginW);
+
+            if(!decode_dword(src, &len))
+                return JS_E_INVALID_CHAR;
+
+            src += 8;
+
+            for(i=0; i<len; i++) {
+                if (src[i] == '@') {
+                    switch(src[++i]) {
+                    case '#':
+                        s += dst[j++] = '\r';
+                        break;
+                    case '&':
+                        s += dst[j++] = '\n';
+                        break;
+                    case '!':
+                        s += dst[j++] = '<';
+                        break;
+                    case '*':
+                        s += dst[j++] = '>';
+                        break;
+                    case '$':
+                        s += dst[j++] = '@';
+                        break;
+                    default:
+                        FIXME("unescape %c\n", src[i]);
+                        return E_FAIL;
+                    }
+                }else if (src[i] < 128) {
+                    s += dst[j] = dictionary[src[i]][pick_encoding[j%64]];
+                    j++;
+                }else {
+                    FIXME("Unsupported char %c\n", src[i]);
+                    return E_FAIL;
+                }
+            }
+
+            src += len;
+            dst += j;
+
+            if(!decode_dword(src, &csum) || s != csum)
+                return JS_E_INVALID_CHAR;
+            src += 8;
+
+            if(strncmpW(src, decode_endW, sizeof(decode_endW)/sizeof(*decode_endW)))
+                return JS_E_INVALID_CHAR;
+            src += sizeof(decode_endW)/sizeof(*decode_endW);
+        }else {
+            *dst++ = *src++;
+        }
+    }
+
+    *dst = 0;
+
+    TRACE("decoded %s\n", debugstr_w(code));
+    return S_OK;
+}
index 60b5c14..763df13 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include <assert.h>
+
 #include "jscript.h"
 
 //#include "wine/unicode.h"
 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 
 /*
- * This IID is used to get DispatchEx objecto from interface.
- * We might consider using private insteface instead.
+ * This IID is used to get jsdisp_t objecto from interface.
+ * We might consider using private interface instead.
  */
 static const IID IID_IDispatchJS =
         {0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa6}};
 
 #define FDEX_VERSION_MASK 0xf0000000
+#define GOLDEN_RATIO 0x9E3779B9U
 
 typedef enum {
-    PROP_VARIANT,
+    PROP_JSVAL,
     PROP_BUILTIN,
     PROP_PROTREF,
-    PROP_DELETED
+    PROP_DELETED,
+    PROP_IDX
 } prop_type_t;
 
 struct _dispex_prop_t {
     WCHAR *name;
+    unsigned hash;
     prop_type_t type;
     DWORD flags;
 
     union {
-        VARIANT var;
+        jsval_t val;
         const builtin_prop_t *p;
         DWORD ref;
+        unsigned idx;
     } u;
+
+    int bucket_head;
+    int bucket_next;
 };
 
-static inline DISPID prop_to_id(DispatchEx *This, dispex_prop_t *prop)
+static inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop)
 {
     return prop - This->props;
 }
 
-static inline dispex_prop_t *get_prop(DispatchEx *This, DISPID id)
+static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id)
 {
     if(id < 0 || id >= This->prop_cnt || This->props[id].type == PROP_DELETED)
         return NULL;
@@ -64,7 +73,7 @@ static inline dispex_prop_t *get_prop(DispatchEx *This, DISPID id)
     return This->props+id;
 }
 
-static DWORD get_flags(DispatchEx *This, dispex_prop_t *prop)
+static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop)
 {
     if(prop->type == PROP_PROTREF) {
         dispex_prop_t *parent = get_prop(This->prototype, prop->u.ref);
@@ -79,7 +88,7 @@ static DWORD get_flags(DispatchEx *This, dispex_prop_t *prop)
     return prop->flags;
 }
 
-static const builtin_prop_t *find_builtin_prop(DispatchEx *This, const WCHAR *name)
+static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name)
 {
     int min = 0, max, i, r;
 
@@ -100,28 +109,72 @@ static const builtin_prop_t *find_builtin_prop(DispatchEx *This, const WCHAR *na
     return NULL;
 }
 
-static dispex_prop_t *alloc_prop(DispatchEx *This, const WCHAR *name, prop_type_t type, DWORD flags)
+static inline unsigned string_hash(const WCHAR *name)
 {
-    dispex_prop_t *ret;
+    unsigned h = 0;
+    for(; *name; name++)
+        h = (h>>(sizeof(unsigned)*8-4)) ^ (h<<4) ^ tolowerW(*name);
+    return h;
+}
 
-    if(This->buf_size == This->prop_cnt) {
-        dispex_prop_t *tmp = heap_realloc(This->props, (This->buf_size<<=1)*sizeof(*This->props));
-        if(!tmp)
-            return NULL;
-        This->props = tmp;
+static inline unsigned get_props_idx(jsdisp_t *This, unsigned hash)
+{
+    return (hash*GOLDEN_RATIO) & (This->buf_size-1);
+}
+
+static inline HRESULT resize_props(jsdisp_t *This)
+{
+    dispex_prop_t *props;
+    int i, bucket;
+
+    if(This->buf_size != This->prop_cnt)
+        return S_FALSE;
+
+    props = heap_realloc(This->props, sizeof(dispex_prop_t)*This->buf_size*2);
+    if(!props)
+        return E_OUTOFMEMORY;
+    This->buf_size *= 2;
+    This->props = props;
+
+    for(i=0; i<This->buf_size; i++) {
+        This->props[i].bucket_head = 0;
+        This->props[i].bucket_next = 0;
     }
 
-    ret = This->props + This->prop_cnt++;
-    ret->type = type;
-    ret->flags = flags;
-    ret->name = heap_strdupW(name);
-    if(!ret->name)
+    for(i=1; i<This->prop_cnt; i++) {
+        props = This->props+i;
+
+        bucket = get_props_idx(This, props->hash);
+        props->bucket_next = This->props[bucket].bucket_head;
+        This->props[bucket].bucket_head = i;
+    }
+
+    return S_OK;
+}
+
+static inline dispex_prop_t* alloc_prop(jsdisp_t *This, const WCHAR *name, prop_type_t type, DWORD flags)
+{
+    dispex_prop_t *prop;
+    unsigned bucket;
+
+    if(FAILED(resize_props(This)))
         return NULL;
 
-    return ret;
+    prop = &This->props[This->prop_cnt];
+    prop->name = heap_strdupW(name);
+    if(!prop->name)
+        return NULL;
+    prop->type = type;
+    prop->flags = flags;
+    prop->hash = string_hash(name);
+
+    bucket = get_props_idx(This, prop->hash);
+    prop->bucket_next = This->props[bucket].bucket_head;
+    This->props[bucket].bucket_head = This->prop_cnt++;
+    return prop;
 }
 
-static dispex_prop_t *alloc_protref(DispatchEx *This, const WCHAR *name, DWORD ref)
+static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref)
 {
     dispex_prop_t *ret;
 
@@ -133,16 +186,28 @@ static dispex_prop_t *alloc_protref(DispatchEx *This, const WCHAR *name, DWORD r
     return ret;
 }
 
-static HRESULT find_prop_name(DispatchEx *This, const WCHAR *name, dispex_prop_t **ret)
+static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
 {
     const builtin_prop_t *builtin;
+    unsigned bucket, pos, prev = 0;
     dispex_prop_t *prop;
 
-    for(prop = This->props; prop < This->props+This->prop_cnt; prop++) {
-        if(prop->name && !strcmpW(prop->name, name)) {
-            *ret = prop;
+    bucket = get_props_idx(This, hash);
+    pos = This->props[bucket].bucket_head;
+    while(pos != 0) {
+        if(!strcmpW(name, This->props[pos].name)) {
+            if(prev != 0) {
+                This->props[prev].bucket_next = This->props[pos].bucket_next;
+                This->props[pos].bucket_next = This->props[bucket].bucket_head;
+                This->props[bucket].bucket_head = pos;
+            }
+
+            *ret = &This->props[pos];
             return S_OK;
         }
+
+        prev = pos;
+        pos = This->props[pos].bucket_next;
     }
 
     builtin = find_builtin_prop(This, name);
@@ -156,188 +221,233 @@ static HRESULT find_prop_name(DispatchEx *This, const WCHAR *name, dispex_prop_t
         return S_OK;
     }
 
+    if(This->builtin_info->idx_length) {
+        const WCHAR *ptr;
+        unsigned idx = 0;
+
+        for(ptr = name; isdigitW(*ptr) && idx < 0x10000; ptr++)
+            idx = idx*10 + (*ptr-'0');
+        if(!*ptr && idx < This->builtin_info->idx_length(This)) {
+            prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? 0 : PROPF_CONST);
+            if(!prop)
+                return E_OUTOFMEMORY;
+
+            prop->u.idx = idx;
+            *ret = prop;
+            return S_OK;
+        }
+    }
+
     *ret = NULL;
     return S_OK;
 }
 
-static HRESULT find_prop_name_prot(DispatchEx *This, const WCHAR *name, dispex_prop_t **ret)
+static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
 {
-    dispex_prop_t *prop;
+    dispex_prop_t *prop, *del=NULL;
     HRESULT hres;
 
-    hres = find_prop_name(This, name, &prop);
+    hres = find_prop_name(This, hash, name, &prop);
     if(FAILED(hres))
         return hres;
-    if(prop) {
+    if(prop && prop->type==PROP_DELETED) {
+        del = prop;
+    } else if(prop) {
         *ret = prop;
         return S_OK;
     }
 
     if(This->prototype) {
-        hres = find_prop_name_prot(This->prototype, name, &prop);
+        hres = find_prop_name_prot(This->prototype, hash, name, &prop);
         if(FAILED(hres))
             return hres;
         if(prop) {
-            prop = alloc_protref(This, prop->name, prop - This->prototype->props);
-            if(!prop)
-                return E_OUTOFMEMORY;
+            if(del) {
+                del->type = PROP_PROTREF;
+                del->flags = 0;
+                del->u.ref = prop - This->prototype->props;
+                prop = del;
+            }else {
+                prop = alloc_protref(This, prop->name, prop - This->prototype->props);
+                if(!prop)
+                    return E_OUTOFMEMORY;
+            }
+
             *ret = prop;
             return S_OK;
         }
     }
 
-    *ret = prop;
+    *ret = del;
     return S_OK;
 }
 
-static HRESULT ensure_prop_name(DispatchEx *This, const WCHAR *name, BOOL search_prot, DWORD create_flags, dispex_prop_t **ret)
+static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, BOOL search_prot, DWORD create_flags, dispex_prop_t **ret)
 {
     dispex_prop_t *prop;
     HRESULT hres;
 
     if(search_prot)
-        hres = find_prop_name_prot(This, name, &prop);
+        hres = find_prop_name_prot(This, string_hash(name), name, &prop);
     else
-        hres = find_prop_name(This, name, &prop);
-    if(SUCCEEDED(hres) && !prop) {
-        TRACE("creating prop %s\n", debugstr_w(name));
+        hres = find_prop_name(This, string_hash(name), name, &prop);
+    if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) {
+        TRACE("creating prop %s flags %x\n", debugstr_w(name), create_flags);
 
-        prop = alloc_prop(This, name, PROP_VARIANT, create_flags);
-        if(!prop)
-            return E_OUTOFMEMORY;
-        VariantInit(&prop->u.var);
+        if(prop) {
+            prop->type = PROP_JSVAL;
+            prop->flags = create_flags;
+            prop->u.val = jsval_undefined();
+        }else {
+            prop = alloc_prop(This, name, PROP_JSVAL, create_flags);
+            if(!prop)
+                return E_OUTOFMEMORY;
+        }
+
+        prop->u.val = jsval_undefined();
     }
 
     *ret = prop;
     return hres;
 }
 
-static HRESULT set_this(DISPPARAMS *dp, DISPPARAMS *olddp, IDispatch *jsthis)
+static IDispatch *get_this(DISPPARAMS *dp)
 {
-    VARIANTARG *oldargs;
-    int i;
+    DWORD i;
 
-    static DISPID this_id = DISPID_THIS;
+    for(i=0; i < dp->cNamedArgs; i++) {
+        if(dp->rgdispidNamedArgs[i] == DISPID_THIS) {
+            if(V_VT(dp->rgvarg+i) == VT_DISPATCH)
+                return V_DISPATCH(dp->rgvarg+i);
 
-    *dp = *olddp;
-
-    for(i = 0; i < dp->cNamedArgs; i++) {
-        if(dp->rgdispidNamedArgs[i] == DISPID_THIS)
-            return S_OK;
+            WARN("This is not VT_DISPATCH\n");
+            return NULL;
+        }
     }
 
-    oldargs = dp->rgvarg;
-    dp->rgvarg = heap_alloc((dp->cArgs+1) * sizeof(VARIANTARG));
-    if(!dp->rgvarg)
-        return E_OUTOFMEMORY;
-    memcpy(dp->rgvarg+1, oldargs, dp->cArgs*sizeof(VARIANTARG));
-    V_VT(dp->rgvarg) = VT_DISPATCH;
-    V_DISPATCH(dp->rgvarg) = jsthis;
-    dp->cArgs++;
-
-    if(dp->cNamedArgs) {
-        DISPID *old = dp->rgdispidNamedArgs;
-        dp->rgdispidNamedArgs = heap_alloc((dp->cNamedArgs+1)*sizeof(DISPID));
-        if(!dp->rgdispidNamedArgs) {
-            heap_free(dp->rgvarg);
-            return E_OUTOFMEMORY;
-        }
+    TRACE("no this passed\n");
+    return NULL;
+}
 
-        memcpy(dp->rgdispidNamedArgs+1, old, dp->cNamedArgs*sizeof(DISPID));
-        dp->rgdispidNamedArgs[0] = DISPID_THIS;
-        dp->cNamedArgs++;
+static HRESULT convert_params(const DISPPARAMS *dp, jsval_t *buf, unsigned *argc, jsval_t **ret)
+{
+    jsval_t *argv;
+    unsigned cnt;
+    unsigned i;
+    HRESULT hres;
+
+    cnt = dp->cArgs - dp->cNamedArgs;
+
+    if(cnt > 6) {
+        argv = heap_alloc(cnt * sizeof(*argv));
+        if(!argv)
+            return E_OUTOFMEMORY;
     }else {
-        dp->rgdispidNamedArgs = &this_id;
-        dp->cNamedArgs = 1;
+        argv = buf;
     }
 
+    for(i = 0; i < cnt; i++) {
+        hres = variant_to_jsval(dp->rgvarg+dp->cArgs-i-1, argv+i);
+        if(FAILED(hres)) {
+            while(i--)
+                jsval_release(argv[i]);
+            if(argv != buf)
+                heap_free(argv);
+            return hres;
+        }
+    }
+
+    *argc = cnt;
+    *ret = argv;
     return S_OK;
 }
 
-static HRESULT invoke_prop_func(DispatchEx *This, DispatchEx *jsthis, dispex_prop_t *prop, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags,
+        unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller)
 {
     HRESULT hres;
 
     switch(prop->type) {
     case PROP_BUILTIN: {
-        vdisp_t vthis;
-
-        if(flags == DISPATCH_CONSTRUCT && (prop->flags & DISPATCH_METHOD)) {
+        if(flags == DISPATCH_CONSTRUCT && (prop->flags & PROPF_METHOD)) {
             WARN("%s is not a constructor\n", debugstr_w(prop->name));
             return E_INVALIDARG;
         }
 
-        set_jsdisp(&vthis, jsthis);
-        hres = prop->u.p->invoke(This->ctx, &vthis, flags, dp, retv, ei, caller);
-        vdisp_release(&vthis);
+        if(prop->name || This->builtin_info->class != JSCLASS_FUNCTION) {
+            vdisp_t vthis;
+
+            if(jsthis)
+                set_disp(&vthis, jsthis);
+            else
+                set_jsdisp(&vthis, This);
+            hres = prop->u.p->invoke(This->ctx, &vthis, flags, argc, argv, r);
+            vdisp_release(&vthis);
+        }else {
+            /* Function object calls are special case */
+            hres = Function_invoke(This, jsthis, flags, argc, argv, r);
+        }
         return hres;
     }
     case PROP_PROTREF:
-        return invoke_prop_func(This->prototype, jsthis, This->prototype->props+prop->u.ref, flags, dp, retv, ei, caller);
-    case PROP_VARIANT: {
-        DISPPARAMS new_dp;
-
-        if(V_VT(&prop->u.var) != VT_DISPATCH) {
-            FIXME("invoke vt %d\n", V_VT(&prop->u.var));
+        return invoke_prop_func(This->prototype, jsthis, This->prototype->props+prop->u.ref,
+                flags, argc, argv, r, caller);
+    case PROP_JSVAL: {
+        if(!is_object_instance(prop->u.val)) {
+            FIXME("invoke %s\n", debugstr_jsval(prop->u.val));
             return E_FAIL;
         }
 
-        TRACE("call %s %p\n", debugstr_w(prop->name), V_DISPATCH(&prop->u.var));
+        TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val));
 
-        hres = set_this(&new_dp, dp, (IDispatch*)_IDispatchEx_(jsthis));
-        if(FAILED(hres))
-            return hres;
-
-        hres = disp_call(This->ctx, V_DISPATCH(&prop->u.var), DISPID_VALUE, flags, &new_dp, retv, ei, caller);
-
-        if(new_dp.rgvarg != dp->rgvarg) {
-            heap_free(new_dp.rgvarg);
-            if(new_dp.cNamedArgs > 1)
-                heap_free(new_dp.rgdispidNamedArgs);
-        }
-
-        return hres;
+        return disp_call_value(This->ctx, get_object(prop->u.val), jsthis, flags, argc, argv, r);
     }
-    default:
-        ERR("type %d\n", prop->type);
+    case PROP_IDX:
+        FIXME("Invoking PROP_IDX not yet supported\n");
+        return E_NOTIMPL;
+    case PROP_DELETED:
+        assert(0);
     }
 
+    assert(0);
     return E_FAIL;
 }
 
-static HRESULT prop_get(DispatchEx *This, dispex_prop_t *prop, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, DISPPARAMS *dp,
+        jsval_t *r, IServiceProvider *caller)
 {
     HRESULT hres;
 
     switch(prop->type) {
     case PROP_BUILTIN:
         if(prop->u.p->flags & PROPF_METHOD) {
-            DispatchEx *obj;
+            jsdisp_t *obj;
             hres = create_builtin_function(This->ctx, prop->u.p->invoke, prop->u.p->name, NULL,
                     prop->u.p->flags, NULL, &obj);
             if(FAILED(hres))
                 break;
 
-            prop->type = PROP_VARIANT;
-            V_VT(&prop->u.var) = VT_DISPATCH;
-            V_DISPATCH(&prop->u.var) = (IDispatch*)_IDispatchEx_(obj);
+            prop->type = PROP_JSVAL;
+            prop->u.val = jsval_obj(obj);
 
-            hres = VariantCopy(retv, &prop->u.var);
+            jsdisp_addref(obj);
+            *r = jsval_obj(obj);
         }else {
             vdisp_t vthis;
 
             set_jsdisp(&vthis, This);
-            hres = prop->u.p->invoke(This->ctx, &vthis, DISPATCH_PROPERTYGET, dp, retv, ei, caller);
+            hres = prop->u.p->invoke(This->ctx, &vthis, DISPATCH_PROPERTYGET, 0, NULL, r);
             vdisp_release(&vthis);
         }
         break;
     case PROP_PROTREF:
-        hres = prop_get(This->prototype, This->prototype->props+prop->u.ref, dp, retv, ei, caller);
+        hres = prop_get(This->prototype, This->prototype->props+prop->u.ref, dp, r, caller);
+        break;
+    case PROP_JSVAL:
+        hres = jsval_copy(prop->u.val, r);
         break;
-    case PROP_VARIANT:
-        hres = VariantCopy(retv, &prop->u.var);
+    case PROP_IDX:
+        hres = This->builtin_info->idx_get(This, prop->u.idx, r);
         break;
     default:
         ERR("type %d\n", prop->type);
@@ -349,12 +459,11 @@ static HRESULT prop_get(DispatchEx *This, dispex_prop_t *prop, DISPPARAMS *dp,
         return hres;
     }
 
-    TRACE("%s ret %s\n", debugstr_w(prop->name), debugstr_variant(retv));
+    TRACE("%s ret %s\n", debugstr_w(prop->name), debugstr_jsval(*r));
     return hres;
 }
 
-static HRESULT prop_put(DispatchEx *This, dispex_prop_t *prop, VARIANT *val,
-        jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServiceProvider *caller)
 {
     HRESULT hres;
 
@@ -364,39 +473,44 @@ static HRESULT prop_put(DispatchEx *This, dispex_prop_t *prop, VARIANT *val,
     switch(prop->type) {
     case PROP_BUILTIN:
         if(!(prop->flags & PROPF_METHOD)) {
-            DISPPARAMS dp = {val, NULL, 1, 0};
             vdisp_t vthis;
 
             set_jsdisp(&vthis, This);
-            hres = prop->u.p->invoke(This->ctx, &vthis, DISPATCH_PROPERTYPUT, &dp, NULL, ei, caller);
+            hres = prop->u.p->invoke(This->ctx, &vthis, DISPATCH_PROPERTYPUT, 1, &val, NULL);
             vdisp_release(&vthis);
             return hres;
         }
+        /* fall through */
     case PROP_PROTREF:
-        prop->type = PROP_VARIANT;
+        prop->type = PROP_JSVAL;
         prop->flags = PROPF_ENUM;
-        V_VT(&prop->u.var) = VT_EMPTY;
+        prop->u.val = jsval_undefined();
         break;
-    case PROP_VARIANT:
-        VariantClear(&prop->u.var);
+    case PROP_JSVAL:
+        jsval_release(prop->u.val);
         break;
+    case PROP_IDX:
+        return This->builtin_info->idx_put(This, prop->u.idx, val);
     default:
         ERR("type %d\n", prop->type);
         return E_FAIL;
     }
 
-    hres = VariantCopy(&prop->u.var, val);
-    if(FAILED(hres))
+    TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val));
+
+    hres = jsval_copy(val, &prop->u.val);
+    if(FAILED(hres)) {
+        prop->u.val = jsval_undefined();
         return hres;
+    }
 
     if(This->builtin_info->on_put)
         This->builtin_info->on_put(This, prop->name);
 
-    TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_variant(val));
     return S_OK;
 }
 
-static HRESULT fill_protrefs(DispatchEx *This)
+static HRESULT fill_protrefs(jsdisp_t *This)
 {
     dispex_prop_t *iter, *prop;
     HRESULT hres;
@@ -409,37 +523,46 @@ static HRESULT fill_protrefs(DispatchEx *This)
     for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) {
         if(!iter->name)
             continue;
-        hres = find_prop_name(This, iter->name, &prop);
+        hres = find_prop_name(This, iter->hash, iter->name, &prop);
         if(FAILED(hres))
             return hres;
-        if(!prop) {
-            prop = alloc_protref(This, iter->name, iter - This->prototype->props);
-            if(!prop)
-                return E_OUTOFMEMORY;
+        if(!prop || prop->type==PROP_DELETED) {
+            if(prop) {
+                prop->type = PROP_PROTREF;
+                prop->flags = 0;
+                prop->u.ref = iter - This->prototype->props;
+            }else {
+                prop = alloc_protref(This, iter->name, iter - This->prototype->props);
+                if(!prop)
+                    return E_OUTOFMEMORY;
+            }
         }
     }
 
     return S_OK;
 }
 
-#define DISPATCHEX_THIS(iface) DEFINE_THIS(DispatchEx, IDispatchEx, iface)
+static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
+{
+    return CONTAINING_RECORD(iface, jsdisp_t, IDispatchEx_iface);
+}
 
 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
 
     if(IsEqualGUID(&IID_IUnknown, riid)) {
         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
-        *ppv = _IDispatchEx_(This);
+        *ppv = &This->IDispatchEx_iface;
     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
-        *ppv = _IDispatchEx_(This);
+        *ppv = &This->IDispatchEx_iface;
     }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
-        *ppv = _IDispatchEx_(This);
+        *ppv = &This->IDispatchEx_iface;
     }else if(IsEqualGUID(&IID_IDispatchJS, riid)) {
         TRACE("(%p)->(IID_IDispatchJS %p)\n", This, ppv);
-        IUnknown_AddRef(_IDispatchEx_(This));
+        jsdisp_addref(This);
         *ppv = This;
         return S_OK;
     }else {
@@ -448,52 +571,29 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid,
         return E_NOINTERFACE;
     }
 
-    IUnknown_AddRef((IUnknown*)*ppv);
+    jsdisp_addref(This);
     return S_OK;
 }
 
 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
-    LONG ref = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref=%d\n", This, ref);
-
-    return ref;
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
+    jsdisp_addref(This);
+    return This->ref;
 }
 
 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
-    LONG ref = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref=%d\n", This, ref);
-
-    if(!ref) {
-        dispex_prop_t *prop;
-
-        for(prop = This->props; prop < This->props+This->prop_cnt; prop++) {
-            if(prop->type == PROP_VARIANT)
-                VariantClear(&prop->u.var);
-            heap_free(prop->name);
-        }
-        heap_free(This->props);
-        script_release(This->ctx);
-        if(This->prototype)
-            jsdisp_release(This->prototype);
-
-        if(This->builtin_info->destructor)
-            This->builtin_info->destructor(This);
-        else
-            heap_free(This);
-    }
-
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
+    ULONG ref = --This->ref;
+    if(!ref)
+        jsdisp_free(This);
     return ref;
 }
 
 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
 
     TRACE("(%p)->(%p)\n", This, pctinfo);
 
@@ -504,7 +604,7 @@ static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pcti
 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
                                               ITypeInfo **ppTInfo)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
     return E_NOTIMPL;
 }
@@ -513,7 +613,7 @@ static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
                                                 LPOLESTR *rgszNames, UINT cNames, LCID lcid,
                                                 DISPID *rgDispId)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
     UINT i;
     HRESULT hres;
 
@@ -521,7 +621,7 @@ static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
           lcid, rgDispId);
 
     for(i=0; i < cNames; i++) {
-        hres = IDispatchEx_GetDispID(_IDispatchEx_(This), rgszNames[i], 0, rgDispId+i);
+        hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i);
         if(FAILED(hres))
             return hres;
     }
@@ -533,18 +633,18 @@ static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
                                         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
 
     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
 
-    return IDispatchEx_InvokeEx(_IDispatchEx_(This), dispIdMember, lcid, wFlags,
+    return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
             pDispParams, pVarResult, pExcepInfo, NULL);
 }
 
 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
 
     TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
 
@@ -559,9 +659,8 @@ static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DW
 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
     dispex_prop_t *prop;
-    jsexcept_t jsexcept;
     HRESULT hres;
 
     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
@@ -575,17 +674,42 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
         return DISP_E_MEMBERNOTFOUND;
     }
 
-    memset(&jsexcept, 0, sizeof(jsexcept));
+    clear_ei(This->ctx);
 
     switch(wFlags) {
+    case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
+        wFlags = DISPATCH_METHOD;
+        /* fall through */
     case DISPATCH_METHOD:
-    case DISPATCH_CONSTRUCT:
-        hres = invoke_prop_func(This, This, prop, wFlags, pdp, pvarRes, &jsexcept, pspCaller);
+    case DISPATCH_CONSTRUCT: {
+        jsval_t *argv, buf[6], r;
+        unsigned argc;
+
+        hres = convert_params(pdp, buf, &argc, &argv);
+        if(FAILED(hres))
+            return hres;
+
+        hres = invoke_prop_func(This, get_this(pdp), prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller);
+        if(argv != buf)
+            heap_free(argv);
+        if(SUCCEEDED(hres) && pvarRes) {
+            hres = jsval_to_variant(r, pvarRes);
+            jsval_release(r);
+        }
         break;
-    case DISPATCH_PROPERTYGET:
-        hres = prop_get(This, prop, pdp, pvarRes, &jsexcept, pspCaller);
+    }
+    case DISPATCH_PROPERTYGET: {
+        jsval_t r;
+
+        hres = prop_get(This, prop, pdp, &r, pspCaller);
+        if(SUCCEEDED(hres)) {
+            hres = jsval_to_variant(r, pvarRes);
+            jsval_release(r);
+        }
         break;
+    }
     case DISPATCH_PROPERTYPUT: {
+        jsval_t val;
         DWORD i;
 
         for(i=0; i < pdp->cNamedArgs; i++) {
@@ -598,7 +722,12 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
             return DISP_E_PARAMNOTOPTIONAL;
         }
 
-        hres = prop_put(This, prop, pdp->rgvarg+i, &jsexcept, pspCaller);
+        hres = variant_to_jsval(pdp->rgvarg+i, &val);
+        if(FAILED(hres))
+            return hres;
+
+        hres = prop_put(This, prop, val, pspCaller);
+        jsval_release(val);
         break;
     }
     default:
@@ -607,24 +736,31 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
     }
 
     if(pei)
-        *pei = jsexcept.ei;
-
+        *pei = This->ctx->ei.ei;
     return hres;
 }
 
-static HRESULT delete_prop(dispex_prop_t *prop)
+static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret)
 {
-    heap_free(prop->name);
-    prop->name = NULL;
-    prop->type = PROP_DELETED;
+    if(prop->flags & PROPF_DONTDELETE) {
+        *ret = FALSE;
+        return S_OK;
+    }
 
+    *ret = TRUE; /* FIXME: not exactly right */
+
+    if(prop->type == PROP_JSVAL) {
+        jsval_release(prop->u.val);
+        prop->type = PROP_DELETED;
+    }
     return S_OK;
 }
 
 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
     dispex_prop_t *prop;
+    BOOL b;
     HRESULT hres;
 
     TRACE("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
@@ -632,7 +768,7 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bst
     if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK))
         FIXME("Unsupported grfdex %x\n", grfdex);
 
-    hres = find_prop_name(This, bstrName, &prop);
+    hres = find_prop_name(This, string_hash(bstrName), bstrName, &prop);
     if(FAILED(hres))
         return hres;
     if(!prop) {
@@ -640,13 +776,14 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bst
         return S_OK;
     }
 
-    return delete_prop(prop);
+    return delete_prop(prop, &b);
 }
 
 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
     dispex_prop_t *prop;
+    BOOL b;
 
     TRACE("(%p)->(%x)\n", This, id);
 
@@ -656,19 +793,19 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID
         return DISP_E_MEMBERNOTFOUND;
     }
 
-    return delete_prop(prop);
+    return delete_prop(prop, &b);
 }
 
 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
     FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
     dispex_prop_t *prop;
 
     TRACE("(%p)->(%x %p)\n", This, id, pbstrName);
@@ -686,7 +823,7 @@ static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BS
 
 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
     dispex_prop_t *iter;
     HRESULT hres;
 
@@ -698,14 +835,15 @@ static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex,
             return hres;
     }
 
-    iter = get_prop(This, id+1);
-    if(!iter) {
+    if(id+1>=0 && id+1<This->prop_cnt) {
+        iter = &This->props[id+1];
+    }else {
         *pid = DISPID_STARTENUM;
         return S_FALSE;
     }
 
     while(iter < This->props + This->prop_cnt) {
-        if(iter->name && (get_flags(This, iter) & PROPF_ENUM)) {
+        if(iter->name && (get_flags(This, iter) & PROPF_ENUM) && iter->type!=PROP_DELETED) {
             *pid = prop_to_id(This, iter);
             return S_OK;
         }
@@ -718,13 +856,11 @@ static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex,
 
 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
 {
-    DispatchEx *This = DISPATCHEX_THIS(iface);
+    jsdisp_t *This = impl_from_IDispatchEx(iface);
     FIXME("(%p)->(%p)\n", This, ppunk);
     return E_NOTIMPL;
 }
 
-#undef DISPATCHEX_THIS
-
 static IDispatchExVtbl DispatchExVtbl = {
     DispatchEx_QueryInterface,
     DispatchEx_AddRef,
@@ -743,25 +879,34 @@ static IDispatchExVtbl DispatchExVtbl = {
     DispatchEx_GetNameSpaceParent
 };
 
-HRESULT init_dispex(DispatchEx *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, DispatchEx *prototype)
+jsdisp_t *as_jsdisp(IDispatch *disp)
+{
+    assert(disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl);
+    return impl_from_IDispatchEx((IDispatchEx*)disp);
+}
+
+jsdisp_t *to_jsdisp(IDispatch *disp)
+{
+    return disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl ? impl_from_IDispatchEx((IDispatchEx*)disp) : NULL;
+}
+
+HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype)
 {
     TRACE("%p (%p)\n", dispex, prototype);
 
-    dispex->lpIDispatchExVtbl = &DispatchExVtbl;
+    dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
     dispex->ref = 1;
     dispex->builtin_info = builtin_info;
 
-    dispex->props = heap_alloc((dispex->buf_size=4) * sizeof(dispex_prop_t));
+    dispex->props = heap_alloc_zero(sizeof(dispex_prop_t)*(dispex->buf_size=4));
     if(!dispex->props)
         return E_OUTOFMEMORY;
 
     dispex->prototype = prototype;
     if(prototype)
-        IDispatchEx_AddRef(_IDispatchEx_(prototype));
+        jsdisp_addref(prototype);
 
     dispex->prop_cnt = 1;
-    dispex->props[0].name = NULL;
-    dispex->props[0].flags = 0;
     if(builtin_info->value_prop.invoke) {
         dispex->props[0].type = PROP_BUILTIN;
         dispex->props[0].u.p = &builtin_info->value_prop;
@@ -783,76 +928,101 @@ static const builtin_info_t dispex_info = {
     NULL
 };
 
-HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, DispatchEx *prototype, DispatchEx **dispex)
+HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex)
 {
-    DispatchEx *ret;
+    jsdisp_t *ret;
     HRESULT hres;
 
-    ret = heap_alloc_zero(sizeof(DispatchEx));
+    ret = heap_alloc_zero(sizeof(jsdisp_t));
     if(!ret)
         return E_OUTOFMEMORY;
 
     hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype);
-    if(FAILED(hres))
+    if(FAILED(hres)) {
+        heap_free(ret);
         return hres;
+    }
 
     *dispex = ret;
     return S_OK;
 }
 
-HRESULT init_dispex_from_constr(DispatchEx *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, DispatchEx *constr)
+void jsdisp_free(jsdisp_t *obj)
 {
-    DispatchEx *prot = NULL;
+    dispex_prop_t *prop;
+
+    TRACE("(%p)\n", obj);
+
+    for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) {
+        if(prop->type == PROP_JSVAL)
+            jsval_release(prop->u.val);
+        heap_free(prop->name);
+    }
+    heap_free(obj->props);
+    script_release(obj->ctx);
+    if(obj->prototype)
+        jsdisp_release(obj->prototype);
+
+    if(obj->builtin_info->destructor)
+        obj->builtin_info->destructor(obj);
+    else
+        heap_free(obj);
+}
+
+#ifdef TRACE_REFCNT
+
+jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp)
+{
+    ULONG ref = ++jsdisp->ref;
+    TRACE("(%p) ref=%d\n", jsdisp, ref);
+    return jsdisp;
+}
+
+void jsdisp_release(jsdisp_t *jsdisp)
+{
+    ULONG ref = --jsdisp->ref;
+
+    TRACE("(%p) ref=%d\n", jsdisp, ref);
+
+    if(!ref)
+        jsdisp_free(jsdisp);
+}
+
+#endif
+
+HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *constr)
+{
+    jsdisp_t *prot = NULL;
     dispex_prop_t *prop;
     HRESULT hres;
 
-    static const WCHAR constructorW[] = {'c','o','n','s','t','r','u','c','t','o','r'};
     static const WCHAR prototypeW[] = {'p','r','o','t','o','t','y','p','e',0};
 
-    hres = find_prop_name_prot(constr, prototypeW, &prop);
-    if(SUCCEEDED(hres) && prop) {
-        jsexcept_t jsexcept;
-        VARIANT var;
+    hres = find_prop_name_prot(constr, string_hash(prototypeW), prototypeW, &prop);
+    if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) {
+        jsval_t val;
 
-        V_VT(&var) = VT_EMPTY;
-        memset(&jsexcept, 0, sizeof(jsexcept));
-        hres = prop_get(constr, prop, NULL, &var, &jsexcept, NULL/*FIXME*/);
+        hres = prop_get(constr, prop, NULL, &val, NULL);
         if(FAILED(hres)) {
             ERR("Could not get prototype\n");
             return hres;
         }
 
-        if(V_VT(&var) == VT_DISPATCH)
-            prot = iface_to_jsdisp((IUnknown*)V_DISPATCH(&var));
-        VariantClear(&var);
+        if(is_object_instance(val))
+            prot = iface_to_jsdisp((IUnknown*)get_object(val));
+        jsval_release(val);
     }
 
     hres = init_dispex(dispex, ctx, builtin_info, prot);
 
     if(prot)
         jsdisp_release(prot);
-    if(FAILED(hres))
-        return hres;
-
-    hres = ensure_prop_name(dispex, constructorW, FALSE, 0, &prop);
-    if(SUCCEEDED(hres)) {
-        jsexcept_t jsexcept;
-        VARIANT var;
-
-        V_VT(&var) = VT_DISPATCH;
-        V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(constr);
-        memset(&jsexcept, 0, sizeof(jsexcept));
-        hres = prop_put(dispex, prop, &var, &jsexcept, NULL/*FIXME*/);
-    }
-    if(FAILED(hres))
-        jsdisp_release(dispex);
-
     return hres;
 }
 
-DispatchEx *iface_to_jsdisp(IUnknown *iface)
+jsdisp_t *iface_to_jsdisp(IUnknown *iface)
 {
-    DispatchEx *ret;
+    jsdisp_t *ret;
     HRESULT hres;
 
     hres = IUnknown_QueryInterface(iface, &IID_IDispatchJS, (void**)&ret);
@@ -862,7 +1032,7 @@ DispatchEx *iface_to_jsdisp(IUnknown *iface)
     return ret;
 }
 
-HRESULT jsdisp_get_id(DispatchEx *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
+HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
 {
     dispex_prop_t *prop;
     HRESULT hres;
@@ -870,11 +1040,11 @@ HRESULT jsdisp_get_id(DispatchEx *jsdisp, const WCHAR *name, DWORD flags, DISPID
     if(flags & fdexNameEnsure)
         hres = ensure_prop_name(jsdisp, name, TRUE, PROPF_ENUM, &prop);
     else
-        hres = find_prop_name_prot(jsdisp, name, &prop);
+        hres = find_prop_name_prot(jsdisp, string_hash(name), name, &prop);
     if(FAILED(hres))
         return hres;
 
-    if(prop) {
+    if(prop && prop->type!=PROP_DELETED) {
         *id = prop_to_id(jsdisp, prop);
         return S_OK;
     }
@@ -883,71 +1053,212 @@ HRESULT jsdisp_get_id(DispatchEx *jsdisp, const WCHAR *name, DWORD flags, DISPID
     return DISP_E_UNKNOWNNAME;
 }
 
-HRESULT jsdisp_call_value(DispatchEx *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv,
-        jsexcept_t *ei, IServiceProvider *caller)
+HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
-    vdisp_t vdisp;
     HRESULT hres;
 
-    set_jsdisp(&vdisp, jsthis);
-    hres = jsthis->builtin_info->value_prop.invoke(jsthis->ctx, &vdisp, flags, dp, retv, ei, caller);
-    vdisp_release(&vdisp);
+    if(is_class(jsfunc, JSCLASS_FUNCTION)) {
+        hres = Function_invoke(jsfunc, jsthis, flags, argc, argv, r);
+    }else {
+        vdisp_t vdisp;
+
+        set_disp(&vdisp, jsthis);
+        hres = jsfunc->builtin_info->value_prop.invoke(jsfunc->ctx, &vdisp, flags, argc, argv, r);
+        vdisp_release(&vdisp);
+    }
     return hres;
 }
 
-HRESULT jsdisp_call(DispatchEx *disp, DISPID id, WORD flags, DISPPARAMS *dp, VARIANT *retv,
-        jsexcept_t *ei, IServiceProvider *caller)
+HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
     dispex_prop_t *prop;
 
-    memset(ei, 0, sizeof(*ei));
-    if(retv)
-        V_VT(retv) = VT_EMPTY;
-
     prop = get_prop(disp, id);
     if(!prop)
         return DISP_E_MEMBERNOTFOUND;
 
-    return invoke_prop_func(disp, disp, prop, flags, dp, retv, ei, caller);
+    return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
 }
 
-HRESULT jsdisp_call_name(DispatchEx *disp, const WCHAR *name, WORD flags, DISPPARAMS *dp, VARIANT *retv,
-        jsexcept_t *ei, IServiceProvider *caller)
+HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
     dispex_prop_t *prop;
     HRESULT hres;
 
-    hres = find_prop_name_prot(disp, name, &prop);
+    hres = find_prop_name_prot(disp, string_hash(name), name, &prop);
     if(FAILED(hres))
         return hres;
 
-    memset(ei, 0, sizeof(*ei));
-    if(retv)
-        V_VT(retv) = VT_EMPTY;
+    return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
+}
+
+HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *ret)
+{
+    IDispatchEx *dispex;
+    jsdisp_t *jsdisp;
+    VARIANT buf[6], retv;
+    DISPPARAMS dp;
+    unsigned i;
+    HRESULT hres;
+
+    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    if(jsdisp) {
+        if(flags & DISPATCH_PROPERTYPUT) {
+            FIXME("disp_call(propput) on builtin object\n");
+            return E_FAIL;
+        }
+
+        hres = jsdisp_call(jsdisp, id, flags, argc, argv, ret);
+        jsdisp_release(jsdisp);
+        return hres;
+    }
+
+    if(ret && argc)
+        flags |= DISPATCH_PROPERTYGET;
+
+    dp.cArgs = argc;
+
+    if(flags & DISPATCH_PROPERTYPUT) {
+        static DISPID propput_dispid = DISPID_PROPERTYPUT;
+
+        dp.cNamedArgs = 1;
+        dp.rgdispidNamedArgs = &propput_dispid;
+    }else {
+        dp.cNamedArgs = 0;
+        dp.rgdispidNamedArgs = NULL;
+    }
+
+    if(argc > 6) {
+        dp.rgvarg = heap_alloc(argc*sizeof(VARIANT));
+        if(!dp.rgvarg)
+            return E_OUTOFMEMORY;
+    }else {
+        dp.rgvarg = buf;
+    }
+
+    for(i=0; i<argc; i++) {
+        hres = jsval_to_variant(argv[i], dp.rgvarg+argc-i-1);
+        if(FAILED(hres)) {
+            while(i--)
+                VariantClear(dp.rgvarg+argc-i-1);
+            if(dp.rgvarg != buf)
+                heap_free(dp.rgvarg);
+            return hres;
+        }
+    }
+
+    V_VT(&retv) = VT_EMPTY;
+    clear_ei(ctx);
+    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+    if(SUCCEEDED(hres)) {
+        hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, &dp, ret ? &retv : NULL, &ctx->ei.ei,
+                &ctx->jscaller->IServiceProvider_iface);
+        IDispatchEx_Release(dispex);
+    }else {
+        UINT err = 0;
+
+        if(flags == DISPATCH_CONSTRUCT) {
+            WARN("IDispatch cannot be constructor\n");
+            return DISP_E_MEMBERNOTFOUND;
+        }
+
+        TRACE("using IDispatch\n");
+        hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, &dp, ret ? &retv : NULL, &ctx->ei.ei, &err);
+    }
 
-    return invoke_prop_func(disp, disp, prop, flags, dp, retv, ei, caller);
+    for(i=0; i<argc; i++)
+        VariantClear(dp.rgvarg+argc-i-1);
+    if(dp.rgvarg != buf)
+        heap_free(dp.rgvarg);
+    if(FAILED(hres))
+        return hres;
+
+    if(ret) {
+        hres = variant_to_jsval(&retv, ret);
+        VariantClear(&retv);
+    }
+    return hres;
 }
 
-HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *dp, VARIANT *retv,
-        jsexcept_t *ei, IServiceProvider *caller)
+HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *jsdisp;
+    jsdisp_t *jsdisp;
     IDispatchEx *dispex;
+    VARIANT buf[6], retv;
+    DISPPARAMS dp;
+    unsigned i;
     HRESULT hres;
 
     jsdisp = iface_to_jsdisp((IUnknown*)disp);
     if(jsdisp) {
-        hres = jsdisp_call(jsdisp, id, flags, dp, retv, ei, caller);
+        if(flags & DISPATCH_PROPERTYPUT) {
+            FIXME("disp_call(propput) on builtin object\n");
+            return E_FAIL;
+        }
+
+        hres = jsdisp_call_value(jsdisp, jsthis, flags, argc, argv, r);
         jsdisp_release(jsdisp);
         return hres;
     }
 
-    memset(ei, 0, sizeof(*ei));
+    if(r && argc)
+        flags |= DISPATCH_PROPERTYGET;
 
-    if(retv)
-        V_VT(retv) = VT_EMPTY;
     hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
     if(FAILED(hres)) {
+        TRACE("using IDispatch\n");
+        dispex = NULL;
+        jsthis = NULL;
+    }
+
+    if(jsthis) {
+        static DISPID this_id = DISPID_THIS;
+
+        dp.cArgs = argc+1;
+        dp.cNamedArgs = 1;
+        dp.rgdispidNamedArgs = &this_id;
+    }else {
+        dp.cArgs = argc;
+        dp.cNamedArgs = 0;
+        dp.rgdispidNamedArgs = NULL;
+    }
+
+    if(dp.cArgs > sizeof(buf)/sizeof(*buf)) {
+        dp.rgvarg = heap_alloc(dp.cArgs*sizeof(VARIANT));
+        if(!dp.rgvarg) {
+            if(dispex)
+                IDispatchEx_Release(dispex);
+            return E_OUTOFMEMORY;
+        }
+    }else {
+        dp.rgvarg = buf;
+    }
+
+    for(i=0; i<argc; i++) {
+        hres = jsval_to_variant(argv[i], dp.rgvarg+dp.cArgs-i-1);
+        if(FAILED(hres)) {
+            while(i--)
+                VariantClear(dp.rgvarg+dp.cArgs-i-1);
+            if(dp.rgvarg != buf)
+                heap_free(dp.rgvarg);
+            if(dispex)
+                IDispatchEx_Release(dispex);
+            return hres;
+        }
+    }
+    if(jsthis) {
+        V_VT(dp.rgvarg) = VT_DISPATCH;
+        V_DISPATCH(dp.rgvarg) = jsthis;
+    }
+
+    V_VT(&retv) = VT_EMPTY;
+    clear_ei(ctx);
+    if(dispex) {
+        hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, ctx->lcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei,
+                &ctx->jscaller->IServiceProvider_iface);
+        IDispatchEx_Release(dispex);
+    }else {
         UINT err = 0;
 
         if(flags == DISPATCH_CONSTRUCT) {
@@ -955,53 +1266,71 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DIS
             return DISP_E_MEMBERNOTFOUND;
         }
 
-        TRACE("using IDispatch\n");
-        return IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, dp, retv, &ei->ei, &err);
+        hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, ctx->lcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei, &err);
     }
 
-    hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, retv, &ei->ei, caller);
-    IDispatchEx_Release(dispex);
+    for(i=0; i<argc; i++)
+        VariantClear(dp.rgvarg+dp.cArgs-i-1);
+    if(dp.rgvarg != buf)
+        heap_free(dp.rgvarg);
+    if(FAILED(hres))
+        return hres;
+
+    if(!r)
+        return S_OK;
 
+    hres = variant_to_jsval(&retv, r);
+    VariantClear(&retv);
     return hres;
 }
 
-HRESULT jsdisp_propput_name(DispatchEx *obj, const WCHAR *name, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller)
+HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, jsval_t val)
 {
     dispex_prop_t *prop;
     HRESULT hres;
 
-    hres = ensure_prop_name(obj, name, FALSE, PROPF_ENUM, &prop);
+    hres = ensure_prop_name(obj, name, FALSE, flags, &prop);
     if(FAILED(hres))
         return hres;
 
-    return prop_put(obj, prop, val, ei, caller);
+    return prop_put(obj, prop, val, NULL);
 }
 
-HRESULT jsdisp_propput_const(DispatchEx *obj, const WCHAR *name, VARIANT *val)
+HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val)
+{
+    return jsdisp_propput(obj, name, PROPF_ENUM, val);
+}
+
+HRESULT jsdisp_propput_const(jsdisp_t *obj, const WCHAR *name, jsval_t val)
 {
     dispex_prop_t *prop;
     HRESULT hres;
 
-    hres = ensure_prop_name(obj, name, FALSE, PROPF_ENUM|PROPF_CONST, &prop);
+    hres = ensure_prop_name(obj, name, FALSE, PROPF_CONST, &prop);
     if(FAILED(hres))
         return hres;
 
-    return VariantCopy(&prop->u.var, val);
+    return jsval_copy(val, &prop->u.val);
 }
 
-HRESULT jsdisp_propput_idx(DispatchEx *obj, DWORD idx, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller)
+HRESULT jsdisp_propput_dontenum(jsdisp_t *obj, const WCHAR *name, jsval_t val)
+{
+    return jsdisp_propput(obj, name, 0, val);
+}
+
+HRESULT jsdisp_propput_idx(jsdisp_t *obj, DWORD idx, jsval_t val)
 {
     WCHAR buf[12];
 
     static const WCHAR formatW[] = {'%','d',0};
 
     sprintfW(buf, formatW, idx);
-    return jsdisp_propput_name(obj, buf, val, ei, caller);
+    return jsdisp_propput_name(obj, buf, val);
 }
 
-HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller)
+HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
 {
-    DispatchEx *jsdisp;
+    jsdisp_t *jsdisp;
     HRESULT hres;
 
     jsdisp = iface_to_jsdisp((IUnknown*)disp);
@@ -1010,49 +1339,59 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, VARIANT *val
 
         prop = get_prop(jsdisp, id);
         if(prop)
-            hres = prop_put(jsdisp, prop, val, ei, caller);
+            hres = prop_put(jsdisp, prop, val, NULL);
         else
             hres = DISP_E_MEMBERNOTFOUND;
 
         jsdisp_release(jsdisp);
     }else {
         DISPID dispid = DISPID_PROPERTYPUT;
-        DISPPARAMS dp  = {val, &dispid, 1, 1};
+        VARIANT var;
+        DISPPARAMS dp  = {&var, &dispid, 1, 1};
         IDispatchEx *dispex;
 
+        hres = jsval_to_variant(val, &var);
+        if(FAILED(hres))
+            return hres;
+
+        clear_ei(ctx);
         hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
         if(SUCCEEDED(hres)) {
-            hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, DISPATCH_PROPERTYPUT, &dp, NULL, &ei->ei, caller);
+            hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, DISPATCH_PROPERTYPUT, &dp, NULL, &ctx->ei.ei,
+                    &ctx->jscaller->IServiceProvider_iface);
             IDispatchEx_Release(dispex);
         }else {
             ULONG err = 0;
 
             TRACE("using IDispatch\n");
-            hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, DISPATCH_PROPERTYPUT, &dp, NULL, &ei->ei, &err);
+            hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, DISPATCH_PROPERTYPUT, &dp, NULL, &ctx->ei.ei, &err);
         }
+
+        VariantClear(&var);
     }
 
     return hres;
 }
 
-HRESULT jsdisp_propget_name(DispatchEx *obj, const WCHAR *name, VARIANT *var, jsexcept_t *ei, IServiceProvider *caller)
+HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val)
 {
     DISPPARAMS dp = {NULL, NULL, 0, 0};
     dispex_prop_t *prop;
     HRESULT hres;
 
-    hres = find_prop_name_prot(obj, name, &prop);
+    hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
     if(FAILED(hres))
         return hres;
 
-    V_VT(var) = VT_EMPTY;
-    if(!prop)
+    if(!prop || prop->type==PROP_DELETED) {
+        *val = jsval_undefined();
         return S_OK;
+    }
 
-    return prop_get(obj, prop, &dp, var, ei, caller);
+    return prop_get(obj, prop, &dp, val, NULL);
 }
 
-HRESULT jsdisp_get_idx(DispatchEx *obj, DWORD idx, VARIANT *var, jsexcept_t *ei, IServiceProvider *caller)
+HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r)
 {
     WCHAR name[12];
     DISPPARAMS dp = {NULL, NULL, 0, 0};
@@ -1063,18 +1402,19 @@ HRESULT jsdisp_get_idx(DispatchEx *obj, DWORD idx, VARIANT *var, jsexcept_t *ei,
 
     sprintfW(name, formatW, idx);
 
-    hres = find_prop_name_prot(obj, name, &prop);
+    hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
     if(FAILED(hres))
         return hres;
 
-    V_VT(var) = VT_EMPTY;
-    if(!prop)
+    if(!prop || prop->type==PROP_DELETED) {
+        *r = jsval_undefined();
         return DISP_E_UNKNOWNNAME;
+    }
 
-    return prop_get(obj, prop, &dp, var, ei, caller);
+    return prop_get(obj, prop, &dp, r, NULL);
 }
 
-HRESULT jsdisp_propget(DispatchEx *jsdisp, DISPID id, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller)
+HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val)
 {
     DISPPARAMS dp  = {NULL,NULL,0,0};
     dispex_prop_t *prop;
@@ -1083,50 +1423,171 @@ HRESULT jsdisp_propget(DispatchEx *jsdisp, DISPID id, VARIANT *val, jsexcept_t *
     if(!prop)
         return DISP_E_MEMBERNOTFOUND;
 
-    V_VT(val) = VT_EMPTY;
-    return prop_get(jsdisp, prop, &dp, val, ei, caller);
+    return prop_get(jsdisp, prop, &dp, val, NULL);
 }
 
-HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller)
+HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val)
 {
     DISPPARAMS dp  = {NULL,NULL,0,0};
     IDispatchEx *dispex;
-    DispatchEx *jsdisp;
+    jsdisp_t *jsdisp;
+    VARIANT var;
     HRESULT hres;
 
     jsdisp = iface_to_jsdisp((IUnknown*)disp);
     if(jsdisp) {
-        hres = jsdisp_propget(jsdisp, id, val, ei, caller);
+        hres = jsdisp_propget(jsdisp, id, val);
         jsdisp_release(jsdisp);
         return hres;
     }
 
+    V_VT(&var) = VT_EMPTY;
+    clear_ei(ctx);
     hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
-    if(FAILED(hres)) {
+    if(SUCCEEDED(hres)) {
+        hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, INVOKE_PROPERTYGET, &dp, &var, &ctx->ei.ei,
+                &ctx->jscaller->IServiceProvider_iface);
+        IDispatchEx_Release(dispex);
+    }else {
         ULONG err = 0;
 
         TRACE("using IDispatch\n");
-        return IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, INVOKE_PROPERTYGET, &dp, val, &ei->ei, &err);
+        hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, INVOKE_PROPERTYGET, &dp, &var, &ctx->ei.ei, &err);
     }
+    if(FAILED(hres))
+        return hres;
 
-    hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, INVOKE_PROPERTYGET, &dp, val, &ei->ei, caller);
-    IDispatchEx_Release(dispex);
-
+    hres = variant_to_jsval(&var, val);
+    VariantClear(&var);
     return hres;
 }
 
-HRESULT jsdisp_delete_idx(DispatchEx *obj, DWORD idx)
+HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx)
 {
     static const WCHAR formatW[] = {'%','d',0};
     WCHAR buf[12];
     dispex_prop_t *prop;
+    BOOL b;
     HRESULT hres;
 
     sprintfW(buf, formatW, idx);
 
-    hres = find_prop_name(obj, buf, &prop);
+    hres = find_prop_name(obj, string_hash(buf), buf, &prop);
     if(FAILED(hres) || !prop)
         return hres;
 
-    return delete_prop(prop);
+    return delete_prop(prop, &b);
+}
+
+HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret)
+{
+    IDispatchEx *dispex;
+    jsdisp_t *jsdisp;
+    HRESULT hres;
+
+    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    if(jsdisp) {
+        dispex_prop_t *prop;
+
+        prop = get_prop(jsdisp, id);
+        if(prop)
+            hres = delete_prop(prop, ret);
+        else
+            hres = DISP_E_MEMBERNOTFOUND;
+
+        jsdisp_release(jsdisp);
+        return hres;
+    }
+
+    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+    if(FAILED(hres)) {
+        *ret = FALSE;
+        return S_OK;
+    }
+
+    hres = IDispatchEx_DeleteMemberByDispID(dispex, id);
+    IDispatchEx_Release(dispex);
+    if(FAILED(hres))
+        return hres;
+
+    *ret = hres == S_OK;
+    return S_OK;
+}
+
+HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL *ret)
+{
+    IDispatchEx *dispex;
+    jsdisp_t *jsdisp;
+    BSTR bstr;
+    HRESULT hres;
+
+    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    if(jsdisp) {
+        dispex_prop_t *prop;
+
+        hres = find_prop_name(jsdisp, string_hash(name->str), name->str, &prop);
+        if(prop) {
+            hres = delete_prop(prop, ret);
+        }else {
+            *ret = TRUE;
+            hres = S_OK;
+        }
+
+        jsdisp_release(jsdisp);
+        return hres;
+    }
+
+    bstr = SysAllocStringLen(NULL, jsstr_length(name));
+    if(!bstr)
+        return E_OUTOFMEMORY;
+    jsstr_flush(name, bstr);
+
+    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+    if(SUCCEEDED(hres)) {
+        hres = IDispatchEx_DeleteMemberByName(dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive));
+        if(SUCCEEDED(hres))
+            *ret = hres == S_OK;
+        IDispatchEx_Release(dispex);
+    }else {
+        DISPID id;
+
+        hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id);
+        if(SUCCEEDED(hres)) {
+            /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
+            *ret = FALSE;
+        }else if(hres == DISP_E_UNKNOWNNAME) {
+            /* Property doesn't exist, so nothing to delete */
+            *ret = TRUE;
+            hres = S_OK;
+        }
+    }
+
+    SysFreeString(bstr);
+    return hres;
+}
+
+HRESULT jsdisp_is_own_prop(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
+{
+    dispex_prop_t *prop;
+    HRESULT hres;
+
+    hres = find_prop_name(obj, string_hash(name), name, &prop);
+    if(FAILED(hres))
+        return hres;
+
+    *ret = prop && (prop->type == PROP_JSVAL || prop->type == PROP_BUILTIN);
+    return S_OK;
+}
+
+HRESULT jsdisp_is_enumerable(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
+{
+    dispex_prop_t *prop;
+    HRESULT hres;
+
+    hres = find_prop_name(obj, string_hash(name), name, &prop);
+    if(FAILED(hres))
+        return hres;
+
+    *ret = prop && (prop->flags & PROPF_ENUM) && prop->type != PROP_PROTREF;
+    return S_OK;
 }
index 10581ec..bec0d11 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Jacek Caban for CodeWeavers
+ * Copyright 2008,2011 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
@@ -20,6 +20,7 @@
 #include <wine/port.h>
 
 //#include <math.h>
+#include <assert.h>
 
 #include "jscript.h"
 #include "engine.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 
-#define EXPR_NOVAL   0x0001
-#define EXPR_NEWREF  0x0002
-#define EXPR_STRREF  0x0004
+static const WCHAR booleanW[] = {'b','o','o','l','e','a','n',0};
+static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0};
+static const WCHAR numberW[] = {'n','u','m','b','e','r',0};
+static const WCHAR objectW[] = {'o','b','j','e','c','t',0};
+static const WCHAR stringW[] = {'s','t','r','i','n','g',0};
+static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
+static const WCHAR unknownW[] = {'u','n','k','n','o','w','n',0};
 
-static inline HRESULT stat_eval(exec_ctx_t *ctx, statement_t *stat, return_type_t *rt, VARIANT *ret)
+struct _except_frame_t {
+    unsigned stack_top;
+    scope_chain_t *scope;
+    unsigned catch_off;
+    BSTR ident;
+
+    except_frame_t *next;
+};
+
+static HRESULT stack_push(exec_ctx_t *ctx, jsval_t v)
+{
+    if(!ctx->stack_size) {
+        ctx->stack = heap_alloc(16*sizeof(*ctx->stack));
+        if(!ctx->stack)
+            return E_OUTOFMEMORY;
+        ctx->stack_size = 16;
+    }else if(ctx->stack_size == ctx->top) {
+        jsval_t *new_stack;
+
+        new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*new_stack));
+        if(!new_stack) {
+            jsval_release(v);
+            return E_OUTOFMEMORY;
+        }
+
+        ctx->stack = new_stack;
+        ctx->stack_size *= 2;
+    }
+
+    ctx->stack[ctx->top++] = v;
+    return S_OK;
+}
+
+static inline HRESULT stack_push_string(exec_ctx_t *ctx, const WCHAR *str)
+{
+    jsstr_t *v;
+
+    v = jsstr_alloc(str);
+    if(!v)
+        return E_OUTOFMEMORY;
+
+    return stack_push(ctx, jsval_string(v));
+}
+
+static HRESULT stack_push_objid(exec_ctx_t *ctx, IDispatch *disp, DISPID id)
+{
+    HRESULT hres;
+
+    hres = stack_push(ctx, jsval_disp(disp));
+    if(FAILED(hres))
+        return hres;
+
+    return stack_push(ctx, jsval_number(id));
+}
+
+static inline jsval_t stack_top(exec_ctx_t *ctx)
+{
+    assert(ctx->top);
+    return ctx->stack[ctx->top-1];
+}
+
+static inline jsval_t stack_topn(exec_ctx_t *ctx, unsigned n)
+{
+    assert(ctx->top > n);
+    return ctx->stack[ctx->top-1-n];
+}
+
+static inline jsval_t *stack_args(exec_ctx_t *ctx, unsigned n)
+{
+    if(!n)
+        return NULL;
+    assert(ctx->top > n-1);
+    return ctx->stack + ctx->top-n;
+}
+
+static inline jsval_t stack_pop(exec_ctx_t *ctx)
+{
+    assert(ctx->top);
+    return ctx->stack[--ctx->top];
+}
+
+static void stack_popn(exec_ctx_t *ctx, unsigned n)
+{
+    while(n--)
+        jsval_release(stack_pop(ctx));
+}
+
+static HRESULT stack_pop_number(exec_ctx_t *ctx, double *r)
+{
+    jsval_t v;
+    HRESULT hres;
+
+    v = stack_pop(ctx);
+    hres = to_number(ctx->script, v, r);
+    jsval_release(v);
+    return hres;
+}
+
+static HRESULT stack_pop_object(exec_ctx_t *ctx, IDispatch **r)
+{
+    jsval_t v;
+    HRESULT hres;
+
+    v = stack_pop(ctx);
+    if(is_object_instance(v)) {
+        if(!get_object(v))
+            return throw_type_error(ctx->script, JS_E_OBJECT_REQUIRED, NULL);
+        *r = get_object(v);
+        return S_OK;
+    }
+
+    hres = to_object(ctx->script, v, r);
+    jsval_release(v);
+    return hres;
+}
+
+static inline HRESULT stack_pop_int(exec_ctx_t *ctx, INT *r)
+{
+    return to_int32(ctx->script, stack_pop(ctx), r);
+}
+
+static inline HRESULT stack_pop_uint(exec_ctx_t *ctx, DWORD *r)
+{
+    return to_uint32(ctx->script, stack_pop(ctx), r);
+}
+
+static inline IDispatch *stack_pop_objid(exec_ctx_t *ctx, DISPID *id)
 {
-    return stat->eval(ctx, stat, rt, ret);
+    assert(is_number(stack_top(ctx)) && is_object_instance(stack_topn(ctx, 1)));
+
+    *id = get_number(stack_pop(ctx));
+    return get_object(stack_pop(ctx));
 }
 
-static inline HRESULT expr_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static inline IDispatch *stack_topn_objid(exec_ctx_t *ctx, unsigned n, DISPID *id)
 {
-    return _expr->eval(ctx, _expr, flags, ei, ret);
+    assert(is_number(stack_topn(ctx, n)) && is_object_instance(stack_topn(ctx, n+1)));
+
+    *id = get_number(stack_topn(ctx, n));
+    return get_object(stack_topn(ctx, n+1));
 }
 
 static void exprval_release(exprval_t *val)
 {
     switch(val->type) {
-    case EXPRVAL_VARIANT:
-        if(V_VT(&val->u.var) != VT_EMPTY)
-            VariantClear(&val->u.var);
+    case EXPRVAL_JSVAL:
+        jsval_release(val->u.val);
         return;
     case EXPRVAL_IDREF:
         if(val->u.idref.disp)
             IDispatch_Release(val->u.idref.disp);
         return;
-    case EXPRVAL_NAMEREF:
-        if(val->u.nameref.disp)
-            IDispatch_Release(val->u.nameref.disp);
-        SysFreeString(val->u.nameref.name);
-        return;
     case EXPRVAL_INVALID:
-        SysFreeString(val->u.identifier);
+        return;
     }
 }
 
 /* ECMA-262 3rd Edition    8.7.1 */
-static HRESULT exprval_value(script_ctx_t *ctx, exprval_t *val, jsexcept_t *ei, VARIANT *ret)
+static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *val, jsval_t *ret)
 {
-    V_VT(ret) = VT_EMPTY;
-
     switch(val->type) {
-    case EXPRVAL_VARIANT:
-        return VariantCopy(ret, &val->u.var);
+    case EXPRVAL_JSVAL:
+        *ret = val->u.val;
+        val->u.val = jsval_undefined();
+        return S_OK;
     case EXPRVAL_IDREF:
         if(!val->u.idref.disp) {
             FIXME("throw ReferenceError\n");
             return E_FAIL;
         }
 
-        return disp_propget(ctx, val->u.idref.disp, val->u.idref.id, ret, ei, NULL/*FIXME*/);
-    case EXPRVAL_NAMEREF:
-        break;
+        return disp_propget(ctx, val->u.idref.disp, val->u.idref.id, ret);
     case EXPRVAL_INVALID:
-        return throw_type_error(ctx, ei, IDS_UNDEFINED, val->u.identifier);
+        assert(0);
     }
 
     ERR("type %d\n", val->type);
     return E_FAIL;
 }
 
-static HRESULT exprval_to_value(script_ctx_t *ctx, exprval_t *val, jsexcept_t *ei, VARIANT *ret)
-{
-    if(val->type == EXPRVAL_VARIANT) {
-        *ret = val->u.var;
-        V_VT(&val->u.var) = VT_EMPTY;
-        return S_OK;
-    }
-
-    return exprval_value(ctx, val, ei, ret);
-}
-
-static HRESULT exprval_to_boolean(script_ctx_t *ctx, exprval_t *exprval, jsexcept_t *ei, VARIANT_BOOL *b)
-{
-    if(exprval->type != EXPRVAL_VARIANT) {
-        VARIANT val;
-        HRESULT hres;
-
-        hres = exprval_to_value(ctx, exprval, ei, &val);
-        if(FAILED(hres))
-            return hres;
-
-        hres = to_boolean(&val, b);
-        VariantClear(&val);
-        return hres;
-    }
-
-    return to_boolean(&exprval->u.var, b);
-}
-
-static void exprval_init(exprval_t *val)
-{
-    val->type = EXPRVAL_VARIANT;
-    V_VT(&val->u.var) = VT_EMPTY;
-}
-
 static void exprval_set_idref(exprval_t *val, IDispatch *disp, DISPID id)
 {
     val->type = EXPRVAL_IDREF;
@@ -133,7 +227,7 @@ static void exprval_set_idref(exprval_t *val, IDispatch *disp, DISPID id)
         IDispatch_AddRef(disp);
 }
 
-HRESULT scope_push(scope_chain_t *scope, DispatchEx *obj, scope_chain_t **ret)
+HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret)
 {
     scope_chain_t *new_scope;
 
@@ -143,7 +237,8 @@ HRESULT scope_push(scope_chain_t *scope, DispatchEx *obj, scope_chain_t **ret)
 
     new_scope->ref = 1;
 
-    IDispatchEx_AddRef(_IDispatchEx_(obj));
+    IDispatch_AddRef(obj);
+    new_scope->jsobj = jsobj;
     new_scope->obj = obj;
 
     if(scope) {
@@ -166,6 +261,13 @@ static void scope_pop(scope_chain_t **scope)
     scope_release(tmp);
 }
 
+void clear_ei(script_ctx_t *ctx)
+{
+    memset(&ctx->ei.ei, 0, sizeof(ctx->ei.ei));
+    jsval_release(ctx->ei.val);
+    ctx->ei.val = jsval_undefined();
+}
+
 void scope_release(scope_chain_t *scope)
 {
     if(--scope->ref)
@@ -174,12 +276,12 @@ void scope_release(scope_chain_t *scope)
     if(scope->next)
         scope_release(scope->next);
 
-    jsdisp_release(scope->obj);
+    IDispatch_Release(scope->obj);
     heap_free(scope);
 }
 
-HRESULT create_exec_ctx(script_ctx_t *script_ctx, IDispatch *this_obj, DispatchEx *var_disp,
-        scope_chain_t *scope, exec_ctx_t **ret)
+HRESULT create_exec_ctx(script_ctx_t *script_ctx, IDispatch *this_obj, jsdisp_t *var_disp,
+        scope_chain_t *scope, BOOL is_global, exec_ctx_t **ret)
 {
     exec_ctx_t *ctx;
 
@@ -188,18 +290,35 @@ HRESULT create_exec_ctx(script_ctx_t *script_ctx, IDispatch *this_obj, DispatchE
         return E_OUTOFMEMORY;
 
     ctx->ref = 1;
+    ctx->is_global = is_global;
+    ctx->ret = jsval_undefined();
+
+    /* ECMA-262 3rd Edition    11.2.3.7 */
+    if(this_obj) {
+        jsdisp_t *jsthis;
+
+        jsthis = iface_to_jsdisp((IUnknown*)this_obj);
+        if(jsthis) {
+            if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE)
+                this_obj = NULL;
+            jsdisp_release(jsthis);
+        }
+    }
 
     if(this_obj)
         ctx->this_obj = this_obj;
     else if(script_ctx->host_global)
         ctx->this_obj = script_ctx->host_global;
     else
-        ctx->this_obj = (IDispatch*)_IDispatchEx_(script_ctx->global);
+        ctx->this_obj = to_disp(script_ctx->global);
     IDispatch_AddRef(ctx->this_obj);
 
-    IDispatchEx_AddRef(_IDispatchEx_(var_disp));
+    jsdisp_addref(var_disp);
     ctx->var_disp = var_disp;
 
+    script_addref(script_ctx);
+    ctx->script = script_ctx;
+
     if(scope) {
         scope_addref(scope);
         ctx->scope_chain = scope;
@@ -220,38 +339,51 @@ void exec_release(exec_ctx_t *ctx)
         jsdisp_release(ctx->var_disp);
     if(ctx->this_obj)
         IDispatch_Release(ctx->this_obj);
+    if(ctx->script)
+        script_release(ctx->script);
+    jsval_release(ctx->ret);
+    heap_free(ctx->stack);
     heap_free(ctx);
 }
 
-static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, BSTR name, DWORD flags, DISPID *id)
+static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, WCHAR *name, BSTR name_bstr, DWORD flags, DISPID *id)
 {
     IDispatchEx *dispex;
+    jsdisp_t *jsdisp;
+    BSTR bstr;
     HRESULT hres;
 
-    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
-    if(FAILED(hres)) {
-        TRACE("unsing IDispatch\n");
+    jsdisp = iface_to_jsdisp((IUnknown*)disp);
+    if(jsdisp) {
+        hres = jsdisp_get_id(jsdisp, name, flags, id);
+        jsdisp_release(jsdisp);
+        return hres;
+    }
 
-        *id = 0;
-        return IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, id);
+    if(name_bstr) {
+        bstr = name_bstr;
+    }else {
+        bstr = SysAllocString(name);
+        if(!bstr)
+            return E_OUTOFMEMORY;
     }
 
     *id = 0;
-    hres = IDispatchEx_GetDispID(dispex, name, make_grfdex(ctx, flags|fdexNameCaseSensitive), id);
-    IDispatchEx_Release(dispex);
-    return hres;
-}
-
-/* ECMA-262 3rd Edition    8.7.2 */
-static HRESULT put_value(script_ctx_t *ctx, exprval_t *ref, VARIANT *v, jsexcept_t *ei)
-{
-    if(ref->type != EXPRVAL_IDREF)
-        return throw_reference_error(ctx, ei, IDS_ILLEGAL_ASSIGN, NULL);
+    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+    if(SUCCEEDED(hres)) {
+        hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, flags|fdexNameCaseSensitive), id);
+        IDispatchEx_Release(dispex);
+    }else {
+        TRACE("using IDispatch\n");
+        hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, id);
+    }
 
-    return disp_propput(ctx, ref->u.idref.disp, ref->u.idref.id, v, ei, NULL/*FIXME*/);
+    if(name_bstr != bstr)
+        SysFreeString(bstr);
+    return hres;
 }
 
-static inline BOOL is_null(const VARIANT *v)
+static inline BOOL var_is_null(const VARIANT *v)
 {
     return V_VT(v) == VT_NULL || (V_VT(v) == VT_DISPATCH && !V_DISPATCH(v));
 }
@@ -301,96 +433,44 @@ static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret)
 }
 
 /* ECMA-262 3rd Edition    11.9.6 */
-static HRESULT equal2_values(VARIANT *lval, VARIANT *rval, BOOL *ret)
+static HRESULT equal2_values(jsval_t lval, jsval_t rval, BOOL *ret)
 {
+    jsval_type_t type = jsval_type(lval);
+
     TRACE("\n");
 
-    if(V_VT(lval) != V_VT(rval)) {
-        if(is_num_vt(V_VT(lval)) && is_num_vt(V_VT(rval)))
-            *ret = num_val(lval) == num_val(rval);
-        else if(is_null(lval))
-            *ret = is_null(rval);
+    if(type != jsval_type(rval)) {
+        if(is_null_instance(lval))
+            *ret = is_null_instance(rval);
         else
             *ret = FALSE;
         return S_OK;
     }
 
-    switch(V_VT(lval)) {
-    case VT_EMPTY:
-    case VT_NULL:
-        *ret = VARIANT_TRUE;
-        break;
-    case VT_I4:
-        *ret = V_I4(lval) == V_I4(rval);
+    switch(type) {
+    case JSV_UNDEFINED:
+    case JSV_NULL:
+        *ret = TRUE;
         break;
-    case VT_R8:
-        *ret = V_R8(lval) == V_R8(rval);
+    case JSV_OBJECT:
+        return disp_cmp(get_object(lval), get_object(rval), ret);
+    case JSV_STRING:
+        *ret = jsstr_eq(get_string(lval), get_string(rval));
         break;
-    case VT_BSTR:
-        if(!V_BSTR(lval))
-            *ret = SysStringLen(V_BSTR(rval))?FALSE:TRUE;
-        else if(!V_BSTR(rval))
-            *ret = SysStringLen(V_BSTR(lval))?FALSE:TRUE;
-        else
-            *ret = !strcmpW(V_BSTR(lval), V_BSTR(rval));
+    case JSV_NUMBER:
+        *ret = get_number(lval) == get_number(rval);
         break;
-    case VT_DISPATCH:
-        return disp_cmp(V_DISPATCH(lval), V_DISPATCH(rval), ret);
-    case VT_BOOL:
-        *ret = !V_BOOL(lval) == !V_BOOL(rval);
+    case JSV_BOOL:
+        *ret = !get_bool(lval) == !get_bool(rval);
         break;
-    default:
-        FIXME("unimplemented vt %d\n", V_VT(lval));
+    case JSV_VARIANT:
+        FIXME("VARIANT not implemented\n");
         return E_NOTIMPL;
     }
 
     return S_OK;
 }
 
-static HRESULT literal_to_var(script_ctx_t *ctx, literal_t *literal, VARIANT *v)
-{
-    switch(literal->type) {
-    case LT_NULL:
-        V_VT(v) = VT_NULL;
-        break;
-    case LT_INT:
-        V_VT(v) = VT_I4;
-        V_I4(v) = literal->u.lval;
-        break;
-    case LT_DOUBLE:
-        V_VT(v) = VT_R8;
-        V_R8(v) = literal->u.dval;
-        break;
-    case LT_STRING: {
-        BSTR str = SysAllocString(literal->u.wstr);
-        if(!str)
-            return E_OUTOFMEMORY;
-
-        V_VT(v) = VT_BSTR;
-        V_BSTR(v) = str;
-        break;
-    }
-    case LT_BOOL:
-        V_VT(v) = VT_BOOL;
-        V_BOOL(v) = literal->u.bval;
-        break;
-    case LT_REGEXP: {
-        DispatchEx *regexp;
-        HRESULT hres;
-
-        hres = create_regexp(ctx, literal->u.regexp.str, literal->u.regexp.str_len,
-                             literal->u.regexp.flags, &regexp);
-        if(FAILED(hres))
-            return hres;
-
-        V_VT(v) = VT_DISPATCH;
-        V_DISPATCH(v) = (IDispatch*)_IDispatchEx_(regexp);
-    }
-    }
-
-    return S_OK;
-}
-
 static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
 {
     named_item_t *item;
@@ -399,7 +479,7 @@ static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t
 
     for(item = ctx->named_items; item; item = item->next) {
         if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
-            hres = disp_get_id(ctx, item->disp, identifier, 0, &id);
+            hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id);
             if(SUCCEEDED(hres)) {
                 if(ret)
                     exprval_set_idref(ret, item->disp, id);
@@ -411,99 +491,8 @@ static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t
     return FALSE;
 }
 
-HRESULT exec_source(exec_ctx_t *ctx, parser_ctx_t *parser, source_elements_t *source, exec_type_t exec_type,
-        jsexcept_t *ei, VARIANT *retv)
-{
-    script_ctx_t *script = parser->script;
-    function_declaration_t *func;
-    parser_ctx_t *prev_parser;
-    var_list_t *var;
-    VARIANT val, tmp;
-    statement_t *stat;
-    exec_ctx_t *prev_ctx;
-    return_type_t rt;
-    HRESULT hres = S_OK;
-
-    for(func = source->functions; func; func = func->next) {
-        DispatchEx *func_obj;
-        VARIANT var;
-
-        hres = create_source_function(parser, func->expr->parameter_list, func->expr->source_elements,
-                ctx->scope_chain, func->expr->src_str, func->expr->src_len, &func_obj);
-        if(FAILED(hres))
-            return hres;
-
-        V_VT(&var) = VT_DISPATCH;
-        V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(func_obj);
-        hres = jsdisp_propput_name(ctx->var_disp, func->expr->identifier, &var, ei, NULL);
-        jsdisp_release(func_obj);
-        if(FAILED(hres))
-            return hres;
-    }
-
-    for(var = source->variables; var; var = var->next) {
-        DISPID id = 0;
-        BSTR name;
-
-        name = SysAllocString(var->identifier);
-        if(!name)
-            return E_OUTOFMEMORY;
-
-        if(!lookup_global_members(parser->script, name, NULL))
-            hres = jsdisp_get_id(ctx->var_disp, var->identifier, fdexNameEnsure, &id);
-        SysFreeString(name);
-        if(FAILED(hres))
-            return hres;
-    }
-
-    prev_ctx = script->exec_ctx;
-    script->exec_ctx = ctx;
-
-    prev_parser = ctx->parser;
-    ctx->parser = parser;
-
-    V_VT(&val) = VT_EMPTY;
-    memset(&rt, 0, sizeof(rt));
-    rt.type = RT_NORMAL;
-
-    for(stat = source->statement; stat; stat = stat->next) {
-        hres = stat_eval(ctx, stat, &rt, &tmp);
-        if(FAILED(hres))
-            break;
-
-        VariantClear(&val);
-        val = tmp;
-        if(rt.type != RT_NORMAL)
-            break;
-    }
-
-    script->exec_ctx = prev_ctx;
-    ctx->parser = prev_parser;
-
-    if(rt.type != RT_NORMAL && rt.type != RT_RETURN) {
-        FIXME("wrong rt %d\n", rt.type);
-        hres = E_FAIL;
-    }
-
-    *ei = rt.ei;
-    if(FAILED(hres)) {
-        VariantClear(&val);
-        return hres;
-    }
-
-    if(retv && (exec_type == EXECT_EVAL || rt.type == RT_RETURN))
-        *retv = val;
-    else {
-        if (retv) {
-            VariantInit(retv);
-        }
-        VariantClear(&val);
-    }
-    return S_OK;
-}
-
 /* ECMA-262 3rd Edition    10.1.4 */
-static HRESULT identifier_eval(exec_ctx_t *ctx, BSTR identifier, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *ret)
 {
     scope_chain_t *scope;
     named_item_t *item;
@@ -512,32 +501,32 @@ static HRESULT identifier_eval(exec_ctx_t *ctx, BSTR identifier, DWORD flags, js
 
     TRACE("%s\n", debugstr_w(identifier));
 
-    for(scope = ctx->scope_chain; scope; scope = scope->next) {
-        hres = jsdisp_get_id(scope->obj, identifier, 0, &id);
-        if(SUCCEEDED(hres))
-            break;
-    }
-
-    if(scope) {
-        exprval_set_idref(ret, (IDispatch*)_IDispatchEx_(scope->obj), id);
-        return S_OK;
+    for(scope = ctx->exec_ctx->scope_chain; scope; scope = scope->next) {
+        if(scope->jsobj)
+            hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id);
+        else
+            hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id);
+        if(SUCCEEDED(hres)) {
+            exprval_set_idref(ret, scope->obj, id);
+            return S_OK;
+        }
     }
 
-    hres = jsdisp_get_id(ctx->parser->script->global, identifier, 0, &id);
+    hres = jsdisp_get_id(ctx->global, identifier, 0, &id);
     if(SUCCEEDED(hres)) {
-        exprval_set_idref(ret, (IDispatch*)_IDispatchEx_(ctx->parser->script->global), id);
+        exprval_set_idref(ret, to_disp(ctx->global), id);
         return S_OK;
     }
 
-    for(item = ctx->parser->script->named_items; item; item = item->next) {
+    for(item = ctx->named_items; item; item = item->next) {
         if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpW(item->name, identifier)) {
             if(!item->disp) {
                 IUnknown *unk;
 
-                if(!ctx->parser->script->site)
+                if(!ctx->site)
                     break;
 
-                hres = IActiveScriptSite_GetItemInfo(ctx->parser->script->site, identifier,
+                hres = IActiveScriptSite_GetItemInfo(ctx->site, identifier,
                                                      SCRIPTINFO_IUNKNOWN, &unk, NULL);
                 if(FAILED(hres)) {
                     WARN("GetItemInfo failed: %08x\n", hres);
@@ -552,1485 +541,837 @@ static HRESULT identifier_eval(exec_ctx_t *ctx, BSTR identifier, DWORD flags, js
                 }
             }
 
-            ret->type = EXPRVAL_VARIANT;
-            V_VT(&ret->u.var) = VT_DISPATCH;
-            V_DISPATCH(&ret->u.var) = item->disp;
             IDispatch_AddRef(item->disp);
+            ret->type = EXPRVAL_JSVAL;
+            ret->u.val = jsval_disp(item->disp);
             return S_OK;
         }
     }
 
-    if(lookup_global_members(ctx->parser->script, identifier, ret))
+    if(lookup_global_members(ctx, identifier, ret))
         return S_OK;
 
-    if(flags & EXPR_NEWREF) {
-        hres = jsdisp_get_id(ctx->parser->script->global, identifier, fdexNameEnsure, &id);
-        if(FAILED(hres))
-            return hres;
+    ret->type = EXPRVAL_INVALID;
+    return S_OK;
+}
 
-        exprval_set_idref(ret, (IDispatch*)_IDispatchEx_(ctx->parser->script->global), id);
-        return S_OK;
-    }
+static inline BSTR get_op_bstr(exec_ctx_t *ctx, int i){
+    return ctx->code->instrs[ctx->ip].u.arg[i].bstr;
+}
 
-    ret->type = EXPRVAL_INVALID;
-    ret->u.identifier = SysAllocString(identifier);
-    if(!ret->u.identifier)
-        return E_OUTOFMEMORY;
+static inline unsigned get_op_uint(exec_ctx_t *ctx, int i){
+    return ctx->code->instrs[ctx->ip].u.arg[i].uint;
+}
 
-    return S_OK;
+static inline unsigned get_op_int(exec_ctx_t *ctx, int i){
+    return ctx->code->instrs[ctx->ip].u.arg[i].lng;
+}
+
+static inline jsstr_t *get_op_str(exec_ctx_t *ctx, int i){
+    return ctx->code->instrs[ctx->ip].u.arg[i].str;
+}
+
+static inline double get_op_double(exec_ctx_t *ctx){
+    return ctx->code->instrs[ctx->ip].u.dbl;
 }
 
-/* ECMA-262 3rd Edition    12.1 */
-HRESULT block_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    12.2 */
+static HRESULT interp_var_set(exec_ctx_t *ctx)
 {
-    block_statement_t *stat = (block_statement_t*)_stat;
-    VARIANT val, tmp;
-    statement_t *iter;
-    HRESULT hres = S_OK;
+    const BSTR name = get_op_bstr(ctx, 0);
+    jsval_t val;
+    HRESULT hres;
 
-    TRACE("\n");
+    TRACE("%s\n", debugstr_w(name));
 
-    V_VT(&val) = VT_EMPTY;
-    for(iter = stat->stat_list; iter; iter = iter->next) {
-        hres = stat_eval(ctx, iter, rt, &tmp);
-        if(FAILED(hres))
-            break;
+    val = stack_pop(ctx);
+    hres = jsdisp_propput_name(ctx->var_disp, name, val);
+    jsval_release(val);
+    return hres;
+}
 
-        VariantClear(&val);
-        val = tmp;
-        if(rt->type != RT_NORMAL)
-            break;
-    }
+/* ECMA-262 3rd Edition    12.6.4 */
+static HRESULT interp_forin(exec_ctx_t *ctx)
+{
+    const HRESULT arg = get_op_uint(ctx, 0);
+    IDispatch *var_obj, *obj = NULL;
+    IDispatchEx *dispex;
+    DISPID id, var_id;
+    BSTR name = NULL;
+    HRESULT hres;
 
-    if(FAILED(hres)) {
-        VariantClear(&val);
-        return hres;
+    TRACE("\n");
+
+    assert(is_number(stack_top(ctx)));
+    id = get_number(stack_top(ctx));
+
+    var_obj = stack_topn_objid(ctx, 1, &var_id);
+    if(!var_obj) {
+        FIXME("invalid ref\n");
+        return E_FAIL;
     }
 
-    *ret = val;
-    return S_OK;
-}
+    if(is_object_instance(stack_topn(ctx, 3)))
+        obj = get_object(stack_topn(ctx, 3));
 
-/* ECMA-262 3rd Edition    12.2 */
-static HRESULT variable_list_eval(exec_ctx_t *ctx, variable_declaration_t *var_list, jsexcept_t *ei)
-{
-    variable_declaration_t *iter;
-    HRESULT hres = S_OK;
+    if(obj) {
+        hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
+        if(SUCCEEDED(hres)) {
+            hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id);
+            if(hres == S_OK)
+                hres = IDispatchEx_GetMemberName(dispex, id, &name);
+            IDispatchEx_Release(dispex);
+            if(FAILED(hres))
+                return hres;
+        }else {
+            TRACE("No IDispatchEx\n");
+        }
+    }
 
-    for(iter = var_list; iter; iter = iter->next) {
-        exprval_t exprval;
-        VARIANT val;
+    if(name) {
+        jsstr_t *str;
 
-        if(!iter->expr)
-            continue;
+        str = jsstr_alloc_len(name, SysStringLen(name));
+        SysFreeString(name);
+        if(!str)
+            return E_OUTOFMEMORY;
 
-        hres = expr_eval(ctx, iter->expr, 0, ei, &exprval);
-        if(FAILED(hres))
-            break;
+        stack_pop(ctx);
+        stack_push(ctx, jsval_number(id)); /* safe, just after pop() */
 
-        hres = exprval_to_value(ctx->parser->script, &exprval, ei, &val);
-        exprval_release(&exprval);
+        hres = disp_propput(ctx->script, var_obj, var_id, jsval_string(str));
+        jsstr_release(str);
         if(FAILED(hres))
-            break;
+            return hres;
 
-        hres = jsdisp_propput_name(ctx->var_disp, iter->identifier, &val, ei, NULL/*FIXME*/);
-        VariantClear(&val);
-        if(FAILED(hres))
-            break;
+        ctx->ip++;
+    }else {
+        stack_popn(ctx, 4);
+        ctx->ip = arg;
     }
-
-    return hres;
+    return S_OK;
 }
 
-/* ECMA-262 3rd Edition    12.2 */
-HRESULT var_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    12.10 */
+static HRESULT interp_push_scope(exec_ctx_t *ctx)
 {
-    var_statement_t *stat = (var_statement_t*)_stat;
+    IDispatch *disp;
+    jsval_t v;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = variable_list_eval(ctx, stat->variable_list, &rt->ei);
+    v = stack_pop(ctx);
+    hres = to_object(ctx->script, v, &disp);
+    jsval_release(v);
     if(FAILED(hres))
         return hres;
 
-    V_VT(ret) = VT_EMPTY;
-    return S_OK;
+    hres = scope_push(ctx->scope_chain, to_jsdisp(disp), disp, &ctx->scope_chain);
+    IDispatch_Release(disp);
+    return hres;
 }
 
-/* ECMA-262 3rd Edition    12.3 */
-HRESULT empty_statement_eval(exec_ctx_t *ctx, statement_t *stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    12.10 */
+static HRESULT interp_pop_scope(exec_ctx_t *ctx)
 {
     TRACE("\n");
 
-    V_VT(ret) = VT_EMPTY;
+    scope_pop(&ctx->scope_chain);
     return S_OK;
 }
 
-/* ECMA-262 3rd Edition    12.4 */
-HRESULT expression_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    12.13 */
+static HRESULT interp_case(exec_ctx_t *ctx)
 {
-    expression_statement_t *stat = (expression_statement_t*)_stat;
-    exprval_t exprval;
-    VARIANT val;
+    const unsigned arg = get_op_uint(ctx, 0);
+    jsval_t v;
+    BOOL b;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = expr_eval(ctx, stat->expr, EXPR_NOVAL, &rt->ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = exprval_to_value(ctx->parser->script, &exprval, &rt->ei, &val);
-    exprval_release(&exprval);
+    v = stack_pop(ctx);
+    hres = equal2_values(stack_top(ctx), v, &b);
+    jsval_release(v);
     if(FAILED(hres))
         return hres;
 
-    *ret = val;
-    TRACE("= %s\n", debugstr_variant(ret));
+    if(b) {
+        stack_popn(ctx, 1);
+        ctx->ip = arg;
+    }else {
+        ctx->ip++;
+    }
     return S_OK;
 }
 
-/* ECMA-262 3rd Edition    12.5 */
-HRESULT if_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    12.13 */
+static HRESULT interp_throw(exec_ctx_t *ctx)
 {
-    if_statement_t *stat = (if_statement_t*)_stat;
-    exprval_t exprval;
-    VARIANT_BOOL b;
-    HRESULT hres;
-
     TRACE("\n");
 
-    hres = expr_eval(ctx, stat->expr, 0, &rt->ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = exprval_to_boolean(ctx->parser->script, &exprval, &rt->ei, &b);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
-
-    if(b)
-        hres = stat_eval(ctx, stat->if_stat, rt, ret);
-    else if(stat->else_stat)
-        hres = stat_eval(ctx, stat->else_stat, rt, ret);
-    else
-        V_VT(ret) = VT_EMPTY;
-
-    return hres;
+    jsval_release(ctx->script->ei.val);
+    ctx->script->ei.val = stack_pop(ctx);
+    return DISP_E_EXCEPTION;
 }
 
-/* ECMA-262 3rd Edition    12.6.2 */
-HRESULT while_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+static HRESULT interp_throw_ref(exec_ctx_t *ctx)
 {
-    while_statement_t *stat = (while_statement_t*)_stat;
-    exprval_t exprval;
-    VARIANT val, tmp;
-    VARIANT_BOOL b;
-    BOOL test_expr;
-    HRESULT hres;
-
-    TRACE("\n");
-
-    V_VT(&val) = VT_EMPTY;
-    test_expr = !stat->do_while;
-
-    while(1) {
-        if(test_expr) {
-            hres = expr_eval(ctx, stat->expr, 0, &rt->ei, &exprval);
-            if(FAILED(hres))
-                break;
-
-            hres = exprval_to_boolean(ctx->parser->script, &exprval, &rt->ei, &b);
-            exprval_release(&exprval);
-            if(FAILED(hres) || !b)
-                break;
-        }else {
-            test_expr = TRUE;
-        }
-
-        hres = stat_eval(ctx, stat->statement, rt, &tmp);
-        if(FAILED(hres))
-            break;
+    const HRESULT arg = get_op_uint(ctx, 0);
 
-        VariantClear(&val);
-        val = tmp;
+    TRACE("%08x\n", arg);
 
-        if(rt->type == RT_CONTINUE)
-            rt->type = RT_NORMAL;
-        if(rt->type != RT_NORMAL)
-            break;
-    }
-
-    if(FAILED(hres)) {
-        VariantClear(&val);
-        return hres;
-    }
-
-    if(rt->type == RT_BREAK)
-        rt->type = RT_NORMAL;
-
-    *ret = val;
-    return S_OK;
+    return throw_reference_error(ctx->script, arg, NULL);
 }
 
-/* ECMA-262 3rd Edition    12.6.3 */
-HRESULT for_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+static HRESULT interp_throw_type(exec_ctx_t *ctx)
 {
-    for_statement_t *stat = (for_statement_t*)_stat;
-    VARIANT val, tmp, retv;
-    exprval_t exprval;
-    VARIANT_BOOL b;
-    HRESULT hres;
-
-    TRACE("\n");
-
-    if(stat->variable_list) {
-        hres = variable_list_eval(ctx, stat->variable_list, &rt->ei);
-        if(FAILED(hres))
-            return hres;
-    }else if(stat->begin_expr) {
-        hres = expr_eval(ctx, stat->begin_expr, EXPR_NEWREF, &rt->ei, &exprval);
-        if(FAILED(hres))
-            return hres;
-
-        hres = exprval_to_value(ctx->parser->script, &exprval, &rt->ei, &val);
-        exprval_release(&exprval);
-        if(FAILED(hres))
-            return hres;
-
-        VariantClear(&val);
-    }
+    const HRESULT hres = get_op_uint(ctx, 0);
+    jsstr_t *str = get_op_str(ctx, 1);
 
-    V_VT(&retv) = VT_EMPTY;
+    TRACE("%08x %s\n", hres, debugstr_jsstr(str));
 
-    while(1) {
-        if(stat->expr) {
-            hres = expr_eval(ctx, stat->expr, 0, &rt->ei, &exprval);
-            if(FAILED(hres))
-                break;
-
-            hres = exprval_to_boolean(ctx->parser->script, &exprval, &rt->ei, &b);
-            exprval_release(&exprval);
-            if(FAILED(hres) || !b)
-                break;
-        }
-
-        hres = stat_eval(ctx, stat->statement, rt, &tmp);
-        if(FAILED(hres))
-            break;
-
-        VariantClear(&retv);
-        retv = tmp;
-
-        if(rt->type == RT_CONTINUE)
-            rt->type = RT_NORMAL;
-        else if(rt->type != RT_NORMAL)
-            break;
-
-        if(stat->end_expr) {
-            hres = expr_eval(ctx, stat->end_expr, 0, &rt->ei, &exprval);
-            if(FAILED(hres))
-                break;
-
-            hres = exprval_to_value(ctx->parser->script, &exprval, &rt->ei, &val);
-            exprval_release(&exprval);
-            if(FAILED(hres))
-                break;
-
-            VariantClear(&val);
-        }
-    }
-
-    if(FAILED(hres)) {
-        VariantClear(&retv);
-        return hres;
-    }
-
-    if(rt->type == RT_BREAK)
-        rt->type = RT_NORMAL;
-
-    *ret = retv;
-    return S_OK;
+    return throw_type_error(ctx->script, hres, str->str);
 }
 
-/* ECMA-262 3rd Edition    12.6.4 */
-HRESULT forin_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    12.14 */
+static HRESULT interp_push_except(exec_ctx_t *ctx)
 {
-    forin_statement_t *stat = (forin_statement_t*)_stat;
-    VARIANT val, name, retv, tmp;
-    DISPID id = DISPID_STARTENUM;
-    BSTR str, identifier = NULL;
-    IDispatchEx *in_obj;
-    exprval_t exprval;
-    HRESULT hres;
+    const unsigned arg1 = get_op_uint(ctx, 0);
+    const BSTR arg2 = get_op_bstr(ctx, 1);
+    except_frame_t *except;
+    unsigned stack_top;
 
     TRACE("\n");
 
-    if(stat->variable) {
-        hres = variable_list_eval(ctx, stat->variable, &rt->ei);
-        if(FAILED(hres))
-            return hres;
-    }
-
-    hres = expr_eval(ctx, stat->in_expr, EXPR_NEWREF, &rt->ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = exprval_to_value(ctx->parser->script, &exprval, &rt->ei, &val);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
-
-    if(V_VT(&val) != VT_DISPATCH) {
-        TRACE("in vt %d\n", V_VT(&val));
-        VariantClear(&val);
-        V_VT(ret) = VT_EMPTY;
-        return S_OK;
-    }
-
-    hres = IDispatch_QueryInterface(V_DISPATCH(&val), &IID_IDispatchEx, (void**)&in_obj);
-    IDispatch_Release(V_DISPATCH(&val));
-    if(FAILED(hres)) {
-        FIXME("Object doesn't support IDispatchEx\n");
-        return E_NOTIMPL;
-    }
-
-    V_VT(&retv) = VT_EMPTY;
+    stack_top = ctx->top;
 
-    if(stat->variable)
-        identifier = SysAllocString(stat->variable->identifier);
-
-    while(1) {
-        hres = IDispatchEx_GetNextDispID(in_obj, fdexEnumDefault, id, &id);
-        if(FAILED(hres) || hres == S_FALSE)
-            break;
+    if(!arg2) {
+        HRESULT hres;
 
-        hres = IDispatchEx_GetMemberName(in_obj, id, &str);
+        hres = stack_push(ctx, jsval_bool(TRUE));
         if(FAILED(hres))
-            break;
-
-        TRACE("iter %s\n", debugstr_w(str));
-
-        if(stat->variable)
-            hres = identifier_eval(ctx, identifier, 0, NULL, &exprval);
-        else
-            hres = expr_eval(ctx, stat->expr, EXPR_NEWREF, &rt->ei, &exprval);
-        if(SUCCEEDED(hres)) {
-            V_VT(&name) = VT_BSTR;
-            V_BSTR(&name) = str;
-            hres = put_value(ctx->parser->script, &exprval, &name, &rt->ei);
-            exprval_release(&exprval);
-        }
-        SysFreeString(str);
-        if(FAILED(hres))
-            break;
-
-        hres = stat_eval(ctx, stat->statement, rt, &tmp);
+            return hres;
+        hres = stack_push(ctx, jsval_bool(TRUE));
         if(FAILED(hres))
-            break;
-
-        VariantClear(&retv);
-        retv = tmp;
-
-        if(rt->type == RT_CONTINUE)
-            rt->type = RT_NORMAL;
-        else if(rt->type != RT_NORMAL)
-            break;
-    }
-
-    SysFreeString(identifier);
-    IDispatchEx_Release(in_obj);
-    if(FAILED(hres)) {
-        VariantClear(&retv);
-        return hres;
+            return hres;
     }
 
-    if(rt->type == RT_BREAK)
-        rt->type = RT_NORMAL;
-
-    *ret = retv;
-    return S_OK;
-}
-
-/* ECMA-262 3rd Edition    12.7 */
-HRESULT continue_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
-{
-    branch_statement_t *stat = (branch_statement_t*)_stat;
-
-    TRACE("\n");
-
-    if(stat->identifier) {
-        FIXME("indentifier not implemented\n");
-        return E_NOTIMPL;
-    }
+    except = heap_alloc(sizeof(*except));
+    if(!except)
+        return E_OUTOFMEMORY;
 
-    rt->type = RT_CONTINUE;
-    V_VT(ret) = VT_EMPTY;
+    except->stack_top = stack_top;
+    except->scope = ctx->scope_chain;
+    except->catch_off = arg1;
+    except->ident = arg2;
+    except->next = ctx->except_frame;
+    ctx->except_frame = except;
     return S_OK;
 }
 
-/* ECMA-262 3rd Edition    12.8 */
-HRESULT break_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    12.14 */
+static HRESULT interp_pop_except(exec_ctx_t *ctx)
 {
-    branch_statement_t *stat = (branch_statement_t*)_stat;
+    except_frame_t *except;
 
     TRACE("\n");
 
-    if(stat->identifier) {
-        FIXME("indentifier not implemented\n");
-        return E_NOTIMPL;
-    }
+    except = ctx->except_frame;
+    assert(except != NULL);
 
-    rt->type = RT_BREAK;
-    V_VT(ret) = VT_EMPTY;
+    ctx->except_frame = except->next;
+    heap_free(except);
     return S_OK;
 }
 
-/* ECMA-262 3rd Edition    12.9 */
-HRESULT return_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    12.14 */
+static HRESULT interp_end_finally(exec_ctx_t *ctx)
 {
-    expression_statement_t *stat = (expression_statement_t*)_stat;
-    HRESULT hres;
+    //jsval_t v;
 
     TRACE("\n");
 
-    if(stat->expr) {
-        exprval_t exprval;
+    assert(is_bool(stack_top(ctx)));
+    if(!get_bool(stack_top(ctx))) {
+        TRACE("passing exception\n");
 
-        hres = expr_eval(ctx, stat->expr, 0, &rt->ei, &exprval);
-        if(FAILED(hres))
-            return hres;
+        //jsval_release(v);
+        stack_popn(ctx, 1);
 
-        hres = exprval_to_value(ctx->parser->script, &exprval, &rt->ei, ret);
-        exprval_release(&exprval);
-        if(FAILED(hres))
-            return hres;
-    }else {
-        V_VT(ret) = VT_EMPTY;
+        ctx->script->ei.val = stack_pop(ctx);
+        return DISP_E_EXCEPTION;
     }
 
-    TRACE("= %s\n", debugstr_variant(ret));
-    rt->type = RT_RETURN;
+    stack_popn(ctx, 2);
     return S_OK;
 }
 
-/* ECMA-262 3rd Edition    12.10 */
-HRESULT with_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    13 */
+static HRESULT interp_func(exec_ctx_t *ctx)
 {
-    with_statement_t *stat = (with_statement_t*)_stat;
-    exprval_t exprval;
-    IDispatch *disp;
-    DispatchEx *obj;
-    VARIANT val;
+    unsigned func_idx = get_op_uint(ctx, 0);
+    jsdisp_t *dispex;
     HRESULT hres;
 
-    TRACE("\n");
-
-    hres = expr_eval(ctx, stat->expr, 0, &rt->ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = exprval_to_value(ctx->parser->script, &exprval, &rt->ei, &val);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = to_object(ctx->parser->script, &val, &disp);
-    VariantClear(&val);
-    if(FAILED(hres))
-        return hres;
-
-    obj = iface_to_jsdisp((IUnknown*)disp);
-    IDispatch_Release(disp);
-    if(!obj) {
-        FIXME("disp id not jsdisp\n");
-        return E_NOTIMPL;
-    }
+    TRACE("%d\n", func_idx);
 
-    hres = scope_push(ctx->scope_chain, obj, &ctx->scope_chain);
-    jsdisp_release(obj);
+    hres = create_source_function(ctx->script, ctx->code, ctx->func_code->funcs+func_idx,
+            ctx->scope_chain, &dispex);
     if(FAILED(hres))
         return hres;
 
-    hres = stat_eval(ctx, stat->statement, rt, ret);
-
-    scope_pop(&ctx->scope_chain);
-    return hres;
-}
-
-/* ECMA-262 3rd Edition    12.12 */
-HRESULT labelled_statement_eval(exec_ctx_t *ctx, statement_t *stat, return_type_t *rt, VARIANT *ret)
-{
-    FIXME("\n");
-    return E_NOTIMPL;
+    return stack_push(ctx, jsval_obj(dispex));
 }
 
-/* ECMA-262 3rd Edition    12.13 */
-HRESULT switch_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    11.2.1 */
+static HRESULT interp_array(exec_ctx_t *ctx)
 {
-    switch_statement_t *stat = (switch_statement_t*)_stat;
-    case_clausule_t *iter, *default_clausule = NULL;
-    statement_t *stat_iter;
-    VARIANT val, cval;
-    exprval_t exprval;
-    BOOL b;
+    jsval_t v, namev;
+    IDispatch *obj;
+    jsstr_t *name;
+    DISPID id;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = expr_eval(ctx, stat->expr, 0, &rt->ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = exprval_to_value(ctx->parser->script, &exprval, &rt->ei, &val);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
-
-    for(iter = stat->case_list; iter; iter = iter->next) {
-        if(!iter->expr) {
-            default_clausule = iter;
-            continue;
-        }
+    namev = stack_pop(ctx);
 
-        hres = expr_eval(ctx, iter->expr, 0, &rt->ei, &exprval);
-        if(FAILED(hres))
-            break;
-
-        hres = exprval_to_value(ctx->parser->script, &exprval, &rt->ei, &cval);
-        exprval_release(&exprval);
-        if(FAILED(hres))
-            break;
-
-        hres = equal2_values(&val, &cval, &b);
-        VariantClear(&cval);
-        if(FAILED(hres) || b)
-            break;
-    }
-
-    VariantClear(&val);
-    if(FAILED(hres))
+    hres = stack_pop_object(ctx, &obj);
+    if(FAILED(hres)) {
+        jsval_release(namev);
         return hres;
-
-    if(!iter)
-        iter = default_clausule;
-
-    V_VT(&val) = VT_EMPTY;
-    if(iter) {
-        VARIANT tmp;
-
-        for(stat_iter = iter->stat; stat_iter; stat_iter = stat_iter->next) {
-            hres = stat_eval(ctx, stat_iter, rt, &tmp);
-            if(FAILED(hres))
-                break;
-
-            VariantClear(&val);
-            val = tmp;
-
-            if(rt->type != RT_NORMAL)
-                break;
-        }
     }
 
+    hres = to_string(ctx->script, namev, &name);
+    jsval_release(namev);
     if(FAILED(hres)) {
-        VariantClear(&val);
+        IDispatch_Release(obj);
         return hres;
     }
 
-    if(rt->type == RT_BREAK)
-        rt->type = RT_NORMAL;
+    hres = disp_get_id(ctx->script, obj, name->str, NULL, 0, &id);
+    jsstr_release(name);
+    if(SUCCEEDED(hres)) {
+        hres = disp_propget(ctx->script, obj, id, &v);
+    }else if(hres == DISP_E_UNKNOWNNAME) {
+        v = jsval_undefined();
+        hres = S_OK;
+    }
+    IDispatch_Release(obj);
+    if(FAILED(hres))
+        return hres;
 
-    *ret = val;
-    return S_OK;
+    return stack_push(ctx, v);
 }
 
-/* ECMA-262 3rd Edition    12.13 */
-HRESULT throw_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    11.2.1 */
+static HRESULT interp_member(exec_ctx_t *ctx)
 {
-    expression_statement_t *stat = (expression_statement_t*)_stat;
-    exprval_t exprval;
-    VARIANT val;
+    const BSTR arg = get_op_bstr(ctx, 0);
+    IDispatch *obj;
+    jsval_t v;
+    DISPID id;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = expr_eval(ctx, stat->expr, 0, &rt->ei, &exprval);
+    hres = stack_pop_object(ctx, &obj);
     if(FAILED(hres))
         return hres;
 
-    hres = exprval_to_value(ctx->parser->script, &exprval, &rt->ei, &val);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
-
-    rt->ei.var = val;
-    return DISP_E_EXCEPTION;
-}
-
-/* ECMA-262 3rd Edition    12.14 */
-static HRESULT catch_eval(exec_ctx_t *ctx, catch_block_t *block, return_type_t *rt, VARIANT *ret)
-{
-    DispatchEx *var_disp;
-    VARIANT ex, val;
-    HRESULT hres;
-
-    ex = rt->ei.var;
-    memset(&rt->ei, 0, sizeof(jsexcept_t));
-
-    hres = create_dispex(ctx->parser->script, NULL, NULL, &var_disp);
+    hres = disp_get_id(ctx->script, obj, arg, arg, 0, &id);
     if(SUCCEEDED(hres)) {
-        hres = jsdisp_propput_name(var_disp, block->identifier, &ex, &rt->ei, NULL/*FIXME*/);
-        if(SUCCEEDED(hres)) {
-            hres = scope_push(ctx->scope_chain, var_disp, &ctx->scope_chain);
-            if(SUCCEEDED(hres)) {
-                hres = stat_eval(ctx, block->statement, rt, &val);
-                scope_pop(&ctx->scope_chain);
-            }
-        }
-
-        jsdisp_release(var_disp);
+        hres = disp_propget(ctx->script, obj, id, &v);
+    }else if(hres == DISP_E_UNKNOWNNAME) {
+        v = jsval_undefined();
+        hres = S_OK;
     }
-
-    VariantClear(&ex);
+    IDispatch_Release(obj);
     if(FAILED(hres))
         return hres;
 
-    *ret = val;
-    return S_OK;
+    return stack_push(ctx, v);
 }
 
-/* ECMA-262 3rd Edition    12.14 */
-HRESULT try_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
+/* ECMA-262 3rd Edition    11.2.1 */
+static HRESULT interp_memberid(exec_ctx_t *ctx)
 {
-    try_statement_t *stat = (try_statement_t*)_stat;
-    VARIANT val;
+    const unsigned arg = get_op_uint(ctx, 0);
+    jsval_t objv, namev;
+    IDispatch *obj;
+    jsstr_t *name;
+    DISPID id;
     HRESULT hres;
 
-    TRACE("\n");
-
-    hres = stat_eval(ctx, stat->try_statement, rt, &val);
-    if(FAILED(hres)) {
-        TRACE("EXCEPTION\n");
-        if(!stat->catch_block)
-            return hres;
+    TRACE("%x\n", arg);
 
-        hres = catch_eval(ctx, stat->catch_block, rt, &val);
-        if(FAILED(hres))
-            return hres;
-    }
+    namev = stack_pop(ctx);
+    objv = stack_pop(ctx);
 
-    if(stat->finally_statement) {
-        VariantClear(&val);
-        hres = stat_eval(ctx, stat->finally_statement, rt, &val);
+    hres = to_object(ctx->script, objv, &obj);
+    jsval_release(objv);
+    if(SUCCEEDED(hres)) {
+        hres = to_string(ctx->script, namev, &name);
         if(FAILED(hres))
-            return hres;
+            IDispatch_Release(obj);
     }
-
-    *ret = val;
-    return S_OK;
-}
-
-static HRESULT return_bool(exprval_t *ret, DWORD b)
-{
-    ret->type = EXPRVAL_VARIANT;
-    V_VT(&ret->u.var) = VT_BOOL;
-    V_BOOL(&ret->u.var) = b ? VARIANT_TRUE : VARIANT_FALSE;
-
-    return S_OK;
-}
-
-static HRESULT get_binary_expr_values(exec_ctx_t *ctx, binary_expression_t *expr, jsexcept_t *ei, VARIANT *lval, VARIANT *rval)
-{
-    exprval_t exprval;
-    HRESULT hres;
-
-    hres = expr_eval(ctx, expr->expression1, 0, ei, &exprval);
+    jsval_release(namev);
     if(FAILED(hres))
         return hres;
 
-    hres = exprval_to_value(ctx->parser->script, &exprval, ei, lval);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = expr_eval(ctx, expr->expression2, 0, ei, &exprval);
-    if(SUCCEEDED(hres)) {
-        hres = exprval_to_value(ctx->parser->script, &exprval, ei, rval);
-        exprval_release(&exprval);
-    }
-
+    hres = disp_get_id(ctx->script, obj, name->str, NULL, arg, &id);
+    jsstr_release(name);
     if(FAILED(hres)) {
-        VariantClear(lval);
-        return hres;
+        IDispatch_Release(obj);
+        if(hres == DISP_E_UNKNOWNNAME && !(arg & fdexNameEnsure)) {
+            obj = NULL;
+            id = JS_E_INVALID_PROPERTY;
+        }else {
+            ERR("failed %08x\n", hres);
+            return hres;
+        }
     }
 
-    return S_OK;
-}
-
-typedef HRESULT (*oper_t)(exec_ctx_t*,VARIANT*,VARIANT*,jsexcept_t*,VARIANT*);
-
-static HRESULT binary_expr_eval(exec_ctx_t *ctx, binary_expression_t *expr, oper_t oper, jsexcept_t *ei,
-        exprval_t *ret)
-{
-    VARIANT lval, rval, retv;
-    HRESULT hres;
-
-    hres = get_binary_expr_values(ctx, expr, ei, &lval, &rval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = oper(ctx, &lval, &rval, ei, &retv);
-    VariantClear(&lval);
-    VariantClear(&rval);
-    if(FAILED(hres))
-        return hres;
-
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = retv;
-    return S_OK;
+    return stack_push_objid(ctx, obj, id);
 }
 
-/* ECMA-262 3rd Edition    11.13.2 */
-static HRESULT assign_oper_eval(exec_ctx_t *ctx, expression_t *lexpr, expression_t *rexpr, oper_t oper,
-                                jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.2.1 */
+static HRESULT interp_refval(exec_ctx_t *ctx)
 {
-    VARIANT retv, lval, rval;
-    exprval_t exprval, exprvalr;
+    IDispatch *disp;
+    jsval_t v;
+    DISPID id;
     HRESULT hres;
 
-    hres = expr_eval(ctx, lexpr, EXPR_NEWREF, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = exprval_value(ctx->parser->script, &exprval, ei, &lval);
-    if(SUCCEEDED(hres)) {
-        hres = expr_eval(ctx, rexpr, 0, ei, &exprvalr);
-        if(SUCCEEDED(hres)) {
-            hres = exprval_value(ctx->parser->script, &exprvalr, ei, &rval);
-            exprval_release(&exprvalr);
-        }
-        if(SUCCEEDED(hres)) {
-            hres = oper(ctx, &lval, &rval, ei, &retv);
-            VariantClear(&rval);
-        }
-        VariantClear(&lval);
-    }
+    TRACE("\n");
 
-    if(SUCCEEDED(hres)) {
-        hres = put_value(ctx->parser->script, &exprval, &retv, ei);
-        if(FAILED(hres))
-            VariantClear(&retv);
-    }
-    exprval_release(&exprval);
+    disp = stack_topn_objid(ctx, 0, &id);
+    if(!disp)
+        return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
 
+    hres = disp_propget(ctx->script, disp, id, &v);
     if(FAILED(hres))
         return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = retv;
-    return S_OK;
+    return stack_push(ctx, v);
 }
 
-/* ECMA-262 3rd Edition    13 */
-HRESULT function_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.2.2 */
+static HRESULT interp_new(exec_ctx_t *ctx)
 {
-    function_expression_t *expr = (function_expression_t*)_expr;
-    VARIANT var;
+    const unsigned argc = get_op_uint(ctx, 0);
+    jsval_t r, constr;
     HRESULT hres;
 
-    TRACE("\n");
-
-    if(expr->identifier) {
-        hres = jsdisp_propget_name(ctx->var_disp, expr->identifier, &var, ei, NULL/*FIXME*/);
-        if(FAILED(hres))
-            return hres;
-    }else {
-        DispatchEx *dispex;
-
-        hres = create_source_function(ctx->parser, expr->parameter_list, expr->source_elements, ctx->scope_chain,
-                expr->src_str, expr->src_len, &dispex);
-        if(FAILED(hres))
-            return hres;
+    TRACE("%d\n", argc);
 
-        V_VT(&var) = VT_DISPATCH;
-        V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(dispex);
-    }
+    constr = stack_topn(ctx, argc);
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = var;
-    return S_OK;
-}
+    /* NOTE: Should use to_object here */
 
-/* ECMA-262 3rd Edition    11.12 */
-HRESULT conditional_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    conditional_expression_t *expr = (conditional_expression_t*)_expr;
-    exprval_t exprval;
-    VARIANT_BOOL b;
-    HRESULT hres;
-
-    TRACE("\n");
+    if(is_null(constr))
+        return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
+    else if(!is_object_instance(constr))
+        return throw_type_error(ctx->script, JS_E_INVALID_ACTION, NULL);
+    else if(!get_object(constr))
+        return throw_type_error(ctx->script, JS_E_INVALID_PROPERTY, NULL);
 
-    hres = expr_eval(ctx, expr->expression, 0, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = exprval_to_boolean(ctx->parser->script, &exprval, ei, &b);
-    exprval_release(&exprval);
+    hres = disp_call_value(ctx->script, get_object(constr), NULL, DISPATCH_CONSTRUCT, argc, stack_args(ctx, argc), &r);
     if(FAILED(hres))
         return hres;
 
-    return expr_eval(ctx, b ? expr->true_expression : expr->false_expression, flags, ei, ret);
+    stack_popn(ctx, argc+1);
+    return stack_push(ctx, r);
 }
 
-/* ECMA-262 3rd Edition    11.2.1 */
-HRESULT array_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.2.3 */
+static HRESULT interp_call(exec_ctx_t *ctx)
 {
-    array_expression_t *expr = (array_expression_t*)_expr;
-    exprval_t exprval;
-    VARIANT member, val;
-    DISPID id;
-    BSTR str;
-    IDispatch *obj = NULL;
+    const unsigned argn = get_op_uint(ctx, 0);
+    const int do_ret = get_op_int(ctx, 1);
+    jsval_t r, obj;
     HRESULT hres;
 
-    TRACE("\n");
+    TRACE("%d %d\n", argn, do_ret);
 
-    hres = expr_eval(ctx, expr->member_expr, 0, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
+    obj = stack_topn(ctx, argn);
+    if(!is_object_instance(obj))
+        return throw_type_error(ctx->script, JS_E_INVALID_PROPERTY, NULL);
 
-    hres = exprval_to_value(ctx->parser->script, &exprval, ei, &member);
-    exprval_release(&exprval);
+    hres = disp_call_value(ctx->script, get_object(obj), NULL, DISPATCH_METHOD, argn, stack_args(ctx, argn),
+            do_ret ? &r : NULL);
     if(FAILED(hres))
         return hres;
 
-    hres = expr_eval(ctx, expr->expression, EXPR_NEWREF, ei, &exprval);
-    if(SUCCEEDED(hres)) {
-        hres = exprval_to_value(ctx->parser->script, &exprval, ei, &val);
-        exprval_release(&exprval);
-    }
-
-    if(SUCCEEDED(hres)) {
-        hres = to_object(ctx->parser->script, &member, &obj);
-        if(FAILED(hres))
-            VariantClear(&val);
-    }
-    VariantClear(&member);
-    if(SUCCEEDED(hres)) {
-        hres = to_string(ctx->parser->script, &val, ei, &str);
-        VariantClear(&val);
-        if(SUCCEEDED(hres)) {
-            if(flags & EXPR_STRREF) {
-                ret->type = EXPRVAL_NAMEREF;
-                ret->u.nameref.disp = obj;
-                ret->u.nameref.name = str;
-                return S_OK;
-            }
-
-            hres = disp_get_id(ctx->parser->script, obj, str, flags & EXPR_NEWREF ? fdexNameEnsure : 0, &id);
-            SysFreeString(str);
-        }
-
-        if(SUCCEEDED(hres)) {
-            exprval_set_idref(ret, obj, id);
-        }else if(!(flags & EXPR_NEWREF) && hres == DISP_E_UNKNOWNNAME) {
-            exprval_init(ret);
-            hres = S_OK;
-        }
-
-        IDispatch_Release(obj);
-    }
-
-    return hres;
+    stack_popn(ctx, argn+1);
+    return do_ret ? stack_push(ctx, r) : S_OK;
 }
 
-/* ECMA-262 3rd Edition    11.2.1 */
-HRESULT member_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.2.3 */
+static HRESULT interp_call_member(exec_ctx_t *ctx)
 {
-    member_expression_t *expr = (member_expression_t*)_expr;
-    IDispatch *obj = NULL;
-    exprval_t exprval;
-    VARIANT member;
+    const unsigned argn = get_op_uint(ctx, 0);
+    const int do_ret = get_op_int(ctx, 1);
+    IDispatch *obj;
+    jsval_t r;
     DISPID id;
-    BSTR str;
     HRESULT hres;
 
-    TRACE("\n");
-
-    hres = expr_eval(ctx, expr->expression, 0, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
+    TRACE("%d %d\n", argn, do_ret);
 
-    hres = exprval_to_value(ctx->parser->script, &exprval, ei, &member);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
+    obj = stack_topn_objid(ctx, argn, &id);
+    if(!obj)
+        return throw_type_error(ctx->script, id, NULL);
 
-    hres = to_object(ctx->parser->script, &member, &obj);
-    VariantClear(&member);
+    hres = disp_call(ctx->script, obj, id, DISPATCH_METHOD, argn, stack_args(ctx, argn), do_ret ? &r : NULL);
     if(FAILED(hres))
         return hres;
 
-    str = SysAllocString(expr->identifier);
-    if(flags & EXPR_STRREF) {
-        ret->type = EXPRVAL_NAMEREF;
-        ret->u.nameref.disp = obj;
-        ret->u.nameref.name = str;
-        return S_OK;
-    }
-
-    hres = disp_get_id(ctx->parser->script, obj, str, flags & EXPR_NEWREF ? fdexNameEnsure : 0, &id);
-    SysFreeString(str);
-    if(SUCCEEDED(hres)) {
-        exprval_set_idref(ret, obj, id);
-    }else if(!(flags & EXPR_NEWREF) && hres == DISP_E_UNKNOWNNAME) {
-        exprval_init(ret);
-        hres = S_OK;
-    }
-
-    IDispatch_Release(obj);
-    return hres;
-}
-
-static void free_dp(DISPPARAMS *dp)
-{
-    DWORD i;
+    stack_popn(ctx, argn+2);
+    return do_ret ? stack_push(ctx, r) : S_OK;
 
-    for(i=0; i < dp->cArgs; i++)
-        VariantClear(dp->rgvarg+i);
-    heap_free(dp->rgvarg);
 }
 
-static HRESULT args_to_param(exec_ctx_t *ctx, argument_t *args, jsexcept_t *ei, DISPPARAMS *dp)
+/* ECMA-262 3rd Edition    11.1.1 */
+static HRESULT interp_this(exec_ctx_t *ctx)
 {
-    VARIANTARG *vargs;
-    exprval_t exprval;
-    argument_t *iter;
-    DWORD cnt = 0, i;
-    HRESULT hres = S_OK;
-
-    memset(dp, 0, sizeof(*dp));
-    if(!args)
-        return S_OK;
-
-    for(iter = args; iter; iter = iter->next)
-        cnt++;
-
-    vargs = heap_alloc_zero(cnt * sizeof(*vargs));
-    if(!vargs)
-        return E_OUTOFMEMORY;
-
-    for(i = cnt, iter = args; iter; iter = iter->next) {
-        hres = expr_eval(ctx, iter->expr, 0, ei, &exprval);
-        if(FAILED(hres))
-            break;
-
-        hres = exprval_to_value(ctx->parser->script, &exprval, ei, vargs + (--i));
-        exprval_release(&exprval);
-        if(FAILED(hres))
-            break;
-    }
-
-    if(FAILED(hres)) {
-        free_dp(dp);
-        return hres;
-    }
+    TRACE("\n");
 
-    dp->rgvarg = vargs;
-    dp->cArgs = cnt;
-    return S_OK;
+    IDispatch_AddRef(ctx->this_obj);
+    return stack_push(ctx, jsval_disp(ctx->this_obj));
 }
 
-/* ECMA-262 3rd Edition    11.2.2 */
-HRESULT new_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    10.1.4 */
+static HRESULT interp_ident(exec_ctx_t *ctx)
 {
-    call_expression_t *expr = (call_expression_t*)_expr;
+    const BSTR arg = get_op_bstr(ctx, 0);
     exprval_t exprval;
-    VARIANT constr, var;
-    DISPPARAMS dp;
+    jsval_t v;
     HRESULT hres;
 
-    TRACE("\n");
-
-    hres = expr_eval(ctx, expr->expression, 0, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
+    TRACE("%s\n", debugstr_w(arg));
 
-    hres = args_to_param(ctx, expr->argument_list, ei, &dp);
-    if(SUCCEEDED(hres))
-        hres = exprval_to_value(ctx->parser->script, &exprval, ei, &constr);
-    exprval_release(&exprval);
+    hres = identifier_eval(ctx->script, arg, &exprval);
     if(FAILED(hres))
         return hres;
 
-    if(V_VT(&constr) != VT_DISPATCH) {
-        FIXME("throw TypeError\n");
-        VariantClear(&constr);
-        return E_FAIL;
-    }
+    if(exprval.type == EXPRVAL_INVALID)
+        return throw_type_error(ctx->script, JS_E_UNDEFINED_VARIABLE, arg);
 
-    hres = disp_call(ctx->parser->script, V_DISPATCH(&constr), DISPID_VALUE,
-                     DISPATCH_CONSTRUCT, &dp, &var, ei, NULL/*FIXME*/);
-    IDispatch_Release(V_DISPATCH(&constr));
-    free_dp(&dp);
+    hres = exprval_to_value(ctx->script, &exprval, &v);
+    exprval_release(&exprval);
     if(FAILED(hres))
         return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = var;
-    return S_OK;
+    return stack_push(ctx, v);
 }
 
-/* ECMA-262 3rd Edition    11.2.3 */
-HRESULT call_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    10.1.4 */
+static HRESULT interp_identid(exec_ctx_t *ctx)
 {
-    call_expression_t *expr = (call_expression_t*)_expr;
-    VARIANT var;
+    const BSTR arg = get_op_bstr(ctx, 0);
+    const unsigned flags = get_op_uint(ctx, 1);
     exprval_t exprval;
-    DISPPARAMS dp;
     HRESULT hres;
 
-    TRACE("\n");
+    TRACE("%s %x\n", debugstr_w(arg), flags);
 
-    hres = expr_eval(ctx, expr->expression, 0, ei, &exprval);
+    hres = identifier_eval(ctx->script, arg, &exprval);
     if(FAILED(hres))
         return hres;
 
-    hres = args_to_param(ctx, expr->argument_list, ei, &dp);
-    if(SUCCEEDED(hres)) {
-        switch(exprval.type) {
-        case EXPRVAL_VARIANT:
-            if(V_VT(&exprval.u.var) == VT_DISPATCH)
-                hres = disp_call(ctx->parser->script, V_DISPATCH(&exprval.u.var), DISPID_VALUE,
-                        DISPATCH_METHOD, &dp, flags & EXPR_NOVAL ? NULL : &var, ei, NULL/*FIXME*/);
-            else
-                hres = throw_type_error(ctx->parser->script, ei, IDS_NO_PROPERTY, NULL);
-            break;
-        case EXPRVAL_IDREF:
-            hres = disp_call(ctx->parser->script, exprval.u.idref.disp, exprval.u.idref.id,
-                    DISPATCH_METHOD, &dp, flags & EXPR_NOVAL ? NULL : &var, ei, NULL/*FIXME*/);
-            break;
-        case EXPRVAL_INVALID:
-            hres = throw_type_error(ctx->parser->script, ei, IDS_OBJECT_EXPECTED, NULL);
-            break;
-        default:
-            FIXME("unimplemented type %d\n", exprval.type);
-            hres = E_NOTIMPL;
-        }
-
-        free_dp(&dp);
-    }
+    if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) {
+        DISPID id;
 
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
+        hres = jsdisp_get_id(ctx->script->global, arg, fdexNameEnsure, &id);
+        if(FAILED(hres))
+            return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    if(flags & EXPR_NOVAL) {
-        V_VT(&ret->u.var) = VT_EMPTY;
-    }else {
-        TRACE("= %s\n", debugstr_variant(&var));
-        ret->u.var = var;
+        exprval_set_idref(&exprval, to_disp(ctx->script->global), id);
     }
-    return S_OK;
-}
 
-/* ECMA-262 3rd Edition    11.1.1 */
-HRESULT this_expression_eval(exec_ctx_t *ctx, expression_t *expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    TRACE("\n");
+    if(exprval.type != EXPRVAL_IDREF) {
+        WARN("invalid ref\n");
+        exprval_release(&exprval);
+        return stack_push_objid(ctx, NULL, JS_E_OBJECT_EXPECTED);
+    }
 
-    ret->type = EXPRVAL_VARIANT;
-    V_VT(&ret->u.var) = VT_DISPATCH;
-    V_DISPATCH(&ret->u.var) = ctx->this_obj;
-    IDispatch_AddRef(ctx->this_obj);
-    return S_OK;
+    return stack_push_objid(ctx, exprval.u.idref.disp, exprval.u.idref.id);
 }
 
-/* ECMA-262 3rd Edition    10.1.4 */
-HRESULT identifier_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    7.8.1 */
+static HRESULT interp_null(exec_ctx_t *ctx)
 {
-    identifier_expression_t *expr = (identifier_expression_t*)_expr;
-    BSTR identifier;
-    HRESULT hres;
-
     TRACE("\n");
 
-    identifier = SysAllocString(expr->identifier);
-    if(!identifier)
-        return E_OUTOFMEMORY;
-
-    hres = identifier_eval(ctx, identifier, flags, ei, ret);
-
-    SysFreeString(identifier);
-    return hres;
+    return stack_push(ctx, jsval_null());
 }
 
-/* ECMA-262 3rd Edition    7.8 */
-HRESULT literal_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    7.8.2 */
+static HRESULT interp_bool(exec_ctx_t *ctx)
 {
-    literal_expression_t *expr = (literal_expression_t*)_expr;
-    VARIANT var;
-    HRESULT hres;
+    const int arg = get_op_int(ctx, 0);
 
-    TRACE("\n");
+    TRACE("%s\n", arg ? "true" : "false");
 
-    hres = literal_to_var(ctx->parser->script, expr->literal, &var);
-    if(FAILED(hres))
-        return hres;
-
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = var;
-    return S_OK;
+    return stack_push(ctx, jsval_bool(arg));
 }
 
-/* ECMA-262 3rd Edition    11.1.4 */
-HRESULT array_literal_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    7.8.3 */
+static HRESULT interp_int(exec_ctx_t *ctx)
 {
-    array_literal_expression_t *expr = (array_literal_expression_t*)_expr;
-    DWORD length = 0, i = 0;
-    array_element_t *elem;
-    DispatchEx *array;
-    exprval_t exprval;
-    VARIANT val;
-    HRESULT hres;
-
-    TRACE("\n");
-
-    for(elem = expr->element_list; elem; elem = elem->next)
-        length += elem->elision+1;
-    length += expr->length;
-
-    hres = create_array(ctx->parser->script, length, &array);
-    if(FAILED(hres))
-        return hres;
-
-    for(elem = expr->element_list; elem; elem = elem->next) {
-        i += elem->elision;
-
-        hres = expr_eval(ctx, elem->expr, 0, ei, &exprval);
-        if(FAILED(hres))
-            break;
-
-        hres = exprval_to_value(ctx->parser->script, &exprval, ei, &val);
-        exprval_release(&exprval);
-        if(FAILED(hres))
-            break;
+    const int arg = get_op_int(ctx, 0);
 
-        hres = jsdisp_propput_idx(array, i, &val, ei, NULL/*FIXME*/);
-        VariantClear(&val);
-        if(FAILED(hres))
-            break;
-
-        i++;
-    }
-
-    if(FAILED(hres)) {
-        jsdisp_release(array);
-        return hres;
-    }
+    TRACE("%d\n", arg);
 
-    ret->type = EXPRVAL_VARIANT;
-    V_VT(&ret->u.var) = VT_DISPATCH;
-    V_DISPATCH(&ret->u.var) = (IDispatch*)_IDispatchEx_(array);
-    return S_OK;
+    return stack_push(ctx, jsval_number(arg));
 }
 
-/* ECMA-262 3rd Edition    11.1.5 */
-HRESULT property_value_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    7.8.3 */
+static HRESULT interp_double(exec_ctx_t *ctx)
 {
-    property_value_expression_t *expr = (property_value_expression_t*)_expr;
-    VARIANT val, tmp;
-    DispatchEx *obj;
-    prop_val_t *iter;
-    exprval_t exprval;
-    BSTR name;
-    HRESULT hres;
+    const double arg = get_op_double(ctx);
 
-    TRACE("\n");
+    TRACE("%lf\n", arg);
 
-    hres = create_object(ctx->parser->script, NULL, &obj);
-    if(FAILED(hres))
-        return hres;
+    return stack_push(ctx, jsval_number(arg));
+}
 
-    for(iter = expr->property_list; iter; iter = iter->next) {
-        hres = literal_to_var(ctx->parser->script, iter->name, &tmp);
-        if(FAILED(hres))
-            break;
+/* ECMA-262 3rd Edition    7.8.4 */
+static HRESULT interp_str(exec_ctx_t *ctx)
+{
+    jsstr_t *str = get_op_str(ctx, 0);
 
-        hres = to_string(ctx->parser->script, &tmp, ei, &name);
-        VariantClear(&tmp);
-        if(FAILED(hres))
-            break;
+    TRACE("%s\n", debugstr_jsstr(str));
 
-        hres = expr_eval(ctx, iter->value, 0, ei, &exprval);
-        if(SUCCEEDED(hres)) {
-            hres = exprval_to_value(ctx->parser->script, &exprval, ei, &val);
-            exprval_release(&exprval);
-            if(SUCCEEDED(hres)) {
-                hres = jsdisp_propput_name(obj, name, &val, ei, NULL/*FIXME*/);
-                VariantClear(&val);
-            }
-        }
+    return stack_push(ctx, jsval_string(jsstr_addref(str)));
+}
 
-        SysFreeString(name);
-        if(FAILED(hres))
-            break;
-    }
+/* ECMA-262 3rd Edition    7.8 */
+static HRESULT interp_regexp(exec_ctx_t *ctx)
+{
+    jsstr_t *source = get_op_str(ctx, 0);
+    const unsigned flags = get_op_uint(ctx, 1);
+    jsdisp_t *regexp;
+    HRESULT hres;
 
-    if(FAILED(hres)) {
-        jsdisp_release(obj);
+    TRACE("%s %x\n", debugstr_jsstr(source), flags);
+
+    hres = create_regexp(ctx->script, source, flags, &regexp);
+    if(FAILED(hres))
         return hres;
-    }
 
-    ret->type = EXPRVAL_VARIANT;
-    V_VT(&ret->u.var) = VT_DISPATCH;
-    V_DISPATCH(&ret->u.var) = (IDispatch*)_IDispatchEx_(obj);
-    return S_OK;
+    return stack_push(ctx, jsval_obj(regexp));
 }
 
-/* ECMA-262 3rd Edition    11.14 */
-HRESULT comma_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.1.4 */
+static HRESULT interp_carray(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    VARIANT lval, rval;
+    const unsigned arg = get_op_uint(ctx, 0);
+    jsdisp_t *array;
+    jsval_t val;
+    unsigned i;
     HRESULT hres;
 
-    TRACE("\n");
+    TRACE("%u\n", arg);
 
-    hres = get_binary_expr_values(ctx, expr, ei, &lval, &rval);
+    hres = create_array(ctx->script, arg, &array);
     if(FAILED(hres))
         return hres;
 
-    VariantClear(&lval);
+    i = arg;
+    while(i--) {
+        val = stack_pop(ctx);
+        hres = jsdisp_propput_idx(array, i, val);
+        jsval_release(val);
+        if(FAILED(hres)) {
+            jsdisp_release(array);
+            return hres;
+        }
+    }
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = rval;
-    return S_OK;
+    return stack_push(ctx, jsval_obj(array));
 }
 
-/* ECMA-262 3rd Edition    11.11 */
-HRESULT logical_or_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.1.5 */
+static HRESULT interp_new_obj(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    exprval_t exprval;
-    VARIANT_BOOL b;
-    VARIANT val;
+    jsdisp_t *obj;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = expr_eval(ctx, expr->expression1, 0, ei, &exprval);
+    hres = create_object(ctx->script, NULL, &obj);
     if(FAILED(hres))
         return hres;
 
-    hres = exprval_to_value(ctx->parser->script, &exprval, ei, &val);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
+    return stack_push(ctx, jsval_obj(obj));
+}
 
-    hres = to_boolean(&val, &b);
-    if(SUCCEEDED(hres) && b) {
-        ret->type = EXPRVAL_VARIANT;
-        ret->u.var = val;
-        return S_OK;
-    }
+/* ECMA-262 3rd Edition    11.1.5 */
+static HRESULT interp_obj_prop(exec_ctx_t *ctx)
+{
+    const BSTR name = get_op_bstr(ctx, 0);
+    jsdisp_t *obj;
+    jsval_t val;
+    HRESULT hres;
 
-    VariantClear(&val);
-    if(FAILED(hres))
-        return hres;
+    TRACE("%s\n", debugstr_w(name));
 
-    hres = expr_eval(ctx, expr->expression2, 0, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
+    val = stack_pop(ctx);
 
-    hres = exprval_to_value(ctx->parser->script, &exprval, ei, &val);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
+    assert(is_object_instance(stack_top(ctx)));
+    obj = as_jsdisp(get_object(stack_top(ctx)));
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = val;
-    return S_OK;
+    hres = jsdisp_propput_name(obj, name, val);
+    jsval_release(val);
+    return hres;
 }
 
 /* ECMA-262 3rd Edition    11.11 */
-HRESULT logical_and_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_cnd_nz(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    exprval_t exprval;
-    VARIANT_BOOL b;
-    VARIANT val;
+    const unsigned arg = get_op_uint(ctx, 0);
+    BOOL b;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = expr_eval(ctx, expr->expression1, 0, ei, &exprval);
+    hres = to_boolean(stack_top(ctx), &b);
     if(FAILED(hres))
         return hres;
 
-    hres = exprval_to_value(ctx->parser->script, &exprval, ei, &val);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = to_boolean(&val, &b);
-    if(SUCCEEDED(hres) && !b) {
-        ret->type = EXPRVAL_VARIANT;
-        ret->u.var = val;
-        return S_OK;
+    if(b) {
+        ctx->ip = arg;
+    }else {
+        stack_popn(ctx, 1);
+        ctx->ip++;
     }
+    return S_OK;
+}
 
-    VariantClear(&val);
-    if(FAILED(hres))
-        return hres;
+/* ECMA-262 3rd Edition    11.11 */
+static HRESULT interp_cnd_z(exec_ctx_t *ctx)
+{
+    const unsigned arg = get_op_uint(ctx, 0);
+    BOOL b;
+    HRESULT hres;
 
-    hres = expr_eval(ctx, expr->expression2, 0, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
+    TRACE("\n");
 
-    hres = exprval_to_value(ctx->parser->script, &exprval, ei, &val);
-    exprval_release(&exprval);
+    hres = to_boolean(stack_top(ctx), &b);
     if(FAILED(hres))
         return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = val;
+    if(b) {
+        stack_popn(ctx, 1);
+        ctx->ip++;
+    }else {
+        ctx->ip = arg;
+    }
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    11.10 */
-static HRESULT bitor_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
+static HRESULT interp_or(exec_ctx_t *ctx)
 {
-    INT li, ri;
+    INT l, r;
     HRESULT hres;
 
-    hres = to_int32(ctx->parser->script, lval, ei, &li);
+    TRACE("\n");
+
+    hres = stack_pop_int(ctx, &r);
     if(FAILED(hres))
         return hres;
 
-    hres = to_int32(ctx->parser->script, rval, ei, &ri);
+    hres = stack_pop_int(ctx, &l);
     if(FAILED(hres))
         return hres;
 
-    V_VT(retv) = VT_I4;
-    V_I4(retv) = li|ri;
-    return S_OK;
+    return stack_push(ctx, jsval_number(l|r));
 }
 
 /* ECMA-262 3rd Edition    11.10 */
-HRESULT binary_or_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_xor(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    INT l, r;
+    HRESULT hres;
 
     TRACE("\n");
 
-    return binary_expr_eval(ctx, expr, bitor_eval, ei, ret);
-}
-
-/* ECMA-262 3rd Edition    11.10 */
-static HRESULT xor_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
-{
-    INT li, ri;
-    HRESULT hres;
-
-    hres = to_int32(ctx->parser->script, lval, ei, &li);
+    hres = stack_pop_int(ctx, &r);
     if(FAILED(hres))
         return hres;
 
-    hres = to_int32(ctx->parser->script, rval, ei, &ri);
+    hres = stack_pop_int(ctx, &l);
     if(FAILED(hres))
         return hres;
 
-    V_VT(retv) = VT_I4;
-    V_I4(retv) = li^ri;
-    return S_OK;
+    return stack_push(ctx, jsval_number(l^r));
 }
 
 /* ECMA-262 3rd Edition    11.10 */
-HRESULT binary_xor_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_and(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    INT l, r;
+    HRESULT hres;
 
     TRACE("\n");
 
-    return binary_expr_eval(ctx, expr, xor_eval, ei, ret);
-}
-
-/* ECMA-262 3rd Edition    11.10 */
-static HRESULT bitand_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
-{
-    INT li, ri;
-    HRESULT hres;
-
-    hres = to_int32(ctx->parser->script, lval, ei, &li);
+    hres = stack_pop_int(ctx, &r);
     if(FAILED(hres))
         return hres;
 
-    hres = to_int32(ctx->parser->script, rval, ei, &ri);
+    hres = stack_pop_int(ctx, &l);
     if(FAILED(hres))
         return hres;
 
-    V_VT(retv) = VT_I4;
-    V_I4(retv) = li&ri;
-    return S_OK;
-}
-
-/* ECMA-262 3rd Edition    11.10 */
-HRESULT binary_and_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-
-    TRACE("\n");
-
-    return binary_expr_eval(ctx, expr, bitand_eval, ei, ret);
+    return stack_push(ctx, jsval_number(l&r));
 }
 
 /* ECMA-262 3rd Edition    11.8.6 */
-static HRESULT instanceof_eval(exec_ctx_t *ctx, VARIANT *inst, VARIANT *objv, jsexcept_t *ei, VARIANT *retv)
+static HRESULT interp_instanceof(exec_ctx_t *ctx)
 {
-    DispatchEx *obj, *iter, *tmp = NULL;
-    VARIANT_BOOL ret = VARIANT_FALSE;
-    BOOL b;
-    VARIANT var;
+    jsdisp_t *obj, *iter, *tmp = NULL;
+    jsval_t prot, v;
+    BOOL ret = FALSE;
     HRESULT hres;
 
     static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
 
-    if(V_VT(objv) != VT_DISPATCH) {
-        FIXME("throw TypeError\n");
-        return E_FAIL;
+    v = stack_pop(ctx);
+    if(!is_object_instance(v) || !get_object(v)) {
+        jsval_release(v);
+        return throw_type_error(ctx->script, JS_E_FUNCTION_EXPECTED, NULL);
     }
 
-    obj = iface_to_jsdisp((IUnknown*)V_DISPATCH(objv));
+    obj = iface_to_jsdisp((IUnknown*)get_object(v));
+    IDispatch_Release(get_object(v));
     if(!obj) {
-        FIXME("throw TypeError\n");
+        FIXME("non-jsdisp objects not supported\n");
         return E_FAIL;
     }
 
     if(is_class(obj, JSCLASS_FUNCTION)) {
-        hres = jsdisp_propget_name(obj, prototypeW, &var, ei, NULL/*FIXME*/);
+        hres = jsdisp_propget_name(obj, prototypeW, &prot);
     }else {
-        FIXME("throw TypeError\n");
-        hres = E_FAIL;
+        hres = throw_type_error(ctx->script, JS_E_FUNCTION_EXPECTED, NULL);
     }
     jsdisp_release(obj);
     if(FAILED(hres))
         return hres;
 
-    if(V_VT(&var) == VT_DISPATCH) {
-        if(V_VT(inst) == VT_DISPATCH)
-            tmp = iface_to_jsdisp((IUnknown*)V_DISPATCH(inst));
-        for(iter = tmp; iter; iter = iter->prototype) {
-            hres = disp_cmp(V_DISPATCH(&var), (IDispatch*)_IDispatchEx_(iter), &b);
+    v = stack_pop(ctx);
+
+    if(is_object_instance(prot)) {
+        if(is_object_instance(v))
+            tmp = iface_to_jsdisp((IUnknown*)get_object(v));
+        for(iter = tmp; !ret && iter; iter = iter->prototype) {
+            hres = disp_cmp(get_object(prot), to_disp(iter), &ret);
             if(FAILED(hres))
                 break;
-            if(b) {
-                ret = VARIANT_TRUE;
-                break;
-            }
         }
 
         if(tmp)
@@ -2040,370 +1381,294 @@ static HRESULT instanceof_eval(exec_ctx_t *ctx, VARIANT *inst, VARIANT *objv, js
         hres = E_FAIL;
     }
 
-    VariantClear(&var);
+    jsval_release(prot);
+    jsval_release(v);
     if(FAILED(hres))
         return hres;
 
-    V_VT(retv) = VT_BOOL;
-    V_BOOL(retv) = ret;
-    return S_OK;
-}
-
-/* ECMA-262 3rd Edition    11.8.6 */
-HRESULT instanceof_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-
-    TRACE("\n");
-
-    return binary_expr_eval(ctx, expr, instanceof_eval, ei, ret);
+    return stack_push(ctx, jsval_bool(ret));
 }
 
 /* ECMA-262 3rd Edition    11.8.7 */
-static HRESULT in_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *obj, jsexcept_t *ei, VARIANT *retv)
+static HRESULT interp_in(exec_ctx_t *ctx)
 {
-    VARIANT_BOOL ret;
-    DISPID id;
-    BSTR str;
+    jsval_t obj, v;
+    DISPID id = 0;
+    BOOL ret;
+    jsstr_t *str;
     HRESULT hres;
 
-    if(V_VT(obj) != VT_DISPATCH) {
-        FIXME("throw TypeError\n");
-        return E_FAIL;
+    TRACE("\n");
+
+    obj = stack_pop(ctx);
+    if(!is_object_instance(obj) || !get_object(obj)) {
+        jsval_release(obj);
+        return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
     }
 
-    hres = to_string(ctx->parser->script, lval, ei, &str);
-    if(FAILED(hres))
+    v = stack_pop(ctx);
+    hres = to_string(ctx->script, v, &str);
+    jsval_release(v);
+    if(FAILED(hres)) {
+        IDispatch_Release(get_object(obj));
         return hres;
+    }
 
-    hres = disp_get_id(ctx->parser->script, V_DISPATCH(obj), str, 0, &id);
-    SysFreeString(str);
+    hres = disp_get_id(ctx->script, get_object(obj), str->str, NULL, 0, &id);
+    IDispatch_Release(get_object(obj));
+    jsstr_release(str);
     if(SUCCEEDED(hres))
-        ret = VARIANT_TRUE;
+        ret = TRUE;
     else if(hres == DISP_E_UNKNOWNNAME)
-        ret = VARIANT_FALSE;
+        ret = FALSE;
     else
         return hres;
 
-    V_VT(retv) = VT_BOOL;
-    V_BOOL(retv) = ret;
-    return S_OK;
-}
-
-/* ECMA-262 3rd Edition    11.8.7 */
-HRESULT in_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-
-    TRACE("\n");
-
-    return binary_expr_eval(ctx, expr, in_eval, ei, ret);
+    return stack_push(ctx, jsval_bool(ret));
 }
 
 /* ECMA-262 3rd Edition    11.6.1 */
-static HRESULT add_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
+static HRESULT add_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, jsval_t *ret)
 {
-    VARIANT r, l;
+    jsval_t r, l;
     HRESULT hres;
 
-    hres = to_primitive(ctx->parser->script, lval, ei, &l, NO_HINT);
+    hres = to_primitive(ctx, lval, &l, NO_HINT);
     if(FAILED(hres))
         return hres;
 
-    hres = to_primitive(ctx->parser->script, rval, ei, &r, NO_HINT);
+    hres = to_primitive(ctx, rval, &r, NO_HINT);
     if(FAILED(hres)) {
-        VariantClear(&l);
+        jsval_release(l);
         return hres;
     }
 
-    if(V_VT(&l) == VT_BSTR || V_VT(&r) == VT_BSTR) {
-        BSTR lstr = NULL, rstr = NULL;
+    if(is_string(l) || is_string(r)) {
+        jsstr_t *lstr, *rstr = NULL;
 
-        if(V_VT(&l) == VT_BSTR)
-            lstr = V_BSTR(&l);
-        else
-            hres = to_string(ctx->parser->script, &l, ei, &lstr);
-
-        if(SUCCEEDED(hres)) {
-            if(V_VT(&r) == VT_BSTR)
-                rstr = V_BSTR(&r);
-            else
-                hres = to_string(ctx->parser->script, &r, ei, &rstr);
-        }
+        hres = to_string(ctx, l, &lstr);
+        if(SUCCEEDED(hres))
+            hres = to_string(ctx, r, &rstr);
 
         if(SUCCEEDED(hres)) {
-            int len1, len2;
+            jsstr_t *ret_str;
 
-            len1 = SysStringLen(lstr);
-            len2 = SysStringLen(rstr);
-
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = SysAllocStringLen(NULL, len1+len2);
-            memcpy(V_BSTR(retv), lstr, len1*sizeof(WCHAR));
-            memcpy(V_BSTR(retv)+len1, rstr, (len2+1)*sizeof(WCHAR));
+            ret_str = jsstr_concat(lstr, rstr);
+            if(ret_str)
+                *ret = jsval_string(ret_str);
+            else
+                hres = E_OUTOFMEMORY;
         }
 
-        if(V_VT(&l) != VT_BSTR)
-            SysFreeString(lstr);
-        if(V_VT(&r) != VT_BSTR)
-            SysFreeString(rstr);
+        jsstr_release(lstr);
+        if(rstr)
+            jsstr_release(rstr);
     }else {
-        VARIANT nl, nr;
+        double nl, nr;
 
-        hres = to_number(ctx->parser->script, &l, ei, &nl);
+        hres = to_number(ctx, l, &nl);
         if(SUCCEEDED(hres)) {
-            hres = to_number(ctx->parser->script, &r, ei, &nr);
+            hres = to_number(ctx, r, &nr);
             if(SUCCEEDED(hres))
-                num_set_val(retv, num_val(&nl) + num_val(&nr));
+                *ret = jsval_number(nl+nr);
         }
     }
 
-    VariantClear(&r);
-    VariantClear(&l);
+    jsval_release(r);
+    jsval_release(l);
     return hres;
 }
 
 /* ECMA-262 3rd Edition    11.6.1 */
-HRESULT add_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-
-    TRACE("\n");
-
-    return binary_expr_eval(ctx, expr, add_eval, ei, ret);
-}
-
-/* ECMA-262 3rd Edition    11.6.2 */
-static HRESULT sub_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
+static HRESULT interp_add(exec_ctx_t *ctx)
 {
-    VARIANT lnum, rnum;
+    jsval_t l, r, ret;
     HRESULT hres;
 
-    hres = to_number(ctx->parser->script, lval, ei, &lnum);
-    if(FAILED(hres))
-        return hres;
+    r = stack_pop(ctx);
+    l = stack_pop(ctx);
+
+    TRACE("%s + %s\n", debugstr_jsval(l), debugstr_jsval(r));
 
-    hres = to_number(ctx->parser->script, rval, ei, &rnum);
+    hres = add_eval(ctx->script, l, r, &ret);
+    jsval_release(l);
+    jsval_release(r);
     if(FAILED(hres))
         return hres;
 
-    num_set_val(retv, num_val(&lnum) - num_val(&rnum));
-    return S_OK;
+    return stack_push(ctx, ret);
 }
 
 /* ECMA-262 3rd Edition    11.6.2 */
-HRESULT sub_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_sub(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    double l, r;
+    HRESULT hres;
 
     TRACE("\n");
 
-    return binary_expr_eval(ctx, expr, sub_eval, ei, ret);
-}
-
-/* ECMA-262 3rd Edition    11.5.1 */
-static HRESULT mul_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
-{
-    VARIANT lnum, rnum;
-    HRESULT hres;
-
-    hres = to_number(ctx->parser->script, lval, ei, &lnum);
+    hres = stack_pop_number(ctx, &r);
     if(FAILED(hres))
         return hres;
 
-    hres = to_number(ctx->parser->script, rval, ei, &rnum);
+    hres = stack_pop_number(ctx, &l);
     if(FAILED(hres))
         return hres;
 
-    num_set_val(retv, num_val(&lnum) * num_val(&rnum));
-    return S_OK;
+    return stack_push(ctx, jsval_number(l-r));
 }
 
 /* ECMA-262 3rd Edition    11.5.1 */
-HRESULT mul_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_mul(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    double l, r;
+    HRESULT hres;
 
     TRACE("\n");
 
-    return binary_expr_eval(ctx, expr, mul_eval, ei, ret);
-}
-
-/* ECMA-262 3rd Edition    11.5.2 */
-static HRESULT div_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
-{
-    VARIANT lnum, rnum;
-    HRESULT hres;
-
-    hres = to_number(ctx->parser->script, lval, ei, &lnum);
+    hres = stack_pop_number(ctx, &r);
     if(FAILED(hres))
         return hres;
 
-    hres = to_number(ctx->parser->script, rval, ei, &rnum);
+    hres = stack_pop_number(ctx, &l);
     if(FAILED(hres))
         return hres;
 
-    num_set_val(retv, num_val(&lnum) / num_val(&rnum));
-    return S_OK;
+    return stack_push(ctx, jsval_number(l*r));
 }
 
 /* ECMA-262 3rd Edition    11.5.2 */
-HRESULT div_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_div(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    double l, r;
+    HRESULT hres;
 
     TRACE("\n");
 
-    return binary_expr_eval(ctx, expr, div_eval, ei, ret);
-}
-
-/* ECMA-262 3rd Edition    11.5.3 */
-static HRESULT mod_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
-{
-    VARIANT lnum, rnum;
-    HRESULT hres;
-
-    hres = to_number(ctx->parser->script, lval, ei, &lnum);
+    hres = stack_pop_number(ctx, &r);
     if(FAILED(hres))
         return hres;
 
-    hres = to_number(ctx->parser->script, rval, ei, &rnum);
+    hres = stack_pop_number(ctx, &l);
     if(FAILED(hres))
         return hres;
 
-    num_set_val(retv, fmod(num_val(&lnum), num_val(&rnum)));
-    return S_OK;
+    return stack_push(ctx, jsval_number(l/r));
 }
 
 /* ECMA-262 3rd Edition    11.5.3 */
-HRESULT mod_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_mod(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    double l, r;
+    HRESULT hres;
 
     TRACE("\n");
 
-    return binary_expr_eval(ctx, expr, mod_eval, ei, ret);
+    hres = stack_pop_number(ctx, &r);
+    if(FAILED(hres))
+        return hres;
+
+    hres = stack_pop_number(ctx, &l);
+    if(FAILED(hres))
+        return hres;
+
+    return stack_push(ctx, jsval_number(fmod(l, r)));
 }
 
 /* ECMA-262 3rd Edition    11.4.2 */
-HRESULT delete_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_delete(exec_ctx_t *ctx)
 {
-    unary_expression_t *expr = (unary_expression_t*)_expr;
-    VARIANT_BOOL b = VARIANT_FALSE;
-    exprval_t exprval;
+    jsval_t objv, namev;
+    IDispatch *obj;
+    jsstr_t *name;
+    BOOL ret;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = expr_eval(ctx, expr->expression, EXPR_STRREF, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    switch(exprval.type) {
-    case EXPRVAL_IDREF: {
-        IDispatchEx *dispex;
+    namev = stack_pop(ctx);
+    objv = stack_pop(ctx);
 
-        hres = IDispatch_QueryInterface(exprval.u.nameref.disp, &IID_IDispatchEx, (void**)&dispex);
-        if(SUCCEEDED(hres)) {
-            hres = IDispatchEx_DeleteMemberByDispID(dispex, exprval.u.idref.id);
-            b = VARIANT_TRUE;
-            IDispatchEx_Release(dispex);
-        }
-        break;
+    hres = to_object(ctx->script, objv, &obj);
+    jsval_release(objv);
+    if(FAILED(hres)) {
+        jsval_release(namev);
+        return hres;
     }
-    case EXPRVAL_NAMEREF: {
-        IDispatchEx *dispex;
 
-        hres = IDispatch_QueryInterface(exprval.u.nameref.disp, &IID_IDispatchEx, (void**)&dispex);
-        if(SUCCEEDED(hres)) {
-            hres = IDispatchEx_DeleteMemberByName(dispex, exprval.u.nameref.name,
-                    make_grfdex(ctx->parser->script, fdexNameCaseSensitive));
-            b = VARIANT_TRUE;
-            IDispatchEx_Release(dispex);
-        }
-        break;
-    }
-    default:
-        FIXME("unsupported type %d\n", exprval.type);
-        hres = E_NOTIMPL;
+    hres = to_string(ctx->script, namev, &name);
+    jsval_release(namev);
+    if(FAILED(hres)) {
+        IDispatch_Release(obj);
+        return hres;
     }
 
-    exprval_release(&exprval);
+    hres = disp_delete_name(ctx->script, obj, name, &ret);
+    IDispatch_Release(obj);
+    jsstr_release(name);
     if(FAILED(hres))
         return hres;
 
-    return return_bool(ret, b);
+    return stack_push(ctx, jsval_bool(ret));
 }
 
 /* ECMA-262 3rd Edition    11.4.2 */
-HRESULT void_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_delete_ident(exec_ctx_t *ctx)
 {
-    unary_expression_t *expr = (unary_expression_t*)_expr;
+    const BSTR arg = get_op_bstr(ctx, 0);
     exprval_t exprval;
-    VARIANT tmp;
+    BOOL ret;
     HRESULT hres;
 
-    TRACE("\n");
+    TRACE("%s\n", debugstr_w(arg));
 
-    hres = expr_eval(ctx, expr->expression, 0, ei, &exprval);
+    hres = identifier_eval(ctx->script, arg, &exprval);
     if(FAILED(hres))
         return hres;
 
-    hres = exprval_to_value(ctx->parser->script, &exprval, ei, &tmp);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
+    switch(exprval.type) {
+    case EXPRVAL_IDREF:
+        hres = disp_delete(exprval.u.idref.disp, exprval.u.idref.id, &ret);
+        IDispatch_Release(exprval.u.idref.disp);
+        if(FAILED(hres))
+            return ret;
+        break;
+    case EXPRVAL_INVALID:
+        ret = TRUE;
+        break;
+    default:
+        FIXME("Unsupported exprval\n");
+        exprval_release(&exprval);
+        return E_NOTIMPL;
+    }
 
-    VariantClear(&tmp);
 
-    ret->type = EXPRVAL_VARIANT;
-    V_VT(&ret->u.var) = VT_EMPTY;
-    return S_OK;
+    return stack_push(ctx, jsval_bool(ret));
 }
 
-/* ECMA-262 3rd Edition    11.4.3 */
-static HRESULT typeof_exprval(exec_ctx_t *ctx, exprval_t *exprval, jsexcept_t *ei, const WCHAR **ret)
+/* ECMA-262 3rd Edition    11.4.2 */
+static HRESULT interp_void(exec_ctx_t *ctx)
 {
-    VARIANT val;
-    HRESULT hres;
-
-    static const WCHAR booleanW[] = {'b','o','o','l','e','a','n',0};
-    static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0};
-    static const WCHAR numberW[] = {'n','u','m','b','e','r',0};
-    static const WCHAR objectW[] = {'o','b','j','e','c','t',0};
-    static const WCHAR stringW[] = {'s','t','r','i','n','g',0};
-    static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
-
-    if(exprval->type == EXPRVAL_INVALID) {
-        *ret = undefinedW;
-        return S_OK;
-    }
+    TRACE("\n");
 
-    hres = exprval_to_value(ctx->parser->script, exprval, ei, &val);
-    if(FAILED(hres))
-        return hres;
+    stack_popn(ctx, 1);
+    return stack_push(ctx, jsval_undefined());
+}
 
-    switch(V_VT(&val)) {
-    case VT_EMPTY:
+/* ECMA-262 3rd Edition    11.4.3 */
+static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
+{
+    switch(jsval_type(v)) {
+    case JSV_UNDEFINED:
         *ret = undefinedW;
         break;
-    case VT_NULL:
+    case JSV_NULL:
         *ret = objectW;
         break;
-    case VT_BOOL:
-        *ret = booleanW;
-        break;
-    case VT_I4:
-    case VT_R8:
-        *ret = numberW;
-        break;
-    case VT_BSTR:
-        *ret = stringW;
-        break;
-    case VT_DISPATCH: {
-        DispatchEx *dispex;
+    case JSV_OBJECT: {
+        jsdisp_t *dispex;
 
-        if(V_DISPATCH(&val) && (dispex = iface_to_jsdisp((IUnknown*)V_DISPATCH(&val)))) {
+        if(get_object(v) && (dispex = iface_to_jsdisp((IUnknown*)get_object(v)))) {
             *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW;
             jsdisp_release(dispex);
         }else {
@@ -2411,328 +1676,274 @@ static HRESULT typeof_exprval(exec_ctx_t *ctx, exprval_t *exprval, jsexcept_t *e
         }
         break;
     }
-    default:
-        FIXME("unhandled vt %d\n", V_VT(&val));
-        hres = E_NOTIMPL;
-    }
-
-    VariantClear(&val);
-    return S_OK;
-}
-
-HRESULT typeof_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    unary_expression_t *expr = (unary_expression_t*)_expr;
-    const WCHAR *str = NULL;
-    exprval_t exprval;
-    HRESULT hres;
-
-    TRACE("\n");
-
-    hres = expr_eval(ctx, expr->expression, 0, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = typeof_exprval(ctx, &exprval, ei, &str);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
-
-    ret->type = EXPRVAL_VARIANT;
-    V_VT(&ret->u.var) = VT_BSTR;
-    V_BSTR(&ret->u.var) = SysAllocString(str);
-    if(!V_BSTR(&ret->u.var))
-        return E_OUTOFMEMORY;
+    case JSV_STRING:
+        *ret = stringW;
+        break;
+    case JSV_NUMBER:
+        *ret = numberW;
+        break;
+    case JSV_BOOL:
+        *ret = booleanW;
+        break;
+    case JSV_VARIANT:
+        FIXME("unhandled variant %s\n", debugstr_variant(get_variant(v)));
+        return E_NOTIMPL;
+    }
 
     return S_OK;
 }
 
-/* ECMA-262 3rd Edition    11.4.7 */
-HRESULT minus_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.4.3 */
+static HRESULT interp_typeofid(exec_ctx_t *ctx)
 {
-    unary_expression_t *expr = (unary_expression_t*)_expr;
-    exprval_t exprval;
-    VARIANT val, num;
+    const WCHAR *ret;
+    IDispatch *obj;
+    jsval_t v;
+    DISPID id;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = expr_eval(ctx, expr->expression, 0, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
+    obj = stack_pop_objid(ctx, &id);
+    if(!obj)
+        return stack_push(ctx, jsval_string(jsstr_undefined()));
 
-    hres = exprval_to_value(ctx->parser->script, &exprval, ei, &val);
-    exprval_release(&exprval);
+    hres = disp_propget(ctx->script, obj, id, &v);
+    IDispatch_Release(obj);
     if(FAILED(hres))
-        return hres;
+        return stack_push_string(ctx, unknownW);
 
-    hres = to_number(ctx->parser->script, &val, ei, &num);
-    VariantClear(&val);
+    hres = typeof_string(v, &ret);
+    jsval_release(v);
     if(FAILED(hres))
         return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    num_set_val(&ret->u.var, -num_val(&num));
-    return S_OK;
+    return stack_push_string(ctx, ret);
 }
 
-/* ECMA-262 3rd Edition    11.4.6 */
-HRESULT plus_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.4.3 */
+static HRESULT interp_typeofident(exec_ctx_t *ctx)
 {
-    unary_expression_t *expr = (unary_expression_t*)_expr;
+    const BSTR arg = get_op_bstr(ctx, 0);
     exprval_t exprval;
-    VARIANT val, num;
+    const WCHAR *ret;
+    jsval_t v;
     HRESULT hres;
 
-    TRACE("\n");
+    TRACE("%s\n", debugstr_w(arg));
 
-    hres = expr_eval(ctx, expr->expression, EXPR_NEWREF, ei, &exprval);
+    hres = identifier_eval(ctx->script, arg, &exprval);
     if(FAILED(hres))
         return hres;
 
-    hres = exprval_to_value(ctx->parser->script, &exprval, ei, &val);
+    if(exprval.type == EXPRVAL_INVALID) {
+        hres = stack_push(ctx, jsval_string(jsstr_undefined()));
+        exprval_release(&exprval);
+        return hres;
+    }
+
+    hres = exprval_to_value(ctx->script, &exprval, &v);
     exprval_release(&exprval);
     if(FAILED(hres))
         return hres;
 
-    hres = to_number(ctx->parser->script, &val, ei, &num);
-    VariantClear(&val);
+    hres = typeof_string(v, &ret);
+    jsval_release(v);
     if(FAILED(hres))
         return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = num;
-    return S_OK;
+    return stack_push_string(ctx, ret);
 }
 
-/* ECMA-262 3rd Edition    11.3.1 */
-HRESULT post_increment_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.4.3 */
+static HRESULT interp_typeof(exec_ctx_t *ctx)
 {
-    unary_expression_t *expr = (unary_expression_t*)_expr;
-    VARIANT val, num;
-    exprval_t exprval;
+    const WCHAR *ret;
+    jsval_t v;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = expr_eval(ctx, expr->expression, EXPR_NEWREF, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = exprval_value(ctx->parser->script, &exprval, ei, &val);
-    if(SUCCEEDED(hres)) {
-        hres = to_number(ctx->parser->script, &val, ei, &num);
-        VariantClear(&val);
-    }
-
-    if(SUCCEEDED(hres)) {
-        VARIANT inc;
-        num_set_val(&inc, num_val(&num)+1.0);
-        hres = put_value(ctx->parser->script, &exprval, &inc, ei);
-    }
-
-    exprval_release(&exprval);
+    v = stack_pop(ctx);
+    hres = typeof_string(v, &ret);
+    jsval_release(v);
     if(FAILED(hres))
         return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = num;
-    return S_OK;
+    return stack_push_string(ctx, ret);
 }
 
-/* ECMA-262 3rd Edition    11.3.2 */
-HRESULT post_decrement_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.4.7 */
+static HRESULT interp_minus(exec_ctx_t *ctx)
 {
-    unary_expression_t *expr = (unary_expression_t*)_expr;
-    VARIANT val, num;
-    exprval_t exprval;
+    double n;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = expr_eval(ctx, expr->expression, EXPR_NEWREF, ei, &exprval);
+    hres = stack_pop_number(ctx, &n);
     if(FAILED(hres))
         return hres;
 
-    hres = exprval_value(ctx->parser->script, &exprval, ei, &val);
-    if(SUCCEEDED(hres)) {
-        hres = to_number(ctx->parser->script, &val, ei, &num);
-        VariantClear(&val);
-    }
+    return stack_push(ctx, jsval_number(-n));
+}
 
-    if(SUCCEEDED(hres)) {
-        VARIANT dec;
-        num_set_val(&dec, num_val(&num)-1.0);
-        hres = put_value(ctx->parser->script, &exprval, &dec, ei);
-    }
+/* ECMA-262 3rd Edition    11.4.6 */
+static HRESULT interp_tonum(exec_ctx_t *ctx)
+{
+    jsval_t v;
+    double n;
+    HRESULT hres;
 
-    exprval_release(&exprval);
+    TRACE("\n");
+
+    v = stack_pop(ctx);
+    hres = to_number(ctx->script, v, &n);
+    jsval_release(v);
     if(FAILED(hres))
         return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = num;
-    return S_OK;
+    return stack_push(ctx, jsval_number(n));
 }
 
-/* ECMA-262 3rd Edition    11.4.4 */
-HRESULT pre_increment_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.3.1 */
+static HRESULT interp_postinc(exec_ctx_t *ctx)
 {
-    unary_expression_t *expr = (unary_expression_t*)_expr;
-    VARIANT val, num;
-    exprval_t exprval;
+    const int arg = get_op_int(ctx, 0);
+    IDispatch *obj;
+    DISPID id;
+    jsval_t v;
     HRESULT hres;
 
-    TRACE("\n");
+    TRACE("%d\n", arg);
 
-    hres = expr_eval(ctx, expr->expression, EXPR_NEWREF, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
+    obj = stack_pop_objid(ctx, &id);
+    if(!obj)
+        return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
 
-    hres = exprval_value(ctx->parser->script, &exprval, ei, &val);
+    hres = disp_propget(ctx->script, obj, id, &v);
     if(SUCCEEDED(hres)) {
-        hres = to_number(ctx->parser->script, &val, ei, &num);
-        VariantClear(&val);
-    }
+        double n;
 
-    if(SUCCEEDED(hres)) {
-        num_set_val(&val, num_val(&num)+1.0);
-        hres = put_value(ctx->parser->script, &exprval, &val, ei);
+        hres = to_number(ctx->script, v, &n);
+        if(SUCCEEDED(hres))
+            hres = disp_propput(ctx->script, obj, id, jsval_number(n+(double)arg));
+        if(FAILED(hres))
+            jsval_release(v);
     }
-
-    exprval_release(&exprval);
+    IDispatch_Release(obj);
     if(FAILED(hres))
         return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = val;
-    return S_OK;
+    return stack_push(ctx, v);
 }
 
-/* ECMA-262 3rd Edition    11.4.5 */
-HRESULT pre_decrement_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.4.4, 11.4.5 */
+static HRESULT interp_preinc(exec_ctx_t *ctx)
 {
-    unary_expression_t *expr = (unary_expression_t*)_expr;
-    VARIANT val, num;
-    exprval_t exprval;
+    const int arg = get_op_int(ctx, 0);
+    IDispatch *obj;
+    double ret;
+    DISPID id;
+    jsval_t v;
     HRESULT hres;
 
-    TRACE("\n");
+    TRACE("%d\n", arg);
 
-    hres = expr_eval(ctx, expr->expression, EXPR_NEWREF, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
+    obj = stack_pop_objid(ctx, &id);
+    if(!obj)
+        return throw_type_error(ctx->script, JS_E_OBJECT_EXPECTED, NULL);
 
-    hres = exprval_value(ctx->parser->script, &exprval, ei, &val);
+    hres = disp_propget(ctx->script, obj, id, &v);
     if(SUCCEEDED(hres)) {
-        hres = to_number(ctx->parser->script, &val, ei, &num);
-        VariantClear(&val);
-    }
+        double n;
 
-    if(SUCCEEDED(hres)) {
-        num_set_val(&val, num_val(&num)-1.0);
-        hres = put_value(ctx->parser->script, &exprval, &val, ei);
+        hres = to_number(ctx->script, v, &n);
+        jsval_release(v);
+        if(SUCCEEDED(hres)) {
+            ret = n+(double)arg;
+            hres = disp_propput(ctx->script, obj, id, jsval_number(ret));
+        }
     }
-
-    exprval_release(&exprval);
+    IDispatch_Release(obj);
     if(FAILED(hres))
         return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = val;
-    return S_OK;
+    return stack_push(ctx, jsval_number(ret));
 }
 
 /* ECMA-262 3rd Edition    11.9.3 */
-static HRESULT equal_values(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, BOOL *ret)
+static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL *ret)
 {
-    if(V_VT(lval) == V_VT(rval) || (is_num_vt(V_VT(lval)) && is_num_vt(V_VT(rval))))
+    if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval)))
        return equal2_values(lval, rval, ret);
 
     /* FIXME: NULL disps should be handled in more general way */
-    if(V_VT(lval) == VT_DISPATCH && !V_DISPATCH(lval)) {
-        VARIANT v;
-        V_VT(&v) = VT_NULL;
-        return equal_values(ctx, &v, rval, ei, ret);
-    }
-
-    if(V_VT(rval) == VT_DISPATCH && !V_DISPATCH(rval)) {
-        VARIANT v;
-        V_VT(&v) = VT_NULL;
-        return equal_values(ctx, lval, &v, ei, ret);
-    }
+    if(is_object_instance(lval) && !get_object(lval))
+        return equal_values(ctx, jsval_null(), rval, ret);
+    if(is_object_instance(rval) && !get_object(rval))
+        return equal_values(ctx, lval, jsval_null(), ret);
 
-    if((V_VT(lval) == VT_NULL && V_VT(rval) == VT_EMPTY) ||
-       (V_VT(lval) == VT_EMPTY && V_VT(rval) == VT_NULL)) {
+    if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) {
         *ret = TRUE;
         return S_OK;
     }
 
-    if(V_VT(lval) == VT_BSTR && is_num_vt(V_VT(rval))) {
-        VARIANT v;
+    if(is_string(lval) && is_number(rval)) {
+        double n;
         HRESULT hres;
 
-        hres = to_number(ctx->parser->script, lval, ei, &v);
+        hres = to_number(ctx, lval, &n);
         if(FAILED(hres))
             return hres;
 
-        return equal_values(ctx, &v, rval, ei, ret);
+        /* FIXME: optimize */
+        return equal_values(ctx, jsval_number(n), rval, ret);
     }
 
-    if(V_VT(rval) == VT_BSTR && is_num_vt(V_VT(lval))) {
-        VARIANT v;
+    if(is_string(rval) && is_number(lval)) {
+        double n;
         HRESULT hres;
 
-        hres = to_number(ctx->parser->script, rval, ei, &v);
+        hres = to_number(ctx, rval, &n);
         if(FAILED(hres))
             return hres;
 
-        return equal_values(ctx, lval, &v, ei, ret);
-    }
-
-    if(V_VT(rval) == VT_BOOL) {
-        VARIANT v;
-
-        V_VT(&v) = VT_I4;
-        V_I4(&v) = V_BOOL(rval) ? 1 : 0;
-        return equal_values(ctx, lval, &v, ei, ret);
+        /* FIXME: optimize */
+        return equal_values(ctx, lval, jsval_number(n), ret);
     }
 
-    if(V_VT(lval) == VT_BOOL) {
-        VARIANT v;
+    if(is_bool(rval))
+        return equal_values(ctx, lval, jsval_number(get_bool(rval) ? 1 : 0), ret);
 
-        V_VT(&v) = VT_I4;
-        V_I4(&v) = V_BOOL(lval) ? 1 : 0;
-        return equal_values(ctx, &v, rval, ei, ret);
-    }
+    if(is_bool(lval))
+        return equal_values(ctx, jsval_number(get_bool(lval) ? 1 : 0), rval, ret);
 
 
-    if(V_VT(rval) == VT_DISPATCH && (V_VT(lval) == VT_BSTR || is_num_vt(V_VT(lval)))) {
-        VARIANT v;
+    if(is_object_instance(rval) && (is_string(lval) || is_number(lval))) {
+        jsval_t prim;
         HRESULT hres;
 
-        hres = to_primitive(ctx->parser->script, rval, ei, &v, NO_HINT);
+        hres = to_primitive(ctx, rval, &prim, NO_HINT);
         if(FAILED(hres))
             return hres;
 
-        hres = equal_values(ctx, lval, &v, ei, ret);
-
-        VariantClear(&v);
+        hres = equal_values(ctx, lval, prim, ret);
+        jsval_release(prim);
         return hres;
     }
 
 
-    if(V_VT(lval) == VT_DISPATCH && (V_VT(rval) == VT_BSTR || is_num_vt(V_VT(rval)))) {
-        VARIANT v;
+    if(is_object_instance(lval) && (is_string(rval) || is_number(rval))) {
+        jsval_t prim;
         HRESULT hres;
 
-        hres = to_primitive(ctx->parser->script, lval, ei, &v, NO_HINT);
+        hres = to_primitive(ctx, lval, &prim, NO_HINT);
         if(FAILED(hres))
             return hres;
 
-        hres = equal_values(ctx, &v, rval, ei, ret);
-
-        VariantClear(&v);
+        hres = equal_values(ctx, prim, rval, ret);
+        jsval_release(prim);
         return hres;
     }
 
@@ -2742,514 +1953,588 @@ static HRESULT equal_values(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexc
 }
 
 /* ECMA-262 3rd Edition    11.9.1 */
-HRESULT equal_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_eq(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    VARIANT rval, lval;
+    jsval_t l, r;
     BOOL b;
     HRESULT hres;
 
-    TRACE("\n");
+    r = stack_pop(ctx);
+    l = stack_pop(ctx);
 
-    hres = get_binary_expr_values(ctx, expr, ei, &rval, &lval);
-    if(FAILED(hres))
-        return hres;
+    TRACE("%s == %s\n", debugstr_jsval(l), debugstr_jsval(r));
 
-    hres = equal_values(ctx, &rval, &lval, ei, &b);
-    VariantClear(&lval);
-    VariantClear(&rval);
+    hres = equal_values(ctx->script, l, r, &b);
+    jsval_release(l);
+    jsval_release(r);
     if(FAILED(hres))
         return hres;
 
-    return return_bool(ret, b);
+    return stack_push(ctx, jsval_bool(b));
 }
 
-/* ECMA-262 3rd Edition    11.9.4 */
-HRESULT equal2_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.9.2 */
+static HRESULT interp_neq(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    VARIANT rval, lval;
+    jsval_t l, r;
     BOOL b;
     HRESULT hres;
 
-    TRACE("\n");
+    r = stack_pop(ctx);
+    l = stack_pop(ctx);
 
-    hres = get_binary_expr_values(ctx, expr, ei, &rval, &lval);
-    if(FAILED(hres))
-        return hres;
+    TRACE("%s != %s\n", debugstr_jsval(l), debugstr_jsval(r));
 
-    hres = equal2_values(&rval, &lval, &b);
-    VariantClear(&lval);
-    VariantClear(&rval);
+    hres = equal_values(ctx->script, l, r, &b);
+    jsval_release(l);
+    jsval_release(r);
     if(FAILED(hres))
         return hres;
 
-    return return_bool(ret, b);
+    return stack_push(ctx, jsval_bool(!b));
 }
 
-/* ECMA-262 3rd Edition    11.9.2 */
-HRESULT not_equal_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.9.4 */
+static HRESULT interp_eq2(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    VARIANT rval, lval;
+    jsval_t l, r;
     BOOL b;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_binary_expr_values(ctx, expr, ei, &lval, &rval);
-    if(FAILED(hres))
-        return hres;
+    r = stack_pop(ctx);
+    l = stack_pop(ctx);
 
-    hres = equal_values(ctx, &lval, &rval, ei, &b);
-    VariantClear(&lval);
-    VariantClear(&rval);
+    hres = equal2_values(r, l, &b);
+    jsval_release(l);
+    jsval_release(r);
     if(FAILED(hres))
         return hres;
 
-    return return_bool(ret, !b);
+    return stack_push(ctx, jsval_bool(b));
 }
 
 /* ECMA-262 3rd Edition    11.9.5 */
-HRESULT not_equal2_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_neq2(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    VARIANT rval, lval;
+    jsval_t l, r;
     BOOL b;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_binary_expr_values(ctx, expr, ei, &lval, &rval);
-    if(FAILED(hres))
-        return hres;
+    r = stack_pop(ctx);
+    l = stack_pop(ctx);
 
-    hres = equal2_values(&lval, &rval, &b);
-    VariantClear(&lval);
-    VariantClear(&rval);
+    hres = equal2_values(r, l, &b);
+    jsval_release(l);
+    jsval_release(r);
     if(FAILED(hres))
         return hres;
 
-    return return_bool(ret, !b);
+    return stack_push(ctx, jsval_bool(!b));
 }
 
 /* ECMA-262 3rd Edition    11.8.5 */
-static HRESULT less_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, BOOL greater, jsexcept_t *ei, BOOL *ret)
+static HRESULT less_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL greater, BOOL *ret)
 {
-    VARIANT l, r, ln, rn;
+    double ln, rn;
+    jsval_t l, r;
     HRESULT hres;
 
-    hres = to_primitive(ctx->parser->script, lval, ei, &l, NO_HINT);
+    hres = to_primitive(ctx, lval, &l, NO_HINT);
     if(FAILED(hres))
         return hres;
 
-    hres = to_primitive(ctx->parser->script, rval, ei, &r, NO_HINT);
+    hres = to_primitive(ctx, rval, &r, NO_HINT);
     if(FAILED(hres)) {
-        VariantClear(&l);
+        jsval_release(l);
         return hres;
     }
 
-    if(V_VT(&l) == VT_BSTR && V_VT(&r) == VT_BSTR) {
-        *ret = (strcmpW(V_BSTR(&l), V_BSTR(&r)) < 0) ^ greater;
-        SysFreeString(V_BSTR(&l));
-        SysFreeString(V_BSTR(&r));
+    if(is_string(l) && is_string(r)) {
+        *ret = (jsstr_cmp(get_string(l), get_string(r)) < 0) ^ greater;
+        jsstr_release(get_string(l));
+        jsstr_release(get_string(r));
         return S_OK;
     }
 
-    hres = to_number(ctx->parser->script, &l, ei, &ln);
-    VariantClear(&l);
+    hres = to_number(ctx, l, &ln);
+    jsval_release(l);
     if(SUCCEEDED(hres))
-        hres = to_number(ctx->parser->script, &r, ei, &rn);
-    VariantClear(&r);
+        hres = to_number(ctx, r, &rn);
+    jsval_release(r);
     if(FAILED(hres))
         return hres;
 
-    if(V_VT(&ln) == VT_I4 && V_VT(&rn) == VT_I4) {
-        *ret = (V_I4(&ln) < V_I4(&rn)) ^ greater;
-    }else  {
-        DOUBLE ld = num_val(&ln);
-        DOUBLE rd = num_val(&rn);
-
-        *ret = !isnan(ld) && !isnan(rd) && ((ld < rd) ^ greater);
-    }
-
+    *ret = !isnan(ln) && !isnan(rn) && ((ln < rn) ^ greater);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    11.8.1 */
-HRESULT less_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_lt(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    VARIANT rval, lval;
+    jsval_t l, r;
     BOOL b;
     HRESULT hres;
 
-    TRACE("\n");
+    r = stack_pop(ctx);
+    l = stack_pop(ctx);
 
-    hres = get_binary_expr_values(ctx, expr, ei, &lval, &rval);
-    if(FAILED(hres))
-        return hres;
+    TRACE("%s < %s\n", debugstr_jsval(l), debugstr_jsval(r));
 
-    hres = less_eval(ctx, &lval, &rval, FALSE, ei, &b);
-    VariantClear(&lval);
-    VariantClear(&rval);
+    hres = less_eval(ctx->script, l, r, FALSE, &b);
+    jsval_release(l);
+    jsval_release(r);
     if(FAILED(hres))
         return hres;
 
-    return return_bool(ret, b);
+    return stack_push(ctx, jsval_bool(b));
 }
 
-/* ECMA-262 3rd Edition    11.8.3 */
-HRESULT lesseq_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.8.1 */
+static HRESULT interp_lteq(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    VARIANT rval, lval;
+    jsval_t l, r;
     BOOL b;
     HRESULT hres;
 
-    TRACE("\n");
+    r = stack_pop(ctx);
+    l = stack_pop(ctx);
 
-    hres = get_binary_expr_values(ctx, expr, ei, &lval, &rval);
-    if(FAILED(hres))
-        return hres;
+    TRACE("%s <= %s\n", debugstr_jsval(l), debugstr_jsval(r));
 
-    hres = less_eval(ctx, &rval, &lval, TRUE, ei, &b);
-    VariantClear(&lval);
-    VariantClear(&rval);
+    hres = less_eval(ctx->script, r, l, TRUE, &b);
+    jsval_release(l);
+    jsval_release(r);
     if(FAILED(hres))
         return hres;
 
-    return return_bool(ret, b);
+    return stack_push(ctx, jsval_bool(b));
 }
 
 /* ECMA-262 3rd Edition    11.8.2 */
-HRESULT greater_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_gt(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    VARIANT rval, lval;
+    jsval_t l, r;
     BOOL b;
     HRESULT hres;
 
-    TRACE("\n");
+    r = stack_pop(ctx);
+    l = stack_pop(ctx);
 
-    hres = get_binary_expr_values(ctx, expr, ei, &lval, &rval);
-    if(FAILED(hres))
-        return hres;
+    TRACE("%s > %s\n", debugstr_jsval(l), debugstr_jsval(r));
 
-    hres = less_eval(ctx, &rval, &lval, FALSE, ei, &b);
-    VariantClear(&lval);
-    VariantClear(&rval);
+    hres = less_eval(ctx->script, r, l, FALSE, &b);
+    jsval_release(l);
+    jsval_release(r);
     if(FAILED(hres))
         return hres;
 
-    return return_bool(ret, b);
+    return stack_push(ctx, jsval_bool(b));
 }
 
 /* ECMA-262 3rd Edition    11.8.4 */
-HRESULT greatereq_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_gteq(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    VARIANT rval, lval;
+    jsval_t l, r;
     BOOL b;
     HRESULT hres;
 
-    TRACE("\n");
+    r = stack_pop(ctx);
+    l = stack_pop(ctx);
 
-    hres = get_binary_expr_values(ctx, expr, ei, &lval, &rval);
-    if(FAILED(hres))
-        return hres;
+    TRACE("%s >= %s\n", debugstr_jsval(l), debugstr_jsval(r));
 
-    hres = less_eval(ctx, &lval, &rval, TRUE, ei, &b);
-    VariantClear(&lval);
-    VariantClear(&rval);
+    hres = less_eval(ctx->script, l, r, TRUE, &b);
+    jsval_release(l);
+    jsval_release(r);
     if(FAILED(hres))
         return hres;
 
-    return return_bool(ret, b);
+    return stack_push(ctx, jsval_bool(b));
 }
 
 /* ECMA-262 3rd Edition    11.4.8 */
-HRESULT binary_negation_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_bneg(exec_ctx_t *ctx)
 {
-    unary_expression_t *expr = (unary_expression_t*)_expr;
-    exprval_t exprval;
-    VARIANT val;
+    jsval_t v;
     INT i;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = expr_eval(ctx, expr->expression, EXPR_NEWREF, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = exprval_to_value(ctx->parser->script, &exprval, ei, &val);
-    exprval_release(&exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = to_int32(ctx->parser->script, &val, ei, &i);
+    v = stack_pop(ctx);
+    hres = to_int32(ctx->script, v, &i);
+    jsval_release(v);
     if(FAILED(hres))
         return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    V_VT(&ret->u.var) = VT_I4;
-    V_I4(&ret->u.var) = ~i;
-    return S_OK;
+    return stack_push(ctx, jsval_number(~i));
 }
 
 /* ECMA-262 3rd Edition    11.4.9 */
-HRESULT logical_negation_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_neg(exec_ctx_t *ctx)
 {
-    unary_expression_t *expr = (unary_expression_t*)_expr;
-    exprval_t exprval;
-    VARIANT_BOOL b;
+    jsval_t v;
+    BOOL b;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = expr_eval(ctx, expr->expression, EXPR_NEWREF, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
-
-    hres = exprval_to_boolean(ctx->parser->script, &exprval, ei, &b);
-    exprval_release(&exprval);
+    v = stack_pop(ctx);
+    hres = to_boolean(v, &b);
+    jsval_release(v);
     if(FAILED(hres))
         return hres;
 
-    return return_bool(ret, !b);
+    return stack_push(ctx, jsval_bool(!b));
 }
 
 /* ECMA-262 3rd Edition    11.7.1 */
-static HRESULT lshift_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
+static HRESULT interp_lshift(exec_ctx_t *ctx)
 {
-    DWORD ri;
-    INT li;
+    DWORD r;
+    INT l;
     HRESULT hres;
 
-    hres = to_int32(ctx->parser->script, lval, ei, &li);
+    hres = stack_pop_uint(ctx, &r);
     if(FAILED(hres))
         return hres;
 
-    hres = to_uint32(ctx->parser->script, rval, ei, &ri);
+    hres = stack_pop_int(ctx, &l);
     if(FAILED(hres))
         return hres;
 
-    V_VT(retv) = VT_I4;
-    V_I4(retv) = li << (ri&0x1f);
-    return S_OK;
+    return stack_push(ctx, jsval_number(l << (r&0x1f)));
 }
 
-/* ECMA-262 3rd Edition    11.7.1 */
-HRESULT left_shift_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.7.2 */
+static HRESULT interp_rshift(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    DWORD r;
+    INT l;
+    HRESULT hres;
 
-    TRACE("\n");
+    hres = stack_pop_uint(ctx, &r);
+    if(FAILED(hres))
+        return hres;
+
+    hres = stack_pop_int(ctx, &l);
+    if(FAILED(hres))
+        return hres;
 
-    return binary_expr_eval(ctx, expr, lshift_eval, ei, ret);
+    return stack_push(ctx, jsval_number(l >> (r&0x1f)));
 }
 
-/* ECMA-262 3rd Edition    11.7.2 */
-static HRESULT rshift_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
+/* ECMA-262 3rd Edition    11.7.3 */
+static HRESULT interp_rshift2(exec_ctx_t *ctx)
 {
-    DWORD ri;
-    INT li;
+    DWORD r, l;
     HRESULT hres;
 
-    hres = to_int32(ctx->parser->script, lval, ei, &li);
+    hres = stack_pop_uint(ctx, &r);
     if(FAILED(hres))
         return hres;
 
-    hres = to_uint32(ctx->parser->script, rval, ei, &ri);
+    hres = stack_pop_uint(ctx, &l);
     if(FAILED(hres))
         return hres;
 
-    V_VT(retv) = VT_I4;
-    V_I4(retv) = li >> (ri&0x1f);
-    return S_OK;
+    return stack_push(ctx, jsval_number(l >> (r&0x1f)));
 }
 
-/* ECMA-262 3rd Edition    11.7.2 */
-HRESULT right_shift_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+/* ECMA-262 3rd Edition    11.13.1 */
+static HRESULT interp_assign(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    IDispatch *disp;
+    DISPID id;
+    jsval_t v;
+    HRESULT hres;
 
     TRACE("\n");
 
-    return binary_expr_eval(ctx, expr, rshift_eval, ei, ret);
+    v = stack_pop(ctx);
+
+    disp = stack_pop_objid(ctx, &id);
+    if(!disp) {
+        jsval_release(v);
+        return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
+    }
+
+    hres = disp_propput(ctx->script, disp, id, v);
+    IDispatch_Release(disp);
+    if(FAILED(hres)) {
+        jsval_release(v);
+        return hres;
+    }
+
+    return stack_push(ctx, v);
 }
 
-/* ECMA-262 3rd Edition    11.7.3 */
-static HRESULT rshift2_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_t *ei, VARIANT *retv)
+/* JScript extension */
+static HRESULT interp_assign_call(exec_ctx_t *ctx)
 {
-    DWORD li, ri;
+    const unsigned argc = get_op_uint(ctx, 0);
+    IDispatch *disp;
+    jsval_t v;
+    DISPID id;
     HRESULT hres;
 
-    hres = to_uint32(ctx->parser->script, lval, ei, &li);
-    if(FAILED(hres))
-        return hres;
+    TRACE("%u\n", argc);
+
+    disp = stack_topn_objid(ctx, argc+1, &id);
+    if(!disp)
+        return throw_reference_error(ctx->script, JS_E_ILLEGAL_ASSIGN, NULL);
 
-    hres = to_uint32(ctx->parser->script, rval, ei, &ri);
+    hres = disp_call(ctx->script, disp, id, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL);
     if(FAILED(hres))
         return hres;
 
-    V_VT(retv) = VT_I4;
-    V_I4(retv) = li >> (ri&0x1f);
-    return S_OK;
+    v = stack_pop(ctx);
+    stack_popn(ctx, argc+2);
+    return stack_push(ctx, v);
 }
 
-/* ECMA-262 3rd Edition    11.7.3 */
-HRESULT right2_shift_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_undefined(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-
     TRACE("\n");
 
-    return binary_expr_eval(ctx, expr, rshift2_eval, ei, ret);
+    return stack_push(ctx, jsval_undefined());
 }
 
-/* ECMA-262 3rd Edition    11.13.1 */
-HRESULT assign_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_jmp(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-    exprval_t exprval, exprvalr;
-    VARIANT rval;
-    HRESULT hres;
+    const unsigned arg = get_op_uint(ctx, 0);
 
-    TRACE("\n");
+    TRACE("%u\n", arg);
 
-    hres = expr_eval(ctx, expr->expression1, EXPR_NEWREF, ei, &exprval);
-    if(FAILED(hres))
-        return hres;
+    ctx->ip = arg;
+    return S_OK;
+}
 
-    hres = expr_eval(ctx, expr->expression2, 0, ei, &exprvalr);
-    if(SUCCEEDED(hres)) {
-        hres = exprval_to_value(ctx->parser->script, &exprvalr, ei, &rval);
-        exprval_release(&exprvalr);
-    }
+static HRESULT interp_jmp_z(exec_ctx_t *ctx)
+{
+    const unsigned arg = get_op_uint(ctx, 0);
+    BOOL b;
+    jsval_t v;
+    HRESULT hres;
 
-    if(SUCCEEDED(hres)) {
-        hres = put_value(ctx->parser->script, &exprval, &rval, ei);
-        if(FAILED(hres))
-            VariantClear(&rval);
-    }
+    TRACE("\n");
 
-    exprval_release(&exprval);
+    v = stack_pop(ctx);
+    hres = to_boolean(v, &b);
+    jsval_release(v);
     if(FAILED(hres))
         return hres;
 
-    ret->type = EXPRVAL_VARIANT;
-    ret->u.var = rval;
+    if(b)
+        ctx->ip++;
+    else
+        ctx->ip = arg;
     return S_OK;
 }
 
-/* ECMA-262 3rd Edition    11.13.2 */
-HRESULT assign_lshift_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_pop(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    const unsigned arg = get_op_uint(ctx, 0);
 
-    TRACE("\n");
+    TRACE("%u\n", arg);
 
-    return assign_oper_eval(ctx, expr->expression1, expr->expression2, lshift_eval, ei, ret);
+    stack_popn(ctx, arg);
+    return S_OK;
 }
 
-/* ECMA-262 3rd Edition    11.13.2 */
-HRESULT assign_rshift_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_ret(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-
     TRACE("\n");
 
-    return assign_oper_eval(ctx, expr->expression1, expr->expression2, rshift_eval, ei, ret);
+    ctx->ip = -1;
+    return S_OK;
 }
 
-/* ECMA-262 3rd Edition    11.13.2 */
-HRESULT assign_rrshift_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT interp_setret(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
-
     TRACE("\n");
 
-    return assign_oper_eval(ctx, expr->expression1, expr->expression2, rshift2_eval, ei, ret);
+    jsval_release(ctx->ret);
+    ctx->ret = stack_pop(ctx);
+    return S_OK;
 }
 
-/* ECMA-262 3rd Edition    11.13.2 */
-HRESULT assign_add_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+typedef HRESULT (*op_func_t)(exec_ctx_t*);
 
-    TRACE("\n");
+static const op_func_t op_funcs[] = {
+#define X(x,a,b,c) interp_##x,
+OP_LIST
+#undef X
+};
 
-    return assign_oper_eval(ctx, expr->expression1, expr->expression2, add_eval, ei, ret);
-}
+static const unsigned op_move[] = {
+#define X(a,x,b,c) x,
+OP_LIST
+#undef X
+};
 
-/* ECMA-262 3rd Edition    11.13.2 */
-HRESULT assign_sub_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT unwind_exception(exec_ctx_t *ctx)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    except_frame_t *except_frame;
+    jsval_t except_val;
+    BSTR ident;
+    HRESULT hres;
 
-    TRACE("\n");
+    except_frame = ctx->except_frame;
+    ctx->except_frame = except_frame->next;
 
-    return assign_oper_eval(ctx, expr->expression1, expr->expression2, sub_eval, ei, ret);
-}
+    assert(except_frame->stack_top <= ctx->top);
+    stack_popn(ctx, ctx->top - except_frame->stack_top);
 
-/* ECMA-262 3rd Edition    11.13.2 */
-HRESULT assign_mul_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    while(except_frame->scope != ctx->scope_chain)
+        scope_pop(&ctx->scope_chain);
 
-    TRACE("\n");
+    ctx->ip = except_frame->catch_off;
 
-    return assign_oper_eval(ctx, expr->expression1, expr->expression2, mul_eval, ei, ret);
-}
+    except_val = ctx->script->ei.val;
+    ctx->script->ei.val = jsval_undefined();
+    clear_ei(ctx->script);
 
-/* ECMA-262 3rd Edition    11.13.2 */
-HRESULT assign_div_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    ident = except_frame->ident;
+    heap_free(except_frame);
 
-    TRACE("\n");
+    if(ident) {
+        jsdisp_t *scope_obj;
 
-    return assign_oper_eval(ctx, expr->expression1, expr->expression2, div_eval, ei, ret);
-}
+        hres = create_dispex(ctx->script, NULL, NULL, &scope_obj);
+        if(SUCCEEDED(hres)) {
+            hres = jsdisp_propput_name(scope_obj, ident, except_val);
+            if(FAILED(hres))
+                jsdisp_release(scope_obj);
+        }
+        jsval_release(except_val);
+        if(FAILED(hres))
+            return hres;
 
-/* ECMA-262 3rd Edition    11.13.2 */
-HRESULT assign_mod_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+        hres = scope_push(ctx->scope_chain, scope_obj, to_disp(scope_obj), &ctx->scope_chain);
+        jsdisp_release(scope_obj);
+    }else {
+        hres = stack_push(ctx, except_val);
+        if(FAILED(hres))
+            return hres;
 
-    TRACE("\n");
+        hres = stack_push(ctx, jsval_bool(FALSE));
+    }
 
-    return assign_oper_eval(ctx, expr->expression1, expr->expression2, mod_eval, ei, ret);
+    return hres;
 }
 
-/* ECMA-262 3rd Edition    11.13.2 */
-HRESULT assign_and_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+static HRESULT enter_bytecode(script_ctx_t *ctx, bytecode_t *code, function_code_t *func, jsval_t *ret)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    exec_ctx_t *exec_ctx = ctx->exec_ctx;
+    except_frame_t *prev_except_frame;
+    function_code_t *prev_func;
+    unsigned prev_ip, prev_top;
+    scope_chain_t *prev_scope;
+    bytecode_t *prev_code;
+    jsop_t op;
+    HRESULT hres = S_OK;
 
     TRACE("\n");
 
-    return assign_oper_eval(ctx, expr->expression1, expr->expression2, bitand_eval, ei, ret);
-}
+    prev_top = exec_ctx->top;
+    prev_scope = exec_ctx->scope_chain;
+    prev_except_frame = exec_ctx->except_frame;
+    prev_ip = exec_ctx->ip;
+    prev_code = exec_ctx->code;
+    prev_func = exec_ctx->func_code;
+    exec_ctx->ip = func->instr_off;
+    exec_ctx->except_frame = NULL;
+    exec_ctx->code = code;
+    exec_ctx->func_code = func;
 
-/* ECMA-262 3rd Edition    11.13.2 */
-HRESULT assign_or_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
-{
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    while(exec_ctx->ip != -1) {
+        op = code->instrs[exec_ctx->ip].op;
+        hres = op_funcs[op](exec_ctx);
+        if(FAILED(hres)) {
+            TRACE("EXCEPTION %08x\n", hres);
 
-    TRACE("\n");
+            if(!exec_ctx->except_frame)
+                break;
+
+            hres = unwind_exception(exec_ctx);
+            if(FAILED(hres))
+                break;
+        }else {
+            exec_ctx->ip += op_move[op];
+        }
+    }
+
+    exec_ctx->ip = prev_ip;
+    exec_ctx->except_frame = prev_except_frame;
+    exec_ctx->code = prev_code;
+    exec_ctx->func_code = prev_func;
+
+    if(FAILED(hres)) {
+        while(exec_ctx->scope_chain != prev_scope)
+            scope_pop(&exec_ctx->scope_chain);
+        stack_popn(exec_ctx, exec_ctx->top-prev_top);
+        return hres;
+    }
 
-    return assign_oper_eval(ctx, expr->expression1, expr->expression2, bitor_eval, ei, ret);
+    assert(exec_ctx->top == prev_top+1 || exec_ctx->top == prev_top);
+    assert(exec_ctx->scope_chain == prev_scope);
+    assert(exec_ctx->top == prev_top);
+
+    *ret = exec_ctx->ret;
+    exec_ctx->ret = jsval_undefined();
+    return S_OK;
 }
 
-/* ECMA-262 3rd Edition    11.13.2 */
-HRESULT assign_xor_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret)
+HRESULT exec_source(exec_ctx_t *ctx, bytecode_t *code, function_code_t *func, BOOL from_eval, jsval_t *ret)
 {
-    binary_expression_t *expr = (binary_expression_t*)_expr;
+    exec_ctx_t *prev_ctx;
+    jsval_t val;
+    unsigned i;
+    HRESULT hres = S_OK;
 
-    TRACE("\n");
+    for(i = 0; i < func->func_cnt; i++) {
+        jsdisp_t *func_obj;
+
+        if(!func->funcs[i].name)
+            continue;
+
+        hres = create_source_function(ctx->script, code, func->funcs+i, ctx->scope_chain, &func_obj);
+        if(FAILED(hres))
+            return hres;
 
-    return assign_oper_eval(ctx, expr->expression1, expr->expression2, xor_eval, ei, ret);
+        hres = jsdisp_propput_name(ctx->var_disp, func->funcs[i].name, jsval_obj(func_obj));
+        jsdisp_release(func_obj);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    for(i=0; i < func->var_cnt; i++) {
+        if(!ctx->is_global || !lookup_global_members(ctx->script, func->variables[i], NULL)) {
+            DISPID id = 0;
+
+            hres = jsdisp_get_id(ctx->var_disp, func->variables[i], fdexNameEnsure, &id);
+            if(FAILED(hres))
+                return hres;
+        }
+    }
+
+    prev_ctx = ctx->script->exec_ctx;
+    ctx->script->exec_ctx = ctx;
+
+    hres = enter_bytecode(ctx->script, code, func, &val);
+    assert(ctx->script->exec_ctx == ctx);
+    ctx->script->exec_ctx = prev_ctx;
+    if(FAILED(hres))
+        return hres;
+
+    if(ret)
+        *ret = val;
+    else
+        jsval_release(val);
+    return S_OK;
 }
index 0bcabf6..618c6f0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Jacek Caban for CodeWeavers
+ * Copyright 2008,2011 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
  */
 
 typedef struct _source_elements_t source_elements_t;
-typedef struct _function_expression_t function_expression_t;
-
-typedef struct _function_declaration_t {
-    function_expression_t *expr;
-
-    struct _function_declaration_t *next;
-} function_declaration_t;
-
-typedef struct _var_list_t {
-    const WCHAR *identifier;
-
-    struct _var_list_t *next;
-} var_list_t;
-
-typedef struct _func_stack {
-    function_declaration_t *func_head;
-    function_declaration_t *func_tail;
-    var_list_t *var_head;
-    var_list_t *var_tail;
-
-    struct _func_stack *next;
-} func_stack_t;
-
-typedef struct _parser_ctx_t {
-    LONG ref;
+typedef struct _expression_t expression_t;
+typedef struct _statement_t statement_t;
 
-    WCHAR *begin;
+typedef struct {
+    const WCHAR *begin;
     const WCHAR *end;
     const WCHAR *ptr;
 
     script_ctx_t *script;
     source_elements_t *source;
     BOOL nl;
+    BOOL implicit_nl_semicolon;
     BOOL is_html;
     BOOL lexer_error;
     HRESULT hres;
 
-    jsheap_t heap;
+    heap_pool_t heap;
+} parser_ctx_t;
 
-    func_stack_t *func_stack;
+#define OP_LIST                            \
+    X(add,        1, 0,0)                  \
+    X(and,        1, 0,0)                  \
+    X(array,      1, 0,0)                  \
+    X(assign,     1, 0,0)                  \
+    X(assign_call,1, ARG_UINT,   0)       \
+    X(bool,       1, ARG_INT,    0)        \
+    X(bneg,       1, 0,0)                  \
+    X(call,       1, ARG_UINT,   ARG_UINT) \
+    X(call_member,1, ARG_UINT,   ARG_UINT) \
+    X(carray,     1, ARG_UINT,   0)        \
+    X(case,       0, ARG_ADDR,   0)        \
+    X(cnd_nz,     0, ARG_ADDR,   0)        \
+    X(cnd_z,      0, ARG_ADDR,   0)        \
+    X(delete,     1, 0,0)                  \
+    X(delete_ident,1,ARG_BSTR,   0)        \
+    X(div,        1, 0,0)                  \
+    X(double,     1, ARG_DBL,    0)        \
+    X(end_finally,1, 0,0)                  \
+    X(eq,         1, 0,0)                  \
+    X(eq2,        1, 0,0)                  \
+    X(forin,      0, ARG_ADDR,   0)        \
+    X(func,       1, ARG_UINT,   0)        \
+    X(gt,         1, 0,0)                  \
+    X(gteq,       1, 0,0)                  \
+    X(ident,      1, ARG_BSTR,   0)        \
+    X(identid,    1, ARG_BSTR,   ARG_INT)  \
+    X(in,         1, 0,0)                  \
+    X(instanceof, 1, 0,0)                  \
+    X(int,        1, ARG_INT,    0)        \
+    X(jmp,        0, ARG_ADDR,   0)        \
+    X(jmp_z,      0, ARG_ADDR,   0)        \
+    X(lshift,     1, 0,0)                  \
+    X(lt,         1, 0,0)                  \
+    X(lteq,       1, 0,0)                  \
+    X(member,     1, ARG_BSTR,   0)        \
+    X(memberid,   1, ARG_UINT,   0)        \
+    X(minus,      1, 0,0)                  \
+    X(mod,        1, 0,0)                  \
+    X(mul,        1, 0,0)                  \
+    X(neg,        1, 0,0)                  \
+    X(neq,        1, 0,0)                  \
+    X(neq2,       1, 0,0)                  \
+    X(new,        1, ARG_UINT,   0)        \
+    X(new_obj,    1, 0,0)                  \
+    X(null,       1, 0,0)                  \
+    X(obj_prop,   1, ARG_BSTR,   0)        \
+    X(or,         1, 0,0)                  \
+    X(pop,        1, ARG_UINT,   0)        \
+    X(pop_except, 1, 0,0)                  \
+    X(pop_scope,  1, 0,0)                  \
+    X(postinc,    1, ARG_INT,    0)        \
+    X(preinc,     1, ARG_INT,    0)        \
+    X(push_except,1, ARG_ADDR,   ARG_BSTR) \
+    X(push_scope, 1, 0,0)                  \
+    X(regexp,     1, ARG_STR,    ARG_UINT) \
+    X(rshift,     1, 0,0)                  \
+    X(rshift2,    1, 0,0)                  \
+    X(str,        1, ARG_STR,    0)        \
+    X(this,       1, 0,0)                  \
+    X(throw,      0, 0,0)                  \
+    X(throw_ref,  0, ARG_UINT,   0)        \
+    X(throw_type, 0, ARG_UINT,   ARG_STR)  \
+    X(tonum,      1, 0,0)                  \
+    X(typeof,     1, 0,0)                  \
+    X(typeofid,   1, 0,0)                  \
+    X(typeofident,1, 0,0)                  \
+    X(refval,     1, 0,0)                  \
+    X(ret,        0, 0,0)                  \
+    X(setret,     1, 0,0)                  \
+    X(sub,        1, 0,0)                  \
+    X(undefined,  1, 0,0)                  \
+    X(var_set,    1, ARG_BSTR,   0)        \
+    X(void,       1, 0,0)                  \
+    X(xor,        1, 0,0)
 
-    struct _parser_ctx_t *next;
-} parser_ctx_t;
+typedef enum {
+#define X(x,a,b,c) OP_##x,
+OP_LIST
+#undef X
+    OP_LAST
+} jsop_t;
+
+typedef union {
+    BSTR bstr;
+    LONG lng;
+    jsstr_t *str;
+    unsigned uint;
+} instr_arg_t;
+
+typedef enum {
+    ARG_NONE = 0,
+    ARG_ADDR,
+    ARG_BSTR,
+    ARG_DBL,
+    ARG_FUNC,
+    ARG_INT,
+    ARG_STR,
+    ARG_UINT
+} instr_arg_type_t;
+
+typedef struct {
+    jsop_t op;
+    union {
+        instr_arg_t arg[2];
+        double dbl;
+    } u;
+} instr_t;
+
+typedef struct _function_code_t {
+    BSTR name;
+    unsigned instr_off;
+
+    const WCHAR *source;
+    unsigned source_len;
+
+    unsigned func_cnt;
+    struct _function_code_t *funcs;
+
+    unsigned var_cnt;
+    BSTR *variables;
+
+    unsigned param_cnt;
+    BSTR *params;
+} function_code_t;
+
+typedef struct _bytecode_t {
+    LONG ref;
+
+    instr_t *instrs;
+    heap_pool_t heap;
+
+    function_code_t global_code;
 
-HRESULT script_parse(script_ctx_t*,const WCHAR*,const WCHAR*,parser_ctx_t**);
-void parser_release(parser_ctx_t*);
+    WCHAR *source;
 
-int parser_lex(void*,parser_ctx_t*);
+    BSTR *bstr_pool;
+    unsigned bstr_pool_size;
+    unsigned bstr_cnt;
 
-static inline void parser_addref(parser_ctx_t *ctx)
+    jsstr_t **str_pool;
+    unsigned str_pool_size;
+    unsigned str_cnt;
+
+    struct _bytecode_t *next;
+} bytecode_t;
+
+HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,const WCHAR*,BOOL,BOOL,bytecode_t**) DECLSPEC_HIDDEN;
+void release_bytecode(bytecode_t*) DECLSPEC_HIDDEN;
+
+static inline void bytecode_addref(bytecode_t *code)
 {
-    ctx->ref++;
+    code->ref++;
 }
 
+HRESULT script_parse(script_ctx_t*,const WCHAR*,const WCHAR*,BOOL,parser_ctx_t**) DECLSPEC_HIDDEN;
+void parser_release(parser_ctx_t*) DECLSPEC_HIDDEN;
+
+int parser_lex(void*,parser_ctx_t*) DECLSPEC_HIDDEN;
+
 static inline void *parser_alloc(parser_ctx_t *ctx, DWORD size)
 {
-    return jsheap_alloc(&ctx->heap, size);
+    return heap_pool_alloc(&ctx->heap, size);
 }
 
 static inline void *parser_alloc_tmp(parser_ctx_t *ctx, DWORD size)
 {
-    return jsheap_alloc(&ctx->script->tmp_heap, size);
+    return heap_pool_alloc(&ctx->script->tmp_heap, size);
 }
 
 typedef struct _scope_chain_t {
     LONG ref;
-    DispatchEx *obj;
+    jsdisp_t *jsobj;
+    IDispatch *obj;
     struct _scope_chain_t *next;
 } scope_chain_t;
 
-HRESULT scope_push(scope_chain_t*,DispatchEx*,scope_chain_t**);
-void scope_release(scope_chain_t*);
+HRESULT scope_push(scope_chain_t*,jsdisp_t*,IDispatch*,scope_chain_t**) DECLSPEC_HIDDEN;
+void scope_release(scope_chain_t*) DECLSPEC_HIDDEN;
 
 static inline void scope_addref(scope_chain_t *scope)
 {
     scope->ref++;
 }
 
+typedef struct _except_frame_t except_frame_t;
+
 struct _exec_ctx_t {
     LONG ref;
 
     parser_ctx_t *parser;
+    bytecode_t *code;
+    script_ctx_t *script;
     scope_chain_t *scope_chain;
-    DispatchEx *var_disp;
+    jsdisp_t *var_disp;
     IDispatch *this_obj;
+    function_code_t *func_code;
+    BOOL is_global;
+
+    jsval_t *stack;
+    unsigned stack_size;
+    unsigned top;
+    except_frame_t *except_frame;
+    jsval_t ret;
+
+    unsigned ip;
 };
 
 static inline void exec_addref(exec_ctx_t *ctx)
@@ -109,25 +249,12 @@ static inline void exec_addref(exec_ctx_t *ctx)
     ctx->ref++;
 }
 
-typedef enum {
-    EXECT_PROGRAM,
-    EXECT_FUNCTION,
-    EXECT_EVAL
-} exec_type_t;
-
-void exec_release(exec_ctx_t*);
-HRESULT create_exec_ctx(script_ctx_t*,IDispatch*,DispatchEx*,scope_chain_t*,exec_ctx_t**);
-HRESULT exec_source(exec_ctx_t*,parser_ctx_t*,source_elements_t*,exec_type_t,jsexcept_t*,VARIANT*);
-
-typedef struct _statement_t statement_t;
-typedef struct _expression_t expression_t;
-typedef struct _parameter_t parameter_t;
-
-HRESULT create_source_function(parser_ctx_t*,parameter_t*,source_elements_t*,scope_chain_t*,
-        const WCHAR*,DWORD,DispatchEx**);
+void exec_release(exec_ctx_t*) DECLSPEC_HIDDEN;
+HRESULT create_exec_ctx(script_ctx_t*,IDispatch*,jsdisp_t*,scope_chain_t*,BOOL,exec_ctx_t**) DECLSPEC_HIDDEN;
+HRESULT exec_source(exec_ctx_t*,bytecode_t*,function_code_t*,BOOL,jsval_t*) DECLSPEC_HIDDEN;
+HRESULT create_source_function(script_ctx_t*,bytecode_t*,function_code_t*,scope_chain_t*,jsdisp_t**) DECLSPEC_HIDDEN;
 
 typedef enum {
-    LT_INT,
     LT_DOUBLE,
     LT_STRING,
     LT_BOOL,
@@ -138,11 +265,9 @@ typedef enum {
 typedef struct {
     literal_type_t type;
     union {
-        LONG lval;
         double dval;
         const WCHAR *wstr;
-        VARIANT_BOOL bval;
-        IDispatch *disp;
+        BOOL bval;
         struct {
             const WCHAR *str;
             DWORD str_len;
@@ -151,29 +276,38 @@ typedef struct {
     } u;
 } literal_t;
 
-literal_t *parse_regexp(parser_ctx_t*);
+literal_t *parse_regexp(parser_ctx_t*) DECLSPEC_HIDDEN;
+literal_t *new_boolean_literal(parser_ctx_t*,BOOL) DECLSPEC_HIDDEN;
 
 typedef struct _variable_declaration_t {
     const WCHAR *identifier;
     expression_t *expr;
 
     struct _variable_declaration_t *next;
+    struct _variable_declaration_t *global_next; /* for compiler */
 } variable_declaration_t;
 
-typedef struct {
-    enum{
-        RT_NORMAL,
-        RT_RETURN,
-        RT_BREAK,
-        RT_CONTINUE
-    } type;
-    jsexcept_t ei;
-} return_type_t;
-
-typedef HRESULT (*statement_eval_t)(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
+typedef enum {
+    STAT_BLOCK,
+    STAT_BREAK,
+    STAT_CONTINUE,
+    STAT_EMPTY,
+    STAT_EXPR,
+    STAT_FOR,
+    STAT_FORIN,
+    STAT_IF,
+    STAT_LABEL,
+    STAT_RETURN,
+    STAT_SWITCH,
+    STAT_THROW,
+    STAT_TRY,
+    STAT_VAR,
+    STAT_WHILE,
+    STAT_WITH
+} statement_type_t;
 
 struct _statement_t {
-    statement_eval_t eval;
+    statement_type_t type;
     statement_t *next;
 };
 
@@ -265,71 +399,106 @@ typedef struct {
     statement_t *finally_statement;
 } try_statement_t;
 
-HRESULT block_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT var_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT empty_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT expression_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT if_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT while_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT for_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT forin_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT continue_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT break_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT return_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT with_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT labelled_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT switch_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT throw_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-HRESULT try_statement_eval(exec_ctx_t*,statement_t*,return_type_t*,VARIANT*);
-
 typedef struct {
     enum {
-        EXPRVAL_VARIANT,
+        EXPRVAL_JSVAL,
         EXPRVAL_IDREF,
-        EXPRVAL_NAMEREF,
         EXPRVAL_INVALID
     } type;
     union {
-        VARIANT var;
+        jsval_t val;
         struct {
             IDispatch *disp;
             DISPID id;
         } idref;
-        struct {
-            IDispatch *disp;
-            BSTR name;
-        } nameref;
-        BSTR identifier;
     } u;
 } exprval_t;
 
-typedef HRESULT (*expression_eval_t)(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
+typedef enum {
+     EXPR_COMMA,
+     EXPR_OR,
+     EXPR_AND,
+     EXPR_BOR,
+     EXPR_BXOR,
+     EXPR_BAND,
+     EXPR_INSTANCEOF,
+     EXPR_IN,
+     EXPR_ADD,
+     EXPR_SUB,
+     EXPR_MUL,
+     EXPR_DIV,
+     EXPR_MOD,
+     EXPR_DELETE,
+     EXPR_VOID,
+     EXPR_TYPEOF,
+     EXPR_MINUS,
+     EXPR_PLUS,
+     EXPR_POSTINC,
+     EXPR_POSTDEC,
+     EXPR_PREINC,
+     EXPR_PREDEC,
+     EXPR_EQ,
+     EXPR_EQEQ,
+     EXPR_NOTEQ,
+     EXPR_NOTEQEQ,
+     EXPR_LESS,
+     EXPR_LESSEQ,
+     EXPR_GREATER,
+     EXPR_GREATEREQ,
+     EXPR_BITNEG,
+     EXPR_LOGNEG,
+     EXPR_LSHIFT,
+     EXPR_RSHIFT,
+     EXPR_RRSHIFT,
+     EXPR_ASSIGN,
+     EXPR_ASSIGNLSHIFT,
+     EXPR_ASSIGNRSHIFT,
+     EXPR_ASSIGNRRSHIFT,
+     EXPR_ASSIGNADD,
+     EXPR_ASSIGNSUB,
+     EXPR_ASSIGNMUL,
+     EXPR_ASSIGNDIV,
+     EXPR_ASSIGNMOD,
+     EXPR_ASSIGNAND,
+     EXPR_ASSIGNOR,
+     EXPR_ASSIGNXOR,
+     EXPR_COND,
+     EXPR_ARRAY,
+     EXPR_MEMBER,
+     EXPR_NEW,
+     EXPR_CALL,
+     EXPR_THIS,
+     EXPR_FUNC,
+     EXPR_IDENT,
+     EXPR_ARRAYLIT,
+     EXPR_PROPVAL,
+     EXPR_LITERAL
+} expression_type_t;
 
 struct _expression_t {
-    expression_eval_t eval;
+    expression_type_t type;
 };
 
-struct _parameter_t {
+typedef struct _parameter_t {
     const WCHAR *identifier;
-
     struct _parameter_t *next;
-};
+} parameter_t;
 
 struct _source_elements_t {
     statement_t *statement;
     statement_t *statement_tail;
-    function_declaration_t *functions;
-    var_list_t *variables;
 };
 
-struct _function_expression_t {
+typedef struct _function_expression_t {
     expression_t expr;
     const WCHAR *identifier;
     parameter_t *parameter_list;
     source_elements_t *source_elements;
     const WCHAR *src_str;
     DWORD src_len;
-};
+
+    struct _function_expression_t *next; /* for compiler */
+} function_expression_t;
 
 typedef struct {
     expression_t expr;
@@ -349,12 +518,6 @@ typedef struct {
     expression_t *false_expression;
 } conditional_expression_t;
 
-typedef struct {
-    expression_t expr;
-    expression_t *member_expr;
-    expression_t *expression;
-} array_expression_t;
-
 typedef struct {
     expression_t expr;
     expression_t *expression;
@@ -407,113 +570,3 @@ typedef struct {
     expression_t expr;
     prop_val_t *property_list;
 } property_value_expression_t;
-
-typedef enum {
-     EXPR_COMMA,
-     EXPR_OR,
-     EXPR_AND,
-     EXPR_BOR,
-     EXPR_BXOR,
-     EXPR_BAND,
-     EXPR_INSTANCEOF,
-     EXPR_IN,
-     EXPR_ADD,
-     EXPR_SUB,
-     EXPR_MUL,
-     EXPR_DIV,
-     EXPR_MOD,
-     EXPR_DELETE,
-     EXPR_VOID,
-     EXPR_TYPEOF,
-     EXPR_MINUS,
-     EXPR_PLUS,
-     EXPR_POSTINC,
-     EXPR_POSTDEC,
-     EXPR_PREINC,
-     EXPR_PREDEC,
-     EXPR_EQ,
-     EXPR_EQEQ,
-     EXPR_NOTEQ,
-     EXPR_NOTEQEQ,
-     EXPR_LESS,
-     EXPR_LESSEQ,
-     EXPR_GREATER,
-     EXPR_GREATEREQ,
-     EXPR_BITNEG,
-     EXPR_LOGNEG,
-     EXPR_LSHIFT,
-     EXPR_RSHIFT,
-     EXPR_RRSHIFT,
-     EXPR_ASSIGN,
-     EXPR_ASSIGNLSHIFT,
-     EXPR_ASSIGNRSHIFT,
-     EXPR_ASSIGNRRSHIFT,
-     EXPR_ASSIGNADD,
-     EXPR_ASSIGNSUB,
-     EXPR_ASSIGNMUL,
-     EXPR_ASSIGNDIV,
-     EXPR_ASSIGNMOD,
-     EXPR_ASSIGNAND,
-     EXPR_ASSIGNOR,
-     EXPR_ASSIGNXOR
-} expression_type_t;
-
-HRESULT function_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT conditional_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT array_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT member_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT new_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT call_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT this_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT identifier_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT literal_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT array_literal_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT property_value_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-
-HRESULT comma_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT logical_or_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT logical_and_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT binary_or_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT binary_xor_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT binary_and_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT instanceof_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT in_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT add_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT sub_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT mul_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT div_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT mod_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT delete_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT void_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT typeof_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT minus_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT plus_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT post_increment_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT post_decrement_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT pre_increment_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT pre_decrement_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT equal_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT equal2_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT not_equal_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT not_equal2_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT less_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT lesseq_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT greater_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT greatereq_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT binary_negation_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT logical_negation_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT left_shift_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT right_shift_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT right2_shift_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_lshift_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_rshift_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_rrshift_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_add_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_sub_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_mul_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_div_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_mod_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_and_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_or_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
-HRESULT assign_xor_expression_eval(exec_ctx_t*,expression_t*,DWORD,jsexcept_t*,exprval_t*);
index 8b7a90d..34c26fe 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 
-typedef struct {
-    DispatchEx dispex;
-
-    VARIANT number;
-    VARIANT description;
-    VARIANT message;
-} ErrorInstance;
-
 static const WCHAR descriptionW[] = {'d','e','s','c','r','i','p','t','i','o','n',0};
 static const WCHAR messageW[] = {'m','e','s','s','a','g','e',0};
 static const WCHAR nameW[] = {'n','a','m','e',0};
 static const WCHAR numberW[] = {'n','u','m','b','e','r',0};
 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
 
-static inline ErrorInstance *error_from_vdisp(vdisp_t *vdisp)
-{
-    return (ErrorInstance*)vdisp->u.jsdisp;
-}
-
-static inline ErrorInstance *error_this(vdisp_t *jsthis)
-{
-    return is_vclass(jsthis, JSCLASS_ERROR) ? error_from_vdisp(jsthis) : NULL;
-}
-
-static HRESULT Error_number(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    ErrorInstance *This = error_from_vdisp(jsthis);
-
-    TRACE("\n");
-
-    switch(flags) {
-    case DISPATCH_PROPERTYGET:
-        return VariantCopy(retv, &This->number);
-    case DISPATCH_PROPERTYPUT:
-        return VariantCopy(&This->number, get_arg(dp, 0));
-    default:
-        FIXME("unimplemented flags %x\n", flags);
-        return E_NOTIMPL;
-    }
-}
-
-static HRESULT Error_description(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    ErrorInstance *This = error_from_vdisp(jsthis);
-
-    TRACE("\n");
-
-    switch(flags) {
-    case DISPATCH_PROPERTYGET:
-        return VariantCopy(retv, &This->description);
-    case DISPATCH_PROPERTYPUT:
-        return VariantCopy(&This->description, get_arg(dp, 0));
-    default:
-        FIXME("unimplemented flags %x\n", flags);
-        return E_NOTIMPL;
-    }
-}
-
-/* ECMA-262 3rd Edition    15.11.4.3 */
-static HRESULT Error_message(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    ErrorInstance *This = error_from_vdisp(jsthis);
-
-    TRACE("\n");
-
-    switch(flags) {
-    case DISPATCH_PROPERTYGET:
-        return VariantCopy(retv, &This->message);
-    case DISPATCH_PROPERTYPUT:
-        return VariantCopy(&This->message, get_arg(dp, 0));
-    default:
-        FIXME("unimplemented flags %x\n", flags);
-        return E_NOTIMPL;
-    }
-}
-
 /* ECMA-262 3rd Edition    15.11.4.4 */
-static HRESULT Error_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Error_toString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags,
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
-    ErrorInstance *error;
-    BSTR name, msg = NULL, ret = NULL;
-    VARIANT v;
+    jsdisp_t *jsthis;
+    jsstr_t *name = NULL, *msg = NULL, *ret = NULL;
+    jsval_t v;
     HRESULT hres;
 
-    static const WCHAR str[] = {'[','o','b','j','e','c','t',' ','E','r','r','o','r',']',0};
+    static const WCHAR object_errorW[] = {'[','o','b','j','e','c','t',' ','E','r','r','o','r',']',0};
 
     TRACE("\n");
 
-    error = error_this(jsthis);
-    if(ctx->version < 2 || !error) {
-        if(retv) {
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = SysAllocString(str);
-            if(!V_BSTR(retv))
+    jsthis = get_jsdisp(vthis);
+    if(!jsthis || ctx->version < 2) {
+        if(r) {
+            jsstr_t *str;
+
+            str = jsstr_alloc(object_errorW);
+            if(!str)
                 return E_OUTOFMEMORY;
+            *r = jsval_string(str);
         }
         return S_OK;
     }
 
-    hres = jsdisp_propget_name(&error->dispex, nameW, &v, ei, caller);
+    hres = jsdisp_propget_name(jsthis, nameW, &v);
     if(FAILED(hres))
         return hres;
 
-    hres = to_string(ctx, &v, ei, &name);
-    VariantClear(&v);
-    if(FAILED(hres))
-        return hres;
+    if(!is_undefined(v)) {
+        hres = to_string(ctx, v, &name);
+        jsval_release(v);
+        if(FAILED(hres))
+            return hres;
+    }
 
-    if(V_VT(&error->message) != VT_EMPTY) {
-        hres = to_string(ctx, &error->message, ei, &msg);
-        if(SUCCEEDED(hres) && !*msg) {
-            SysFreeString(msg);
-            msg = NULL;
+    hres = jsdisp_propget_name(jsthis, messageW, &v);
+    if(SUCCEEDED(hres)) {
+        if(!is_undefined(v)) {
+            hres = to_string(ctx, v, &msg);
+            jsval_release(v);
         }
     }
 
     if(SUCCEEDED(hres)) {
-        if(msg) {
-            DWORD name_len, msg_len;
-
-            name_len = SysStringLen(name);
-            msg_len = SysStringLen(msg);
+        unsigned name_len = name ? jsstr_length(name) : 0;
+        unsigned msg_len = msg ? jsstr_length(msg) : 0;
 
-            ret = SysAllocStringLen(NULL, name_len + msg_len + 2);
+        if(name_len && msg_len) {
+            ret = jsstr_alloc_buf(name_len + msg_len + 2);
             if(ret) {
-                memcpy(ret, name, name_len*sizeof(WCHAR));
-                ret[name_len] = ':';
-                ret[name_len+1] = ' ';
-                memcpy(ret+name_len+2, msg, msg_len*sizeof(WCHAR));
+                jsstr_flush(name, ret->str);
+                ret->str[name_len] = ':';
+                ret->str[name_len+1] = ' ';
+                jsstr_flush(msg, ret->str+name_len+2);
             }
-        }else {
+        }else if(name_len) {
             ret = name;
             name = NULL;
+        }else if(msg_len) {
+            ret = msg;
+            msg = NULL;
+        }else {
+            ret = jsstr_alloc(object_errorW);
         }
     }
 
-    SysFreeString(msg);
-    SysFreeString(name);
+    if(msg)
+        jsstr_release(msg);
+    if(name)
+        jsstr_release(name);
     if(FAILED(hres))
         return hres;
     if(!ret)
         return E_OUTOFMEMORY;
 
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
-    }else {
-        SysFreeString(ret);
-    }
-
+    if(r)
+        *r = jsval_string(ret);
+    else
+        jsstr_release(ret);
     return S_OK;
 }
 
 static HRESULT Error_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     TRACE("\n");
 
     switch(flags) {
     case INVOKE_FUNC:
-        return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
+        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
     default:
         FIXME("unimplemented flags %x\n", flags);
         return E_NOTIMPL;
@@ -199,20 +132,7 @@ static HRESULT Error_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
     return S_OK;
 }
 
-static void Error_destructor(DispatchEx *dispex)
-{
-    ErrorInstance *This = (ErrorInstance*)dispex;
-
-    VariantClear(&This->number);
-    VariantClear(&This->description);
-    VariantClear(&This->message);
-    heap_free(This);
-}
-
 static const builtin_prop_t Error_props[] = {
-    {descriptionW,              Error_description,                  0},
-    {messageW,                  Error_message,                      0},
-    {numberW,                   Error_number,                       0},
     {toStringW,                 Error_toString,                     PROPF_METHOD}
 };
 
@@ -221,39 +141,33 @@ static const builtin_info_t Error_info = {
     {NULL, Error_value, 0},
     sizeof(Error_props)/sizeof(*Error_props),
     Error_props,
-    Error_destructor,
+    NULL,
     NULL
 };
 
-static const builtin_prop_t ErrorInst_props[] = {
-    {descriptionW,              Error_description,                  0},
-    {messageW,                  Error_message,                      0},
-    {numberW,                   Error_number,                       0},
-};
-
 static const builtin_info_t ErrorInst_info = {
     JSCLASS_ERROR,
     {NULL, Error_value, 0},
-    sizeof(ErrorInst_props)/sizeof(*ErrorInst_props),
-    ErrorInst_props,
-    Error_destructor,
+    0,
+    NULL,
+    NULL,
     NULL
 };
 
-static HRESULT alloc_error(script_ctx_t *ctx, DispatchEx *prototype,
-        DispatchEx *constr, ErrorInstance **ret)
+static HRESULT alloc_error(script_ctx_t *ctx, jsdisp_t *prototype,
+        jsdisp_t *constr, jsdisp_t **ret)
 {
-    ErrorInstance *err;
+    jsdisp_t *err;
     HRESULT hres;
 
-    err = heap_alloc_zero(sizeof(ErrorInstance));
+    err = heap_alloc_zero(sizeof(*err));
     if(!err)
         return E_OUTOFMEMORY;
 
     if(prototype)
-        hres = init_dispex(&err->dispex, ctx, &Error_info, prototype);
+        hres = init_dispex(err, ctx, &Error_info, prototype);
     else
-        hres = init_dispex_from_constr(&err->dispex, ctx, &ErrorInst_info,
+        hres = init_dispex_from_constr(err, ctx, &ErrorInst_info,
             constr ? constr : ctx->error_constr);
     if(FAILED(hres)) {
         heap_free(err);
@@ -264,149 +178,143 @@ static HRESULT alloc_error(script_ctx_t *ctx, DispatchEx *prototype,
     return S_OK;
 }
 
-static HRESULT create_error(script_ctx_t *ctx, DispatchEx *constr,
-        const UINT *number, const WCHAR *msg, DispatchEx **ret)
+static HRESULT create_error(script_ctx_t *ctx, jsdisp_t *constr,
+        UINT number, jsstr_t *msg, jsdisp_t **ret)
 {
-    ErrorInstance *err;
+    jsdisp_t *err;
     HRESULT hres;
 
     hres = alloc_error(ctx, NULL, constr, &err);
     if(FAILED(hres))
         return hres;
 
-    if(number) {
-        V_VT(&err->number) = VT_I4;
-        V_I4(&err->number) = *number;
+    hres = jsdisp_propput_dontenum(err, numberW, jsval_number((INT)number));
+    if(FAILED(hres)) {
+        jsdisp_release(err);
+        return hres;
     }
 
-    V_VT(&err->message) = VT_BSTR;
-    if(msg) V_BSTR(&err->message) = SysAllocString(msg);
-    else V_BSTR(&err->message) = SysAllocStringLen(NULL, 0);
-
-    VariantCopy(&err->description, &err->message);
-
-    if(!V_BSTR(&err->message)) {
-        heap_free(err);
-        return E_OUTOFMEMORY;
+    hres = jsdisp_propput_name(err, messageW, jsval_string(msg));
+    if(SUCCEEDED(hres))
+        hres = jsdisp_propput_dontenum(err, descriptionW, jsval_string(msg));
+    if(FAILED(hres)) {
+        jsdisp_release(err);
+        return hres;
     }
 
-    *ret = &err->dispex;
+    *ret = err;
     return S_OK;
 }
 
-static HRESULT error_constr(script_ctx_t *ctx, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, DispatchEx *constr) {
-    DispatchEx *err;
-    VARIANT numv;
-    UINT num;
-    BSTR msg = NULL;
+static HRESULT error_constr(script_ctx_t *ctx, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r, jsdisp_t *constr) {
+    jsdisp_t *err;
+    UINT num = 0;
+    jsstr_t *msg = NULL;
     HRESULT hres;
 
-    V_VT(&numv) = VT_NULL;
-
-    if(arg_cnt(dp)) {
-        hres = to_number(ctx, get_arg(dp, 0), ei, &numv);
-        if(FAILED(hres) || (V_VT(&numv)==VT_R8 && isnan(V_R8(&numv))))
-            hres = to_string(ctx, get_arg(dp, 0), ei, &msg);
-        else if(V_VT(&numv) == VT_I4)
-            num = V_I4(&numv);
-        else
-            num = V_R8(&numv);
+    if(argc) {
+        double n;
 
+        hres = to_number(ctx, argv[0], &n);
+        if(FAILED(hres)) /* FIXME: really? */
+            n = NAN;
+        if(isnan(n))
+            hres = to_string(ctx, argv[0], &msg);
         if(FAILED(hres))
             return hres;
+        num = n;
     }
 
-    if(arg_cnt(dp)>1 && !msg) {
-        hres = to_string(ctx, get_arg(dp, 1), ei, &msg);
-        if(FAILED(hres))
-            return hres;
+    if(!msg) {
+        if(argc > 1) {
+            hres = to_string(ctx, argv[1], &msg);
+            if(FAILED(hres))
+                return hres;
+        }else {
+            msg = jsstr_empty();
+        }
     }
 
     switch(flags) {
     case INVOKE_FUNC:
     case DISPATCH_CONSTRUCT:
-        if(V_VT(&numv) == VT_NULL)
-            hres = create_error(ctx, constr, NULL, msg, &err);
-        else
-            hres = create_error(ctx, constr, &num, msg, &err);
-        SysFreeString(msg);
-
+        hres = create_error(ctx, constr, num, msg, &err);
+        jsstr_release(msg);
         if(FAILED(hres))
             return hres;
 
-        if(retv) {
-            V_VT(retv) = VT_DISPATCH;
-            V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(err);
-        }
+        if(r)
+            *r = jsval_obj(err);
         else
             jsdisp_release(err);
-
         return S_OK;
 
     default:
+        if(msg)
+            jsstr_release(msg);
         FIXME("unimplemented flags %x\n", flags);
         return E_NOTIMPL;
     }
 }
 
 static HRESULT ErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     TRACE("\n");
-    return error_constr(ctx, flags, dp, retv, ei, ctx->error_constr);
+    return error_constr(ctx, flags, argc, argv, r, ctx->error_constr);
 }
 
 static HRESULT EvalErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     TRACE("\n");
-    return error_constr(ctx, flags, dp, retv, ei, ctx->eval_error_constr);
+    return error_constr(ctx, flags, argc, argv, r, ctx->eval_error_constr);
 }
 
 static HRESULT RangeErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     TRACE("\n");
-    return error_constr(ctx, flags, dp, retv, ei, ctx->range_error_constr);
+    return error_constr(ctx, flags, argc, argv, r, ctx->range_error_constr);
 }
 
 static HRESULT ReferenceErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     TRACE("\n");
-    return error_constr(ctx, flags, dp, retv, ei, ctx->reference_error_constr);
+    return error_constr(ctx, flags, argc, argv, r, ctx->reference_error_constr);
 }
 
 static HRESULT RegExpErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     TRACE("\n");
-    return error_constr(ctx, flags, dp, retv, ei, ctx->regexp_error_constr);
+    return error_constr(ctx, flags, argc, argv, r, ctx->regexp_error_constr);
 }
 
 static HRESULT SyntaxErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     TRACE("\n");
-    return error_constr(ctx, flags, dp, retv, ei, ctx->syntax_error_constr);
+    return error_constr(ctx, flags, argc, argv, r, ctx->syntax_error_constr);
 }
 
 static HRESULT TypeErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     TRACE("\n");
-    return error_constr(ctx, flags, dp, retv, ei, ctx->type_error_constr);
+    return error_constr(ctx, flags, argc, argv, r, ctx->type_error_constr);
 }
 
 static HRESULT URIErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     TRACE("\n");
-    return error_constr(ctx, flags, dp, retv, ei, ctx->uri_error_constr);
+    return error_constr(ctx, flags, argc, argv, r, ctx->uri_error_constr);
 }
 
-HRESULT init_error_constr(script_ctx_t *ctx, DispatchEx *object_prototype)
+HRESULT init_error_constr(script_ctx_t *ctx, jsdisp_t *object_prototype)
 {
     static const WCHAR ErrorW[] = {'E','r','r','o','r',0};
     static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0};
@@ -418,7 +326,7 @@ HRESULT init_error_constr(script_ctx_t *ctx, DispatchEx *object_prototype)
     static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0};
     static const WCHAR *names[] = {ErrorW, EvalErrorW, RangeErrorW,
         ReferenceErrorW, RegExpErrorW, SyntaxErrorW, TypeErrorW, URIErrorW};
-    DispatchEx **constr_addr[] = {&ctx->error_constr, &ctx->eval_error_constr,
+    jsdisp_t **constr_addr[] = {&ctx->error_constr, &ctx->eval_error_constr,
         &ctx->range_error_constr, &ctx->reference_error_constr, &ctx->regexp_error_constr,
         &ctx->syntax_error_constr, &ctx->type_error_constr,
         &ctx->uri_error_constr};
@@ -426,9 +334,9 @@ HRESULT init_error_constr(script_ctx_t *ctx, DispatchEx *object_prototype)
         RangeErrorConstr_value, ReferenceErrorConstr_value, RegExpErrorConstr_value,
         SyntaxErrorConstr_value, TypeErrorConstr_value, URIErrorConstr_value};
 
-    ErrorInstance *err;
-    INT i;
-    VARIANT v;
+    jsdisp_t *err;
+    unsigned int i;
+    jsstr_t *str;
     HRESULT hres;
 
     for(i=0; i < sizeof(names)/sizeof(names[0]); i++) {
@@ -436,21 +344,19 @@ HRESULT init_error_constr(script_ctx_t *ctx, DispatchEx *object_prototype)
         if(FAILED(hres))
             return hres;
 
-        V_VT(&v) = VT_BSTR;
-        V_BSTR(&v) = SysAllocString(names[i]);
-        if(!V_BSTR(&v)) {
-            jsdisp_release(&err->dispex);
+        str = jsstr_alloc(names[i]);
+        if(!str) {
+            jsdisp_release(err);
             return E_OUTOFMEMORY;
         }
 
-        hres = jsdisp_propput_name(&err->dispex, nameW, &v, NULL/*FIXME*/, NULL/*FIXME*/);
-
+        hres = jsdisp_propput_dontenum(err, nameW, jsval_string(str));
+        jsstr_release(str);
         if(SUCCEEDED(hres))
-            hres = create_builtin_function(ctx, constr_val[i], names[i], NULL,
-                    PROPF_CONSTR|1, &err->dispex, constr_addr[i]);
+            hres = create_builtin_constructor(ctx, constr_val[i], names[i], NULL,
+                    PROPF_CONSTR|1, err, constr_addr[i]);
 
-        jsdisp_release(&err->dispex);
-        VariantClear(&v);
+        jsdisp_release(err);
         if(FAILED(hres))
             return hres;
     }
@@ -458,14 +364,18 @@ HRESULT init_error_constr(script_ctx_t *ctx, DispatchEx *object_prototype)
     return S_OK;
 }
 
-static HRESULT throw_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCHAR *str, DispatchEx *constr)
+static HRESULT throw_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str, jsdisp_t *constr)
 {
     WCHAR buf[1024], *pos = NULL;
-    DispatchEx *err;
+    jsdisp_t *err;
+    jsstr_t *msg;
     HRESULT hres;
 
+    if(!is_jscript_error(error))
+        return error;
+
     buf[0] = '\0';
-    LoadStringW(jscript_hinstance, id&0xFFFF,  buf, sizeof(buf)/sizeof(WCHAR));
+    LoadStringW(jscript_hinstance, HRESULT_CODE(error),  buf, sizeof(buf)/sizeof(WCHAR));
 
     if(str) pos = strchrW(buf, '|');
     if(pos) {
@@ -476,51 +386,51 @@ static HRESULT throw_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCH
 
     WARN("%s\n", debugstr_w(buf));
 
-    id |= JSCRIPT_ERROR;
-    hres = create_error(ctx, constr, &id, buf, &err);
+    msg = jsstr_alloc(buf);
+    if(!msg)
+        return E_OUTOFMEMORY;
+
+    hres = create_error(ctx, constr, error, msg, &err);
+    jsstr_release(msg);
     if(FAILED(hres))
         return hres;
 
-    if(!ei)
-        return id;
-
-    V_VT(&ei->var) = VT_DISPATCH;
-    V_DISPATCH(&ei->var) = (IDispatch*)_IDispatchEx_(err);
-
-    return id;
+    jsval_release(ctx->ei.val);
+    ctx->ei.val = jsval_obj(err);
+    return error;
 }
 
-HRESULT throw_generic_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCHAR *str)
+HRESULT throw_generic_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
 {
-    return throw_error(ctx, ei, id, str, ctx->error_constr);
+    return throw_error(ctx, error, str, ctx->error_constr);
 }
 
-HRESULT throw_range_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCHAR *str)
+HRESULT throw_range_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
 {
-    return throw_error(ctx, ei, id, str, ctx->range_error_constr);
+    return throw_error(ctx, error, str, ctx->range_error_constr);
 }
 
-HRESULT throw_reference_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCHAR *str)
+HRESULT throw_reference_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
 {
-    return throw_error(ctx, ei, id, str, ctx->reference_error_constr);
+    return throw_error(ctx, error, str, ctx->reference_error_constr);
 }
 
-HRESULT throw_regexp_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCHAR *str)
+HRESULT throw_regexp_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
 {
-    return throw_error(ctx, ei, id, str, ctx->regexp_error_constr);
+    return throw_error(ctx, error, str, ctx->regexp_error_constr);
 }
 
-HRESULT throw_syntax_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCHAR *str)
+HRESULT throw_syntax_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
 {
-    return throw_error(ctx, ei, id, str, ctx->syntax_error_constr);
+    return throw_error(ctx, error, str, ctx->syntax_error_constr);
 }
 
-HRESULT throw_type_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCHAR *str)
+HRESULT throw_type_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
 {
-    return throw_error(ctx, ei, id, str, ctx->type_error_constr);
+    return throw_error(ctx, error, str, ctx->type_error_constr);
 }
 
-HRESULT throw_uri_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCHAR *str)
+HRESULT throw_uri_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
 {
-    return throw_error(ctx, ei, id, str, ctx->uri_error_constr);
+    return throw_error(ctx, error, str, ctx->uri_error_constr);
 }
index 0788733..fd70a39 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include <assert.h>
+
 #include "jscript.h"
 #include "engine.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 
 typedef struct {
-    DispatchEx dispex;
+    jsdisp_t dispex;
     builtin_invoke_t value_proc;
     const WCHAR *name;
     DWORD flags;
-    source_elements_t *source;
-    parameter_t *parameters;
     scope_chain_t *scope_chain;
-    parser_ctx_t *parser;
-    const WCHAR *src_str;
-    DWORD src_len;
+    bytecode_t *code;
+    function_code_t *func_code;
     DWORD length;
+    jsdisp_t *arguments;
 } FunctionInstance;
 
+typedef struct {
+    jsdisp_t jsdisp;
+    FunctionInstance *function;
+    jsdisp_t *var_obj;
+} ArgumentsInstance;
+
 static inline FunctionInstance *function_from_vdisp(vdisp_t *vdisp)
 {
     return (FunctionInstance*)vdisp->u.jsdisp;
@@ -53,135 +59,135 @@ static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
 static const WCHAR applyW[] = {'a','p','p','l','y',0};
 static const WCHAR callW[] = {'c','a','l','l',0};
+static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
 
-static IDispatch *get_this(DISPPARAMS *dp)
+static HRESULT init_parameters(jsdisp_t *var_disp, FunctionInstance *function, unsigned argc, jsval_t *argv)
 {
-    DWORD i;
-
-    for(i=0; i < dp->cNamedArgs; i++) {
-        if(dp->rgdispidNamedArgs[i] == DISPID_THIS) {
-            if(V_VT(dp->rgvarg+i) == VT_DISPATCH)
-                return V_DISPATCH(dp->rgvarg+i);
+    DWORD i=0;
+    HRESULT hres;
 
-            WARN("This is not VT_DISPATCH\n");
-            return NULL;
-        }
+    for(i=0; i < function->func_code->param_cnt; i++) {
+        hres = jsdisp_propput_name(var_disp, function->func_code->params[i],
+                i < argc ? argv[i] : jsval_undefined());
+        if(FAILED(hres))
+            return hres;
     }
 
-    TRACE("no this passed\n");
-    return NULL;
+    return S_OK;
 }
 
-static HRESULT init_parameters(DispatchEx *var_disp, FunctionInstance *function, DISPPARAMS *dp,
-        jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    parameter_t *param;
-    VARIANT var_empty;
-    DWORD cargs, i=0;
-    HRESULT hres;
+    FIXME("\n");
+    return E_NOTIMPL;
+}
 
-    V_VT(&var_empty) = VT_EMPTY;
-    cargs = arg_cnt(dp);
+static void Arguments_destructor(jsdisp_t *jsdisp)
+{
+    ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
 
-    for(param = function->parameters; param; param = param->next) {
-        hres = jsdisp_propput_name(var_disp, param->identifier,
-                i < cargs ? get_arg(dp,i) : &var_empty, ei, caller);
-        if(FAILED(hres))
-            return hres;
+    jsdisp_release(&arguments->function->dispex);
+    jsdisp_release(arguments->var_obj);
+    heap_free(arguments);
+}
 
-        i++;
-    }
+static unsigned Arguments_idx_length(jsdisp_t *jsdisp)
+{
+    ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
+    return arguments->function->length;
+}
 
-    return S_OK;
+static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *res)
+{
+    ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
+
+    TRACE("%p[%u]\n", arguments, idx);
+
+    /* FIXME: Accessing by name won't work for duplicated argument names */
+    return jsdisp_propget_name(arguments->var_obj, arguments->function->func_code->params[idx], res);
 }
 
-static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
+
+    TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val));
+
+    /* FIXME: Accessing by name won't work for duplicated argument names */
+    return jsdisp_propput_name(arguments->var_obj, arguments->function->func_code->params[idx], val);
 }
 
 static const builtin_info_t Arguments_info = {
     JSCLASS_ARGUMENTS,
     {NULL, Arguments_value, 0},
     0, NULL,
+    Arguments_destructor,
     NULL,
-    NULL
+    Arguments_idx_length,
+    Arguments_idx_get,
+    Arguments_idx_put
 };
 
-static HRESULT create_arguments(script_ctx_t *ctx, IDispatch *calee, DISPPARAMS *dp,
-        jsexcept_t *ei, IServiceProvider *caller, DispatchEx **ret)
+static HRESULT create_arguments(script_ctx_t *ctx, FunctionInstance *calee, jsdisp_t *var_obj,
+        unsigned argc, jsval_t *argv, jsdisp_t **ret)
 {
-    DispatchEx *args;
-    VARIANT var;
-    DWORD i;
+    ArgumentsInstance *args;
+    unsigned i;
     HRESULT hres;
 
     static const WCHAR caleeW[] = {'c','a','l','l','e','e',0};
 
-    args = heap_alloc_zero(sizeof(DispatchEx));
+    args = heap_alloc_zero(sizeof(*args));
     if(!args)
         return E_OUTOFMEMORY;
 
-    hres = init_dispex_from_constr(args, ctx, &Arguments_info, ctx->object_constr);
+    hres = init_dispex_from_constr(&args->jsdisp, ctx, &Arguments_info, ctx->object_constr);
     if(FAILED(hres)) {
         heap_free(args);
         return hres;
     }
 
-    for(i=0; i < arg_cnt(dp); i++) {
-        hres = jsdisp_propput_idx(args, i, get_arg(dp,i), ei, caller);
+    jsdisp_addref(&calee->dispex);
+    args->function = calee;
+    args->var_obj = jsdisp_addref(var_obj);
+
+    /* Store unnamed arguments directly in arguments object */
+    for(i = calee->length; i < argc; i++) {
+        WCHAR buf[12];
+
+        static const WCHAR formatW[] = {'%','d',0};
+
+        sprintfW(buf, formatW, i);
+        hres = jsdisp_propput_dontenum(&args->jsdisp, buf, argv[i]);
         if(FAILED(hres))
             break;
     }
 
     if(SUCCEEDED(hres)) {
-        V_VT(&var) = VT_I4;
-        V_I4(&var) = arg_cnt(dp);
-        hres = jsdisp_propput_name(args, lengthW, &var, ei, caller);
-
-        if(SUCCEEDED(hres)) {
-            V_VT(&var) = VT_DISPATCH;
-            V_DISPATCH(&var) = calee;
-            hres = jsdisp_propput_name(args, caleeW, &var, ei, caller);
-        }
+        hres = jsdisp_propput_dontenum(&args->jsdisp, lengthW, jsval_number(argc));
+        if(SUCCEEDED(hres))
+            hres = jsdisp_propput_dontenum(&args->jsdisp, caleeW, jsval_disp(to_disp(&calee->dispex)));
     }
-
     if(FAILED(hres)) {
-        jsdisp_release(args);
+        jsdisp_release(&args->jsdisp);
         return hres;
     }
 
-    *ret = args;
+    *ret = &args->jsdisp;
     return S_OK;
 }
 
-static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, DISPPARAMS *dp, jsexcept_t *ei,
-                               IServiceProvider *caller, DispatchEx **ret)
+static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, unsigned argc, jsval_t *argv, jsdisp_t **ret)
 {
-    DispatchEx *var_disp, *arg_disp;
+    jsdisp_t *var_disp;
     HRESULT hres;
 
-    static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
-
     hres = create_dispex(ctx, NULL, NULL, &var_disp);
     if(FAILED(hres))
         return hres;
 
-    hres = create_arguments(ctx, (IDispatch*)_IDispatchEx_(&function->dispex),
-            dp, ei, caller, &arg_disp);
-    if(SUCCEEDED(hres)) {
-        VARIANT var;
-
-        V_VT(&var) = VT_DISPATCH;
-        V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(arg_disp);
-        hres = jsdisp_propput_name(var_disp, argumentsW, &var, ei, caller);
-        jsdisp_release(arg_disp);
-    }
-
-    if(SUCCEEDED(hres))
-        hres = init_parameters(var_disp, function, dp, ei, caller);
+    hres = init_parameters(var_disp, function, argc, argv);
     if(FAILED(hres)) {
         jsdisp_release(var_disp);
         return hres;
@@ -191,68 +197,91 @@ static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, DI
     return S_OK;
 }
 
-static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *var_disp;
+    jsdisp_t *var_disp, *arg_disp;
     exec_ctx_t *exec_ctx;
     scope_chain_t *scope;
     HRESULT hres;
 
-    if(!function->source) {
+    if(!function->func_code) {
         FIXME("no source\n");
         return E_FAIL;
     }
 
-    hres = create_var_disp(ctx, function, dp, ei, caller, &var_disp);
+    hres = create_var_disp(ctx, function, argc, argv, &var_disp);
     if(FAILED(hres))
         return hres;
 
-    hres = scope_push(function->scope_chain, var_disp, &scope);
+    hres = create_arguments(ctx, function, var_disp, argc, argv, &arg_disp);
+    if(FAILED(hres)) {
+        jsdisp_release(var_disp);
+        return hres;
+    }
+
+    hres = jsdisp_propput(var_disp, argumentsW, PROPF_DONTDELETE, jsval_obj(arg_disp));
+    if(FAILED(hres)) {
+        jsdisp_release(arg_disp);
+        jsdisp_release(var_disp);
+        return hres;
+    }
+
+    hres = scope_push(function->scope_chain, var_disp, to_disp(var_disp), &scope);
     if(SUCCEEDED(hres)) {
-        hres = create_exec_ctx(ctx, this_obj, var_disp, scope, &exec_ctx);
+        hres = create_exec_ctx(ctx, this_obj, var_disp, scope, FALSE, &exec_ctx);
         scope_release(scope);
+
+        if(SUCCEEDED(hres)) {
+            jsdisp_t *prev_args;
+
+            prev_args = function->arguments;
+            function->arguments = arg_disp;
+            hres = exec_source(exec_ctx, function->code, function->func_code, FALSE, r);
+            function->arguments = prev_args;
+
+            exec_release(exec_ctx);
+        }
     }
-    jsdisp_release(var_disp);
-    if(FAILED(hres))
-        return hres;
 
-    hres = exec_source(exec_ctx, function->parser, function->source, EXECT_FUNCTION, ei, retv);
-    exec_release(exec_ctx);
+    /* Reset arguments value to cut the reference cycle. Note that since all activation contexts have
+     * their own arguments property, it's impossible to use prototype's one during name lookup */
+    jsdisp_propput_name(var_disp, argumentsW, jsval_undefined());
 
+    jsdisp_release(arg_disp);
+    jsdisp_release(var_disp);
     return hres;
 }
 
-static HRESULT invoke_constructor(script_ctx_t *ctx, FunctionInstance *function, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT invoke_constructor(script_ctx_t *ctx, FunctionInstance *function, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *this_obj;
-    VARIANT var;
+    jsdisp_t *this_obj;
+    jsval_t var;
     HRESULT hres;
 
     hres = create_object(ctx, &function->dispex, &this_obj);
     if(FAILED(hres))
         return hres;
 
-    hres = invoke_source(ctx, function, (IDispatch*)_IDispatchEx_(this_obj), dp, &var, ei, caller);
+    hres = invoke_source(ctx, function, to_disp(this_obj), argc, argv, &var);
     if(FAILED(hres)) {
         jsdisp_release(this_obj);
         return hres;
     }
 
-    V_VT(retv) = VT_DISPATCH;
-    if(V_VT(&var) == VT_DISPATCH) {
+    if(is_object_instance(var)) {
         jsdisp_release(this_obj);
-        V_DISPATCH(retv) = V_DISPATCH(&var);
+        *r = var;
     }else {
-        VariantClear(&var);
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(this_obj);
+        jsval_release(var);
+        *r = jsval_obj(this_obj);
     }
     return S_OK;
 }
 
-static HRESULT invoke_value_proc(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_disp, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT invoke_value_proc(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_disp, WORD flags,
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     vdisp_t vthis;
     HRESULT hres;
@@ -264,24 +293,24 @@ static HRESULT invoke_value_proc(script_ctx_t *ctx, FunctionInstance *function,
     else
         set_jsdisp(&vthis, ctx->global);
 
-    hres = function->value_proc(ctx, &vthis, flags, dp, retv, ei, caller);
+    hres = function->value_proc(ctx, &vthis, flags, argc, argv, r);
 
     vdisp_release(&vthis);
     return hres;
 }
 
-static HRESULT call_function(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, DISPPARAMS *args,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT call_function(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj,
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     if(function->value_proc)
-        return invoke_value_proc(ctx, function, this_obj, DISPATCH_METHOD, args, retv, ei, caller);
+        return invoke_value_proc(ctx, function, this_obj, DISPATCH_METHOD, argc, argv, r);
 
-    return invoke_source(ctx, function, this_obj, args, retv, ei, caller);
+    return invoke_source(ctx, function, this_obj, argc, argv, r);
 }
 
-static HRESULT function_to_string(FunctionInstance *function, BSTR *ret)
+static HRESULT function_to_string(FunctionInstance *function, jsstr_t **ret)
 {
-    BSTR str;
+    jsstr_t *str;
 
     static const WCHAR native_prefixW[] = {'\n','f','u','n','c','t','i','o','n',' '};
     static const WCHAR native_suffixW[] =
@@ -291,15 +320,15 @@ static HRESULT function_to_string(FunctionInstance *function, BSTR *ret)
         DWORD name_len;
 
         name_len = strlenW(function->name);
-        str = SysAllocStringLen(NULL, sizeof(native_prefixW) + name_len*sizeof(WCHAR) + sizeof(native_suffixW));
+        str = jsstr_alloc_buf((sizeof(native_prefixW)+sizeof(native_suffixW))/sizeof(WCHAR) + name_len);
         if(!str)
             return E_OUTOFMEMORY;
 
-        memcpy(str, native_prefixW, sizeof(native_prefixW));
-        memcpy(str + sizeof(native_prefixW)/sizeof(WCHAR), function->name, name_len*sizeof(WCHAR));
-        memcpy(str + sizeof(native_prefixW)/sizeof(WCHAR) + name_len, native_suffixW, sizeof(native_suffixW));
+        memcpy(str->str, native_prefixW, sizeof(native_prefixW));
+        memcpy(str->str + sizeof(native_prefixW)/sizeof(WCHAR), function->name, name_len*sizeof(WCHAR));
+        memcpy(str->str + sizeof(native_prefixW)/sizeof(WCHAR) + name_len, native_suffixW, sizeof(native_suffixW));
     }else {
-        str = SysAllocStringLen(function->src_str, function->src_len);
+        str = jsstr_alloc_len(function->func_code->source, function->func_code->source_len);
         if(!str)
             return E_OUTOFMEMORY;
     }
@@ -308,8 +337,27 @@ static HRESULT function_to_string(FunctionInstance *function, BSTR *ret)
     return S_OK;
 }
 
-static HRESULT Function_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    FunctionInstance *function;
+
+    TRACE("func %p this %p\n", func_this, jsthis);
+
+    assert(is_class(func_this, JSCLASS_FUNCTION));
+    function = (FunctionInstance*)func_this;
+
+    if(function->value_proc)
+        return invoke_value_proc(function->dispex.ctx, function, jsthis, flags, argc, argv, r);
+
+    if(flags == DISPATCH_CONSTRUCT)
+        return invoke_constructor(function->dispex.ctx, function, argc, argv, r);
+
+    assert(flags == DISPATCH_METHOD);
+    return invoke_source(function->dispex.ctx, function, jsthis, argc, argv, r);
+}
+
+static HRESULT Function_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FunctionInstance *This = function_from_vdisp(jsthis);
 
@@ -317,8 +365,7 @@ static HRESULT Function_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, D
 
     switch(flags) {
     case DISPATCH_PROPERTYGET:
-        V_VT(retv) = VT_I4;
-        V_I4(retv) = This->length;
+        *r = jsval_number(This->length);
         break;
     default:
         FIXME("unimplemented flags %x\n", flags);
@@ -328,98 +375,91 @@ static HRESULT Function_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, D
     return S_OK;
 }
 
-static HRESULT Function_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Function_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FunctionInstance *function;
-    BSTR str;
+    jsstr_t *str;
     HRESULT hres;
 
     TRACE("\n");
 
     if(!(function = function_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
+        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
 
     hres = function_to_string(function, &str);
     if(FAILED(hres))
         return hres;
 
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = str;
-    }else {
-        SysFreeString(str);
-    }
+    if(r)
+        *r = jsval_string(str);
+    else
+        jsstr_release(str);
     return S_OK;
 }
 
-static HRESULT array_to_args(script_ctx_t *ctx, DispatchEx *arg_array, jsexcept_t *ei, IServiceProvider *caller,
-        DISPPARAMS *args)
+static HRESULT array_to_args(script_ctx_t *ctx, jsdisp_t *arg_array, unsigned *argc, jsval_t **ret)
 {
-    VARIANT var, *argv;
+    jsval_t *argv, val;
     DWORD length, i;
     HRESULT hres;
 
-    hres = jsdisp_propget_name(arg_array, lengthW, &var, ei, NULL/*FIXME*/);
+    hres = jsdisp_propget_name(arg_array, lengthW, &val);
     if(FAILED(hres))
         return hres;
 
-    hres = to_uint32(ctx, &var, ei, &length);
-    VariantClear(&var);
+    hres = to_uint32(ctx, val, &length);
+    jsval_release(val);
     if(FAILED(hres))
         return hres;
 
-    argv = heap_alloc(length * sizeof(VARIANT));
+    argv = heap_alloc(length * sizeof(*argv));
     if(!argv)
         return E_OUTOFMEMORY;
 
     for(i=0; i<length; i++) {
-        hres = jsdisp_get_idx(arg_array, i, argv+i, ei, caller);
-        if(hres == DISP_E_UNKNOWNNAME)
-            V_VT(argv+i) = VT_EMPTY;
-        else if(FAILED(hres)) {
+        hres = jsdisp_get_idx(arg_array, i, argv+i);
+        if(hres == DISP_E_UNKNOWNNAME) {
+            argv[i] = jsval_undefined();
+        }else if(FAILED(hres)) {
             while(i--)
-                VariantClear(argv+i);
+                jsval_release(argv[i]);
             heap_free(argv);
             return hres;
         }
     }
 
-    args->cArgs = length;
-    args->rgvarg = argv;
+    *argc = length;
+    *ret = argv;
     return S_OK;
 }
 
-static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
     FunctionInstance *function;
-    DISPPARAMS args = {NULL,NULL,0,0};
-    DWORD argc, i;
+    jsval_t *args = NULL;
+    unsigned i, cnt = 0;
     IDispatch *this_obj = NULL;
     HRESULT hres = S_OK;
 
     TRACE("\n");
 
     if(!(function = function_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
+        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
 
-    argc = arg_cnt(dp);
     if(argc) {
-        VARIANT *v = get_arg(dp,0);
-
-        if(V_VT(v) != VT_EMPTY && V_VT(v) != VT_NULL) {
-            hres = to_object(ctx, v, &this_obj);
+        if(!is_undefined(argv[0]) && !is_null(argv[0])) {
+            hres = to_object(ctx, argv[0], &this_obj);
             if(FAILED(hres))
                 return hres;
         }
     }
 
     if(argc >= 2) {
-        DispatchEx *arg_array = NULL;
+        jsdisp_t *arg_array = NULL;
 
-        if(V_VT(get_arg(dp,1)) == VT_DISPATCH) {
-            arg_array = iface_to_jsdisp((IUnknown*)V_DISPATCH(get_arg(dp,1)));
+        if(is_object_instance(argv[1])) {
+            arg_array = iface_to_jsdisp((IUnknown*)get_object(argv[1]));
             if(arg_array &&
                (!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS) )) {
                 jsdisp_release(arg_array);
@@ -428,7 +468,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DI
         }
 
         if(arg_array) {
-            hres = array_to_args(ctx, arg_array, ei, caller, &args);
+            hres = array_to_args(ctx, arg_array, &cnt, &args);
             jsdisp_release(arg_array);
         }else {
             FIXME("throw TypeError\n");
@@ -436,55 +476,49 @@ static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DI
         }
     }
 
-    hres = call_function(ctx, function, this_obj, &args, retv, ei, caller);
+    if(SUCCEEDED(hres))
+        hres = call_function(ctx, function, this_obj, cnt, args, r);
 
     if(this_obj)
         IDispatch_Release(this_obj);
-    for(i=0; i<args.cArgs; i++)
-        VariantClear(args.rgvarg+i);
-    heap_free(args.rgvarg);
+    for(i=0; i < cnt; i++)
+        jsval_release(args[i]);
+    heap_free(args);
     return hres;
 }
 
-static HRESULT Function_call(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT Function_call(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FunctionInstance *function;
-    DISPPARAMS args = {NULL,NULL,0,0};
     IDispatch *this_obj = NULL;
-    DWORD argc;
+    unsigned cnt = 0;
     HRESULT hres;
 
     TRACE("\n");
 
     if(!(function = function_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
+        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
 
-    argc = arg_cnt(dp);
     if(argc) {
-        VARIANT *v = get_arg(dp,0);
-
-        if(V_VT(v) != VT_EMPTY && V_VT(v) != VT_NULL) {
-            hres = to_object(ctx, v, &this_obj);
+        if(!is_undefined(argv[0]) && !is_null(argv[0])) {
+            hres = to_object(ctx, argv[0], &this_obj);
             if(FAILED(hres))
                 return hres;
         }
 
-        args.cArgs = argc-1;
+        cnt = argc-1;
     }
 
-    if(args.cArgs)
-        args.rgvarg = dp->rgvarg + dp->cArgs - args.cArgs-1;
-
-    hres = call_function(ctx, function, this_obj, &args, retv, ei, caller);
+    hres = call_function(ctx, function, this_obj, cnt, argv+1, r);
 
     if(this_obj)
         IDispatch_Release(this_obj);
     return hres;
 }
 
-HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FunctionInstance *function;
 
@@ -499,29 +533,24 @@ HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAM
 
     switch(flags) {
     case DISPATCH_METHOD:
-        if(function->value_proc)
-            return invoke_value_proc(ctx, function, get_this(dp), flags, dp, retv, ei, caller);
-
-        return invoke_source(ctx, function, get_this(dp), dp, retv, ei, caller);
+        assert(function->value_proc != NULL);
+        return invoke_value_proc(ctx, function, NULL, flags, argc, argv, r);
 
     case DISPATCH_PROPERTYGET: {
         HRESULT hres;
-        BSTR str;
+        jsstr_t *str;
 
         hres = function_to_string(function, &str);
         if(FAILED(hres))
             return hres;
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = str;
+        *r = jsval_string(str);
         break;
     }
 
     case DISPATCH_CONSTRUCT:
-        if(function->value_proc)
-            return invoke_value_proc(ctx, function, get_this(dp), flags, dp, retv, ei, caller);
-
-        return invoke_constructor(ctx, function, dp, retv, ei, caller);
+        assert(function->value_proc != NULL);
+        return invoke_value_proc(ctx, function, NULL, flags, argc, argv, r);
 
     default:
         FIXME("not implemented flags %x\n", flags);
@@ -531,12 +560,35 @@ HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAM
     return S_OK;
 }
 
-static void Function_destructor(DispatchEx *dispex)
+static HRESULT Function_arguments(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+        unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    FunctionInstance *function = (FunctionInstance*)jsthis->u.jsdisp;
+    HRESULT hres = S_OK;
+
+    TRACE("\n");
+
+    switch(flags) {
+    case DISPATCH_PROPERTYGET: {
+        *r = function->arguments ? jsval_obj(jsdisp_addref(function->arguments)) : jsval_null();
+        break;
+    }
+    case DISPATCH_PROPERTYPUT:
+        break;
+    default:
+        FIXME("unimplemented flags %x\n", flags);
+        hres = E_NOTIMPL;
+    }
+
+    return hres;
+}
+
+static void Function_destructor(jsdisp_t *dispex)
 {
     FunctionInstance *This = (FunctionInstance*)dispex;
 
-    if(This->parser)
-        parser_release(This->parser);
+    if(This->code)
+        release_bytecode(This->code);
     if(This->scope_chain)
         scope_release(This->scope_chain);
     heap_free(This);
@@ -544,6 +596,7 @@ static void Function_destructor(DispatchEx *dispex)
 
 static const builtin_prop_t Function_props[] = {
     {applyW,                 Function_apply,                 PROPF_METHOD|2},
+    {argumentsW,             Function_arguments,             0},
     {callW,                  Function_call,                  PROPF_METHOD|1},
     {lengthW,                Function_length,                0},
     {toStringW,              Function_toString,              PROPF_METHOD}
@@ -558,8 +611,22 @@ static const builtin_info_t Function_info = {
     NULL
 };
 
+static const builtin_prop_t FunctionInst_props[] = {
+    {argumentsW,             Function_arguments,             0},
+    {lengthW,                Function_length,                0}
+};
+
+static const builtin_info_t FunctionInst_info = {
+    JSCLASS_FUNCTION,
+    {NULL, Function_value, 0},
+    sizeof(FunctionInst_props)/sizeof(*FunctionInst_props),
+    FunctionInst_props,
+    Function_destructor,
+    NULL
+};
+
 static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_info, DWORD flags,
-        BOOL funcprot, DispatchEx *prototype, FunctionInstance **ret)
+        BOOL funcprot, jsdisp_t *prototype, FunctionInstance **ret)
 {
     FunctionInstance *function;
     HRESULT hres;
@@ -569,13 +636,15 @@ static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_
         return E_OUTOFMEMORY;
 
     if(funcprot)
-        hres = init_dispex(&function->dispex, ctx, &Function_info, prototype);
+        hres = init_dispex(&function->dispex, ctx, builtin_info, prototype);
     else if(builtin_info)
         hres = init_dispex_from_constr(&function->dispex, ctx, builtin_info, ctx->function_constr);
     else
-        hres = init_dispex_from_constr(&function->dispex, ctx, &Function_info, ctx->function_constr);
-    if(FAILED(hres))
+        hres = init_dispex_from_constr(&function->dispex, ctx, &FunctionInst_info, ctx->function_constr);
+    if(FAILED(hres)) {
+        heap_free(function);
         return hres;
+    }
 
     function->flags = flags;
     function->length = flags & PROPF_ARGMASK;
@@ -584,20 +653,13 @@ static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_
     return S_OK;
 }
 
-static HRESULT set_prototype(script_ctx_t *ctx, DispatchEx *dispex, DispatchEx *prototype)
+static inline HRESULT set_prototype(script_ctx_t *ctx, jsdisp_t *dispex, jsdisp_t *prototype)
 {
-    jsexcept_t jsexcept;
-    VARIANT var;
-
-    V_VT(&var) = VT_DISPATCH;
-    V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(prototype);
-    memset(&jsexcept, 0, sizeof(jsexcept));
-
-    return jsdisp_propput_name(dispex, prototypeW, &var, &jsexcept, NULL/*FIXME*/);
+    return jsdisp_propput_dontenum(dispex, prototypeW, jsval_obj(prototype));
 }
 
 HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc, const WCHAR *name,
-        const builtin_info_t *builtin_info, DWORD flags, DispatchEx *prototype, DispatchEx **ret)
+        const builtin_info_t *builtin_info, DWORD flags, jsdisp_t *prototype, jsdisp_t **ret)
 {
     FunctionInstance *function;
     HRESULT hres;
@@ -606,14 +668,8 @@ HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc,
     if(FAILED(hres))
         return hres;
 
-    if(builtin_info) {
-        VARIANT var;
-
-        V_VT(&var) = VT_I4;
-        V_I4(&var) = function->length;
-        hres = jsdisp_propput_const(&function->dispex, lengthW, &var);
-    }
-
+    if(builtin_info)
+        hres = jsdisp_propput_const(&function->dispex, lengthW, jsval_number(function->length));
     if(SUCCEEDED(hres))
         hres = set_prototype(ctx, &function->dispex, prototype);
     if(FAILED(hres)) {
@@ -628,22 +684,49 @@ HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc,
     return S_OK;
 }
 
-HRESULT create_source_function(parser_ctx_t *ctx, parameter_t *parameters, source_elements_t *source,
-        scope_chain_t *scope_chain, const WCHAR *src_str, DWORD src_len, DispatchEx **ret)
+static HRESULT set_constructor_prop(script_ctx_t *ctx, jsdisp_t *constr, jsdisp_t *prot)
+{
+    static const WCHAR constructorW[] = {'c','o','n','s','t','r','u','c','t','o','r',0};
+
+    return jsdisp_propput_dontenum(prot, constructorW, jsval_obj(constr));
+}
+
+HRESULT create_builtin_constructor(script_ctx_t *ctx, builtin_invoke_t value_proc, const WCHAR *name,
+        const builtin_info_t *builtin_info, DWORD flags, jsdisp_t *prototype, jsdisp_t **ret)
+{
+    jsdisp_t *constr;
+    HRESULT hres;
+
+    hres = create_builtin_function(ctx, value_proc, name, builtin_info, flags, prototype, &constr);
+    if(FAILED(hres))
+        return hres;
+
+    hres = set_constructor_prop(ctx, constr, prototype);
+    if(FAILED(hres)) {
+        jsdisp_release(constr);
+        return hres;
+    }
+
+    *ret = constr;
+    return S_OK;
+}
+
+HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_code_t *func_code,
+        scope_chain_t *scope_chain, jsdisp_t **ret)
 {
     FunctionInstance *function;
-    DispatchEx *prototype;
-    parameter_t *iter;
-    DWORD length = 0;
+    jsdisp_t *prototype;
     HRESULT hres;
 
-    hres = create_object(ctx->script, NULL, &prototype);
+    hres = create_object(ctx, NULL, &prototype);
     if(FAILED(hres))
         return hres;
 
-    hres = create_function(ctx->script, NULL, PROPF_CONSTR, FALSE, NULL, &function);
+    hres = create_function(ctx, NULL, PROPF_CONSTR, FALSE, NULL, &function);
     if(SUCCEEDED(hres)) {
-        hres = set_prototype(ctx->script, &function->dispex, prototype);
+        hres = set_prototype(ctx, &function->dispex, prototype);
+        if(SUCCEEDED(hres))
+            hres = set_constructor_prop(ctx, &function->dispex, prototype);
         if(FAILED(hres))
             jsdisp_release(&function->dispex);
     }
@@ -651,56 +734,46 @@ HRESULT create_source_function(parser_ctx_t *ctx, parameter_t *parameters, sourc
     if(FAILED(hres))
         return hres;
 
-    function->source = source;
-    function->parameters = parameters;
-
     if(scope_chain) {
         scope_addref(scope_chain);
         function->scope_chain = scope_chain;
     }
 
-    parser_addref(ctx);
-    function->parser = ctx;
-
-    for(iter = parameters; iter; iter = iter->next)
-        length++;
-    function->length = length;
-
-    function->src_str = src_str;
-    function->src_len = src_len;
+    bytecode_addref(code);
+    function->code = code;
+    function->func_code = func_code;
+    function->length = function->func_code->param_cnt;
 
     *ret = &function->dispex;
     return S_OK;
 }
 
-static HRESULT construct_function(script_ctx_t *ctx, DISPPARAMS *dp, jsexcept_t *ei, IDispatch **ret)
+static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *argv, IDispatch **ret)
 {
-    function_expression_t *expr;
     WCHAR *str = NULL, *ptr;
-    DWORD argc, len = 0, l;
-    parser_ctx_t *parser;
-    DispatchEx *function;
-    BSTR *params = NULL;
-    int i=0, j=0;
+    unsigned len = 0, i = 0;
+    bytecode_t *code;
+    jsdisp_t *function;
+    jsstr_t **params = NULL;
+    int j = 0;
     HRESULT hres = S_OK;
 
     static const WCHAR function_anonymousW[] = {'f','u','n','c','t','i','o','n',' ','a','n','o','n','y','m','o','u','s','('};
     static const WCHAR function_beginW[] = {')',' ','{','\n'};
     static const WCHAR function_endW[] = {'\n','}',0};
 
-    argc = arg_cnt(dp);
     if(argc) {
-        params = heap_alloc(argc*sizeof(BSTR));
+        params = heap_alloc(argc*sizeof(*params));
         if(!params)
             return E_OUTOFMEMORY;
 
         if(argc > 2)
             len = (argc-2)*2; /* separating commas */
         for(i=0; i < argc; i++) {
-            hres = to_string(ctx, get_arg(dp,i), ei, params+i);
+            hres = to_string(ctx, argv[i], params+i);
             if(FAILED(hres))
                 break;
-            len += SysStringLen(params[i]);
+            len += jsstr_length(params[i]);
         }
     }
 
@@ -712,9 +785,7 @@ static HRESULT construct_function(script_ctx_t *ctx, DISPPARAMS *dp, jsexcept_t
             ptr = str + sizeof(function_anonymousW)/sizeof(WCHAR);
             if(argc > 1) {
                 while(1) {
-                    l = SysStringLen(params[j]);
-                    memcpy(ptr, params[j], l*sizeof(WCHAR));
-                    ptr += l;
+                    ptr += jsstr_flush(params[j], ptr);
                     if(++j == argc-1)
                         break;
                     *ptr++ = ',';
@@ -723,11 +794,8 @@ static HRESULT construct_function(script_ctx_t *ctx, DISPPARAMS *dp, jsexcept_t
             }
             memcpy(ptr, function_beginW, sizeof(function_beginW));
             ptr += sizeof(function_beginW)/sizeof(WCHAR);
-            if(argc) {
-                l = SysStringLen(params[argc-1]);
-                memcpy(ptr, params[argc-1], l*sizeof(WCHAR));
-                ptr += l;
-            }
+            if(argc)
+                ptr += jsstr_flush(params[argc-1], ptr);
             memcpy(ptr, function_endW, sizeof(function_endW));
 
             TRACE("%s\n", debugstr_w(str));
@@ -736,36 +804,34 @@ static HRESULT construct_function(script_ctx_t *ctx, DISPPARAMS *dp, jsexcept_t
         }
     }
 
-    while(--i >= 0)
-        SysFreeString(params[i]);
+    while(i)
+        jsstr_release(params[--i]);
     heap_free(params);
     if(FAILED(hres))
         return hres;
 
-    hres = script_parse(ctx, str, NULL, &parser);
+    hres = compile_script(ctx, str, NULL, NULL, FALSE, FALSE, &code);
     heap_free(str);
     if(FAILED(hres))
         return hres;
 
-    if(!parser->source || !parser->source->functions || parser->source->functions->next || parser->source->variables) {
+    if(code->global_code.func_cnt != 1 || code->global_code.var_cnt) {
         ERR("Invalid parser result!\n");
-        parser_release(parser);
+        release_bytecode(code);
         return E_UNEXPECTED;
     }
-    expr = parser->source->functions->expr;
 
-    hres = create_source_function(parser, expr->parameter_list, expr->source_elements, NULL, expr->src_str,
-            expr->src_len, &function);
-    parser_release(parser);
+    hres = create_source_function(ctx, code, code->global_code.funcs, NULL, &function);
+    release_bytecode(code);
     if(FAILED(hres))
         return hres;
 
-    *ret = (IDispatch*)_IDispatchEx_(function);
+    *ret = to_disp(function);
     return S_OK;
 }
 
-static HRESULT FunctionConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT FunctionConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     HRESULT hres;
 
@@ -775,12 +841,11 @@ static HRESULT FunctionConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla
     case DISPATCH_CONSTRUCT: {
         IDispatch *ret;
 
-        hres = construct_function(ctx, dp, ei, &ret);
+        hres = construct_function(ctx, argc, argv, &ret);
         if(FAILED(hres))
             return hres;
 
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = ret;
+        *r = jsval_disp(ret);
         break;
     }
     default:
@@ -791,32 +856,34 @@ static HRESULT FunctionConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla
     return S_OK;
 }
 
-static HRESULT FunctionProt_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT FunctionProt_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-HRESULT init_function_constr(script_ctx_t *ctx, DispatchEx *object_prototype)
+HRESULT init_function_constr(script_ctx_t *ctx, jsdisp_t *object_prototype)
 {
     FunctionInstance *prot, *constr;
     HRESULT hres;
 
     static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0};
 
-    hres = create_function(ctx, NULL, PROPF_CONSTR, TRUE, object_prototype, &prot);
+    hres = create_function(ctx, &Function_info, PROPF_CONSTR, TRUE, object_prototype, &prot);
     if(FAILED(hres))
         return hres;
 
     prot->value_proc = FunctionProt_value;
     prot->name = prototypeW;
 
-    hres = create_function(ctx, NULL, PROPF_CONSTR|1, TRUE, &prot->dispex, &constr);
+    hres = create_function(ctx, &FunctionInst_info, PROPF_CONSTR|1, TRUE, &prot->dispex, &constr);
     if(SUCCEEDED(hres)) {
         constr->value_proc = FunctionConstr_value;
         constr->name = FunctionW;
         hres = set_prototype(ctx, &constr->dispex, &prot->dispex);
+        if(SUCCEEDED(hres))
+            hres = set_constructor_prop(ctx, &constr->dispex, &prot->dispex);
         if(FAILED(hres))
             jsdisp_release(&constr->dispex);
     }
index 50d6c41..a444200 100644 (file)
@@ -48,6 +48,7 @@ static const WCHAR NumberW[] = {'N','u','m','b','e','r',0};
 static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
 static const WCHAR StringW[] = {'S','t','r','i','n','g',0};
 static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
+static const WCHAR RegExpErrorW[] = {'R','e','g','E','x','p','E','r','r','o','r',0};
 static const WCHAR ActiveXObjectW[] = {'A','c','t','i','v','e','X','O','b','j','e','c','t',0};
 static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
 static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0};
@@ -99,6 +100,13 @@ static inline BOOL is_uri_unescaped(WCHAR c)
     return c < 128 && uri_char_table[c] == 2;
 }
 
+/* Check that the character is one of the 69 non-blank characters as defined by ECMA-262 B.2.1 */
+static inline BOOL is_ecma_nonblank(const WCHAR c)
+{
+    return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
+        c == '@' || c == '*' || c == '_' || c == '+' || c == '-' || c == '.' || c == '/');
+}
+
 static WCHAR int_to_char(int i)
 {
     if(i < 10)
@@ -106,241 +114,205 @@ static WCHAR int_to_char(int i)
     return 'A'+i-10;
 }
 
-static HRESULT constructor_call(DispatchEx *constr, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT constructor_call(jsdisp_t *constr, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
     if(flags != DISPATCH_PROPERTYGET)
-        return jsdisp_call_value(constr, flags, dp, retv, ei, sp);
+        return jsdisp_call_value(constr, NULL, flags, argc, argv, r);
 
-    V_VT(retv) = VT_DISPATCH;
-    V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(constr);
-    IDispatchEx_AddRef(_IDispatchEx_(constr));
+    *r = jsval_obj(jsdisp_addref(constr));
     return S_OK;
 }
 
-static HRESULT JSGlobal_NaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_Array(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    switch(flags) {
-    case DISPATCH_PROPERTYGET:
-        num_set_nan(retv);
-        break;
-
-    default:
-        FIXME("unimplemented flags %x\n", flags);
-        return E_NOTIMPL;
-    }
-
-    return S_OK;
+    return constructor_call(ctx->array_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_Infinity(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_Boolean(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    switch(flags) {
-    case DISPATCH_PROPERTYGET:
-        num_set_inf(retv, TRUE);
-        break;
-
-    default:
-        FIXME("unimplemented flags %x\n", flags);
-        return E_NOTIMPL;
-    }
-
-    return S_OK;
+    return constructor_call(ctx->bool_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_Array(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_Date(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->array_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->date_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_Boolean(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_Error(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->bool_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->error_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_Date(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_EvalError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->date_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->eval_error_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_Error(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_RangeError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->error_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->range_error_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_EvalError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_RegExpError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->eval_error_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->regexp_error_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_RangeError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_ReferenceError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->range_error_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->reference_error_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_ReferenceError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_SyntaxError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->reference_error_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->syntax_error_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_SyntaxError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_TypeError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->syntax_error_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->type_error_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_TypeError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_URIError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->type_error_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->uri_error_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_URIError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_Function(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->uri_error_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->function_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_Function(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_Number(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->function_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->number_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_Number(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_Object(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->number_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->object_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_Object(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_String(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->object_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->string_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_String(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_RegExp(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->string_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->regexp_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_RegExp(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_ActiveXObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->regexp_constr, flags, dp, retv, ei, sp);
+    return constructor_call(ctx->activex_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_ActiveXObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_VBArray(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return constructor_call(ctx->activex_constr, flags, dp, retv, ei, sp);
-}
-
-static HRESULT JSGlobal_VBArray(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    FIXME("\n");
-    return E_NOTIMPL;
+    return constructor_call(ctx->vbarray_constr, flags, argc, argv, r);
 }
 
-static HRESULT JSGlobal_Enumerator(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_Enumerator(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    BSTR ret, str;
+    jsstr_t *ret_str, *str;
     const WCHAR *ptr;
     DWORD len = 0;
+    WCHAR *ret;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) {
-            ret = SysAllocString(undefinedW);
-            if(!ret)
-                return E_OUTOFMEMORY;
-
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = ret;
-        }
-
+    if(!argc) {
+        if(r)
+            *r = jsval_string(jsstr_undefined());
         return S_OK;
     }
 
-    hres = to_string(ctx, get_arg(dp, 0), ei, &str);
+    hres = to_string(ctx, argv[0], &str);
     if(FAILED(hres))
         return hres;
 
-    for(ptr=str; *ptr; ptr++) {
+    for(ptr = str->str; *ptr; ptr++) {
         if(*ptr > 0xff)
             len += 6;
-        else if(isalnum((char)*ptr) || *ptr=='*' || *ptr=='@' || *ptr=='-'
-                || *ptr=='_' || *ptr=='+' || *ptr=='.' || *ptr=='/')
+        else if(is_ecma_nonblank(*ptr))
             len++;
         else
             len += 3;
     }
 
-    ret = SysAllocStringLen(NULL, len);
-    if(!ret) {
-        SysFreeString(str);
+    ret_str = jsstr_alloc_buf(len);
+    if(!ret_str) {
+        jsstr_release(str);
         return E_OUTOFMEMORY;
     }
 
     len = 0;
-    for(ptr=str; *ptr; ptr++) {
+    ret = ret_str->str;
+    for(ptr = str->str; *ptr; ptr++) {
         if(*ptr > 0xff) {
             ret[len++] = '%';
             ret[len++] = 'u';
@@ -349,8 +321,7 @@ static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, D
             ret[len++] = int_to_char((*ptr >> 4) & 0xf);
             ret[len++] = int_to_char(*ptr & 0xf);
         }
-        else if(isalnum((char)*ptr) || *ptr=='*' || *ptr=='@' || *ptr=='-'
-                || *ptr=='_' || *ptr=='+' || *ptr=='.' || *ptr=='/')
+        else if(is_ecma_nonblank(*ptr))
             ret[len++] = *ptr;
         else {
             ret[len++] = '%';
@@ -359,40 +330,33 @@ static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, D
         }
     }
 
-    SysFreeString(str);
+    jsstr_release(str);
 
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
-    }
+    if(r)
+        *r = jsval_string(ret_str);
     else
-        SysFreeString(ret);
-
+        jsstr_release(ret_str);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.1.2.1 */
-static HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    parser_ctx_t *parser_ctx;
-    VARIANT *arg;
+    bytecode_t *code;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv)
-            V_VT(retv) = VT_EMPTY;
+    if(!argc) {
+        if(r)
+            *r = jsval_undefined();
         return S_OK;
     }
 
-    arg = get_arg(dp, 0);
-    if(V_VT(arg) != VT_BSTR) {
-        if(retv) {
-            V_VT(retv) = VT_EMPTY;
-            return VariantCopy(retv, arg);
-        }
+    if(!is_string(argv[0])) {
+        if(r)
+            return jsval_copy(argv[0], r);
         return S_OK;
     }
 
@@ -401,69 +365,62 @@ static HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DIS
         return E_UNEXPECTED;
     }
 
-    TRACE("parsing %s\n", debugstr_w(V_BSTR(arg)));
-    hres = script_parse(ctx, V_BSTR(arg), NULL, &parser_ctx);
+    TRACE("parsing %s\n", debugstr_jsval(argv[0]));
+    hres = compile_script(ctx, get_string(argv[0])->str, NULL, NULL, TRUE, FALSE, &code);
     if(FAILED(hres)) {
-        WARN("parse (%s) failed: %08x\n", debugstr_w(V_BSTR(arg)), hres);
-        return throw_syntax_error(ctx, ei, hres, NULL);
+        WARN("parse (%s) failed: %08x\n", debugstr_jsval(argv[0]), hres);
+        return throw_syntax_error(ctx, hres, NULL);
     }
 
-    hres = exec_source(ctx->exec_ctx, parser_ctx, parser_ctx->source, EXECT_EVAL, ei, retv);
-    parser_release(parser_ctx);
-
+    hres = exec_source(ctx->exec_ctx, code, &code->global_code, TRUE, r);
+    release_bytecode(code);
     return hres;
 }
 
-static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT_BOOL ret = VARIANT_FALSE;
-    VARIANT num;
+    BOOL ret = TRUE;
+    double n;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(arg_cnt(dp)) {
-        hres = to_number(ctx, get_arg(dp,0), ei, &num);
+    if(argc) {
+        hres = to_number(ctx, argv[0], &n);
         if(FAILED(hres))
             return hres;
 
-        if(V_VT(&num) == VT_R8 && isnan(V_R8(&num)))
-            ret = VARIANT_TRUE;
-    }else {
-        ret = VARIANT_TRUE;
+        if(!isnan(n))
+            ret = FALSE;
     }
 
-    if(retv) {
-        V_VT(retv) = VT_BOOL;
-        V_BOOL(retv) = ret;
-    }
+    if(r)
+        *r = jsval_bool(ret);
     return S_OK;
 }
 
-static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT_BOOL ret = VARIANT_FALSE;
+    BOOL ret = FALSE;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(arg_cnt(dp)) {
-        VARIANT num;
+    if(argc) {
+        double n;
 
-        hres = to_number(ctx, get_arg(dp,0), ei, &num);
+        hres = to_number(ctx, argv[0], &n);
         if(FAILED(hres))
             return hres;
 
-        if(V_VT(&num) != VT_R8 || (!isinf(V_R8(&num)) && !isnan(V_R8(&num))))
-            ret = VARIANT_TRUE;
+        if(!isinf(n) && !isnan(n))
+            ret = TRUE;
     }
 
-    if(retv) {
-        V_VT(retv) = VT_BOOL;
-        V_BOOL(retv) = ret;
-    }
+    if(r)
+        *r = jsval_bool(ret);
     return S_OK;
 }
 
@@ -478,39 +435,40 @@ static INT char_to_int(WCHAR c)
     return 100;
 }
 
-static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
+    BOOL neg = FALSE, empty = TRUE;
     DOUBLE ret = 0.0;
-    INT radix=10, i;
+    INT radix=0, i;
+    jsstr_t *str;
     WCHAR *ptr;
-    BOOL neg = FALSE;
-    BSTR str;
     HRESULT hres;
 
-    if(!arg_cnt(dp)) {
-        if(retv) num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    if(arg_cnt(dp) >= 2) {
-        hres = to_int32(ctx, get_arg(dp, 1), ei, &radix);
+    if(argc >= 2) {
+        hres = to_int32(ctx, argv[1], &radix);
         if(FAILED(hres))
             return hres;
 
-        if(!radix) {
-            radix = 10;
-        }else if(radix < 2 || radix > 36) {
+        if(radix && (radix < 2 || radix > 36)) {
             WARN("radix %d out of range\n", radix);
-            return E_FAIL;
+            if(r)
+                *r = jsval_number(NAN);
+            return S_OK;
         }
     }
 
-    hres = to_string(ctx, get_arg(dp, 0), ei, &str);
+    hres = to_string(ctx, argv[0], &str);
     if(FAILED(hres))
         return hres;
 
-    for(ptr = str; isspaceW(*ptr); ptr++);
+    for(ptr = str->str; isspaceW(*ptr); ptr++);
 
     switch(*ptr) {
     case '+':
@@ -520,55 +478,64 @@ static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         neg = TRUE;
         ptr++;
         break;
-    case '0':
-        ptr++;
-        if(*ptr == 'x' || *ptr == 'X') {
-            radix = 16;
-            ptr++;
-        }
     }
 
-    while(*ptr) {
-        i = char_to_int(*ptr++);
-        if(i > radix)
-            break;
+    if(!radix) {
+        if(*ptr == '0') {
+            if(ptr[1] == 'x' || ptr[1] == 'X') {
+                radix = 16;
+                ptr += 2;
+            }else {
+                radix = 8;
+                ptr++;
+                empty = FALSE;
+            }
+        }else {
+            radix = 10;
+        }
+    }
 
-        ret = ret*radix + i;
+    i = char_to_int(*ptr++);
+    if(i < radix) {
+        do {
+            ret = ret*radix + i;
+            i = char_to_int(*ptr++);
+        }while(i < radix);
+    }else if(empty) {
+        ret = NAN;
     }
 
-    SysFreeString(str);
+    jsstr_release(str);
 
     if(neg)
         ret = -ret;
 
-    if(retv)
-        num_set_val(retv, ret);
+    if(r)
+        *r = jsval_number(ret);
     return S_OK;
 }
 
-static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     LONGLONG d = 0, hlp;
+    jsstr_t *val_str;
     int exp = 0;
-    VARIANT *arg;
     WCHAR *str;
-    BSTR val_str = NULL;
     BOOL ret_nan = TRUE, positive = TRUE;
     HRESULT hres;
 
-    if(!arg_cnt(dp)) {
-        if(retv)
-            num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    arg = get_arg(dp, 0);
-    hres = to_string(ctx, arg, ei, &val_str);
+    hres = to_string(ctx, argv[0], &val_str);
     if(FAILED(hres))
         return hres;
 
-    str = val_str;
+    str = val_str->str;
 
     while(isspaceW(*str)) str++;
 
@@ -634,16 +601,18 @@ static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag
         else exp += e;
     }
 
-    SysFreeString(val_str);
+    jsstr_release(val_str);
 
     if(ret_nan) {
-        if(retv)
-            num_set_nan(retv);
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    V_VT(retv) = VT_R8;
-    V_R8(retv) = (double)(positive?d:-d)*pow(10, exp);
+    if(!positive)
+        d = -d;
+    if(r)
+        *r = jsval_number(exp>0 ? d*pow(10, exp) : d/pow(10, -exp));
     return S_OK;
 }
 
@@ -653,34 +622,28 @@ static inline int hex_to_int(const WCHAR wch) {
     return -1;
 }
 
-static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    BSTR ret, str;
+    jsstr_t *ret_str, *str;
     const WCHAR *ptr;
     DWORD len = 0;
+    WCHAR *ret;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) {
-            ret = SysAllocString(undefinedW);
-            if(!ret)
-                return E_OUTOFMEMORY;
-
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = ret;
-        }
-
+    if(!argc) {
+        if(r)
+            *r = jsval_string(jsstr_undefined());
         return S_OK;
     }
 
-    hres = to_string(ctx, get_arg(dp, 0), ei, &str);
+    hres = to_string(ctx, argv[0], &str);
     if(FAILED(hres))
         return hres;
 
-    for(ptr=str; *ptr; ptr++) {
+    for(ptr = str->str; *ptr; ptr++) {
         if(*ptr == '%') {
             if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1)
                 ptr += 2;
@@ -692,14 +655,15 @@ static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         len++;
     }
 
-    ret = SysAllocStringLen(NULL, len);
-    if(!ret) {
-        SysFreeString(str);
+    ret_str = jsstr_alloc_buf(len);
+    if(!ret_str) {
+        jsstr_release(str);
         return E_OUTOFMEMORY;
     }
 
+    ret = ret_str->str;
     len = 0;
-    for(ptr=str; *ptr; ptr++) {
+    for(ptr = str->str; *ptr; ptr++) {
         if(*ptr == '%') {
             if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1) {
                 ret[len] = (hex_to_int(*(ptr+1))<<4) + hex_to_int(*(ptr+2));
@@ -720,110 +684,123 @@ static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         len++;
     }
 
-    SysFreeString(str);
+    jsstr_release(str);
 
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
-    }
+    if(r)
+        *r = jsval_string(ret_str);
     else
-        SysFreeString(ret);
-
+        jsstr_release(ret_str);
     return S_OK;
 }
 
-static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    static const WCHAR JScriptW[] = {'J','S','c','r','i','p','t',0};
+
+    TRACE("\n");
+
+    if(r) {
+        jsstr_t *ret;
+
+        ret = jsstr_alloc(JScriptW);
+        if(!ret)
+            return E_OUTOFMEMORY;
+
+        *r = jsval_string(ret);
+    }
+
+    return S_OK;
 }
 
-static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    TRACE("\n");
+
+    if(r)
+        *r = jsval_number(JSCRIPT_MAJOR_VERSION);
+    return S_OK;
 }
 
-static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    TRACE("\n");
+
+    if(r)
+        *r = jsval_number(JSCRIPT_MINOR_VERSION);
+    return S_OK;
 }
 
-static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    TRACE("\n");
+
+    if(r)
+        *r = jsval_number(JSCRIPT_BUILD_VERSION);
+    return S_OK;
 }
 
-static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
+    jsstr_t *str, *ret;
     const WCHAR *ptr;
     DWORD len = 0, i;
     char buf[4];
-    BSTR str, ret;
     WCHAR *rptr;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) {
-            ret = SysAllocString(undefinedW);
-            if(!ret)
-                return E_OUTOFMEMORY;
-
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = ret;
-        }
-
+    if(!argc) {
+        if(r)
+            *r = jsval_string(jsstr_undefined());
         return S_OK;
     }
 
-    hres = to_string(ctx, get_arg(dp,0), ei, &str);
+    hres = to_string(ctx, argv[0], &str);
     if(FAILED(hres))
         return hres;
 
-    for(ptr = str; *ptr; ptr++) {
+    for(ptr = str->str; *ptr; ptr++) {
         if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
             len++;
         }else {
             i = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL)*3;
             if(!i) {
-                SysFreeString(str);
-                return throw_uri_error(ctx, ei, IDS_URI_INVALID_CHAR, NULL);
+                jsstr_release(str);
+                return throw_uri_error(ctx, JS_E_INVALID_URI_CHAR, NULL);
             }
 
             len += i;
         }
     }
 
-    rptr = ret = SysAllocStringLen(NULL, len);
+    ret = jsstr_alloc_buf(len);
     if(!ret) {
-        SysFreeString(str);
+        jsstr_release(str);
         return E_OUTOFMEMORY;
     }
+    rptr = ret->str;
 
-    for(ptr = str; *ptr; ptr++) {
+    for(ptr = str->str; *ptr; ptr++) {
         if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
             *rptr++ = *ptr;
         }else {
@@ -836,29 +813,106 @@ static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
         }
     }
 
-    SysFreeString(str);
+    TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret));
+    jsstr_release(str);
 
-    TRACE("%s -> %s\n", debugstr_w(str), debugstr_w(ret));
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
-    }else {
-        SysFreeString(ret);
-    }
+    if(r)
+        *r = jsval_string(ret);
+    else
+        jsstr_release(ret);
     return S_OK;
 }
 
-static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    jsstr_t *str, *ret;
+    WCHAR *ptr;
+    int i, len = 0, val, res;
+    char buf[4];
+    WCHAR out;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    if(!argc) {
+        if(r)
+            *r = jsval_string(jsstr_undefined());
+        return S_OK;
+    }
+
+    hres = to_string(ctx, argv[0], &str);
+    if(FAILED(hres))
+        return hres;
+
+    for(ptr = str->str; *ptr; ptr++) {
+        if(*ptr != '%') {
+            len++;
+        }else {
+            res = 0;
+            for(i=0; i<4; i++) {
+                if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
+                    break;
+                val += hex_to_int(ptr[i*3+1])<<4;
+                buf[i] = val;
+
+                res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, &out, 1);
+                if(res)
+                    break;
+            }
+
+            if(!res) {
+                jsstr_release(str);
+                return throw_uri_error(ctx, JS_E_INVALID_URI_CODING, NULL);
+            }
+
+            ptr += i*3+2;
+            len++;
+        }
+    }
+
+    ret = jsstr_alloc_buf(len);
+    if(!ret) {
+        jsstr_release(str);
+        return E_OUTOFMEMORY;
+    }
+
+    len = 0;
+    for(ptr = str->str; *ptr; ptr++) {
+        if(*ptr != '%') {
+            ret->str[len] = *ptr;
+            len++;
+        }else {
+            for(i=0; i<4; i++) {
+                if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
+                    break;
+                val += hex_to_int(ptr[i*3+1])<<4;
+                buf[i] = val;
+
+                res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, ret->str+len, 1);
+                if(res)
+                    break;
+            }
+
+            ptr += i*3+2;
+            len++;
+        }
+    }
+
+    TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret));
+    jsstr_release(str);
+
+    if(r)
+        *r = jsval_string(ret);
+    else
+        jsstr_release(ret);
+    return S_OK;
 }
 
-static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    BSTR str, ret;
+    jsstr_t *str, *ret;
     char buf[4];
     const WCHAR *ptr;
     DWORD len = 0, size, i;
@@ -866,74 +920,63 @@ static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) {
-            ret = SysAllocString(undefinedW);
-            if(!ret)
-                return E_OUTOFMEMORY;
-
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = ret;
-        }
-
+    if(!argc) {
+        if(r)
+            *r = jsval_string(jsstr_undefined());
         return S_OK;
     }
 
-    hres = to_string(ctx, get_arg(dp, 0), ei, &str);
+    hres = to_string(ctx, argv[0], &str);
     if(FAILED(hres))
         return hres;
 
-    for(ptr=str; *ptr; ptr++) {
+    for(ptr = str->str; *ptr; ptr++) {
         if(is_uri_unescaped(*ptr))
             len++;
         else {
             size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL);
             if(!size) {
-                SysFreeString(str);
-                FIXME("throw Error\n");
-                return E_FAIL;
+                jsstr_release(str);
+                return throw_uri_error(ctx, JS_E_INVALID_URI_CHAR, NULL);
             }
             len += size*3;
         }
     }
 
-    ret = SysAllocStringLen(NULL, len);
+    ret = jsstr_alloc_buf(len);
     if(!ret) {
-        SysFreeString(str);
+        jsstr_release(str);
         return E_OUTOFMEMORY;
     }
 
     len = 0;
-    for(ptr=str; *ptr; ptr++) {
-        if(is_uri_unescaped(*ptr))
-            ret[len++] = *ptr;
-        else {
+    for(ptr = str->str; *ptr; ptr++) {
+        if(is_uri_unescaped(*ptr)) {
+            ret->str[len++] = *ptr;
+        }else {
             size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, buf, sizeof(buf), NULL, NULL);
             for(i=0; i<size; i++) {
-                ret[len++] = '%';
-                ret[len++] = int_to_char((BYTE)buf[i] >> 4);
-                ret[len++] = int_to_char(buf[i] & 0x0f);
+                ret->str[len++] = '%';
+                ret->str[len++] = int_to_char((BYTE)buf[i] >> 4);
+                ret->str[len++] = int_to_char(buf[i] & 0x0f);
             }
         }
     }
 
-    SysFreeString(str);
-
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
-    } else {
-        SysFreeString(ret);
-    }
+    jsstr_release(str);
 
+    if(r)
+        *r = jsval_string(ret);
+    else
+        jsstr_release(ret);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.1.3.2 */
-static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    BSTR str, ret;
+    jsstr_t *str, *ret;
     const WCHAR *ptr;
     WCHAR *out_ptr;
     DWORD len = 0;
@@ -941,24 +984,17 @@ static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) {
-            ret = SysAllocString(undefinedW);
-            if(!ret)
-                return E_OUTOFMEMORY;
-
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = ret;
-        }
-
+    if(!argc) {
+        if(r)
+            *r = jsval_string(jsstr_undefined());
         return S_OK;
     }
 
-    hres = to_string(ctx, get_arg(dp, 0), ei, &str);
+    hres = to_string(ctx, argv[0], &str);
     if(FAILED(hres))
         return hres;
 
-    ptr = str;
+    ptr = str->str;
     while(*ptr) {
         if(*ptr == '%') {
             char octets[4];
@@ -966,7 +1002,7 @@ static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W
             int i, size, num_bytes = 0;
             if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
                 FIXME("Throw URIError: Invalid hex sequence\n");
-                SysFreeString(str);
+                jsstr_release(str);
                 return E_FAIL;
             }
             octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
@@ -977,18 +1013,18 @@ static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W
             }
             if(num_bytes == 1 || num_bytes > 4) {
                 FIXME("Throw URIError: Invalid initial UTF character\n");
-                SysFreeString(str);
+                jsstr_release(str);
                 return E_FAIL;
             }
             for(i = 1; i < num_bytes; ++i) {
                 if(*ptr != '%'){
                     FIXME("Throw URIError: Incomplete UTF sequence\n");
-                    SysFreeString(str);
+                    jsstr_release(str);
                     return E_FAIL;
                 }
                 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
                     FIXME("Throw URIError: Invalid hex sequence\n");
-                    SysFreeString(str);
+                    jsstr_release(str);
                     return E_FAIL;
                 }
                 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
@@ -998,7 +1034,7 @@ static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W
                     num_bytes ? num_bytes : 1, NULL, 0);
             if(size == 0) {
                 FIXME("Throw URIError: Invalid UTF sequence\n");
-                SysFreeString(str);
+                jsstr_release(str);
                 return E_FAIL;
             }
             len += size;
@@ -1008,13 +1044,14 @@ static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W
         }
     }
 
-    out_ptr = ret = SysAllocStringLen(NULL, len);
+    ret = jsstr_alloc_buf(len);
     if(!ret) {
-        SysFreeString(str);
+        jsstr_release(str);
         return E_OUTOFMEMORY;
     }
+    out_ptr = ret->str;
 
-    ptr = str;
+    ptr = str->str;
     while(*ptr) {
         if(*ptr == '%') {
             char octets[4];
@@ -1040,15 +1077,12 @@ static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W
         }
     }
 
-    SysFreeString(str);
-
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
-    }else {
-        SysFreeString(ret);
-    }
+    jsstr_release(str);
 
+    if(r)
+        *r = jsval_string(ret);
+    else
+        jsstr_release(ret);
     return S_OK;
 }
 
@@ -1063,14 +1097,12 @@ static const builtin_prop_t JSGlobal_props[] = {
     {EvalErrorW,                 JSGlobal_EvalError,                 PROPF_CONSTR|1},
     {FunctionW,                  JSGlobal_Function,                  PROPF_CONSTR|1},
     {_GetObjectW,                JSGlobal_GetObject,                 PROPF_METHOD|2},
-    {InfinityW,                  JSGlobal_Infinity,                  0},
-/*  {MathW,                      JSGlobal_Math,                      0},  */
-    {NaNW,                       JSGlobal_NaN,                       0},
     {NumberW,                    JSGlobal_Number,                    PROPF_CONSTR|1},
     {ObjectW,                    JSGlobal_Object,                    PROPF_CONSTR|1},
     {RangeErrorW,                JSGlobal_RangeError,                PROPF_CONSTR|1},
     {ReferenceErrorW,            JSGlobal_ReferenceError,            PROPF_CONSTR|1},
     {RegExpW,                    JSGlobal_RegExp,                    PROPF_CONSTR|2},
+    {RegExpErrorW,               JSGlobal_RegExpError,               PROPF_CONSTR|1},
     {ScriptEngineW,              JSGlobal_ScriptEngine,              PROPF_METHOD},
     {ScriptEngineBuildVersionW,  JSGlobal_ScriptEngineBuildVersion,  PROPF_METHOD},
     {ScriptEngineMajorVersionW,  JSGlobal_ScriptEngineMajorVersion,  PROPF_METHOD},
@@ -1079,7 +1111,7 @@ static const builtin_prop_t JSGlobal_props[] = {
     {SyntaxErrorW,               JSGlobal_SyntaxError,               PROPF_CONSTR|1},
     {TypeErrorW,                 JSGlobal_TypeError,                 PROPF_CONSTR|1},
     {URIErrorW,                  JSGlobal_URIError,                  PROPF_CONSTR|1},
-    {VBArrayW,                   JSGlobal_VBArray,                   PROPF_METHOD|1},
+    {VBArrayW,                   JSGlobal_VBArray,                   PROPF_CONSTR|1},
     {decodeURIW,                 JSGlobal_decodeURI,                 PROPF_METHOD|1},
     {decodeURIComponentW,        JSGlobal_decodeURIComponent,        PROPF_METHOD|1},
     {encodeURIW,                 JSGlobal_encodeURI,                 PROPF_METHOD|1},
@@ -1102,7 +1134,7 @@ static const builtin_info_t JSGlobal_info = {
     NULL
 };
 
-static HRESULT init_constructors(script_ctx_t *ctx, DispatchEx *object_prototype)
+static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
 {
     HRESULT hres;
 
@@ -1146,13 +1178,16 @@ static HRESULT init_constructors(script_ctx_t *ctx, DispatchEx *object_prototype
     if(FAILED(hres))
         return hres;
 
+    hres = create_vbarray_constr(ctx, object_prototype, &ctx->vbarray_constr);
+    if(FAILED(hres))
+        return hres;
+
     return S_OK;
 }
 
 HRESULT init_global(script_ctx_t *ctx)
 {
-    DispatchEx *math, *object_prototype;
-    VARIANT var;
+    jsdisp_t *math, *object_prototype;
     HRESULT hres;
 
     if(ctx->global)
@@ -1175,15 +1210,19 @@ HRESULT init_global(script_ctx_t *ctx)
     if(FAILED(hres))
         return hres;
 
-    V_VT(&var) = VT_EMPTY;
-    hres = jsdisp_propput_name(ctx->global, undefinedW, &var, NULL/*FIXME*/, NULL/*FIXME*/);
+    hres = jsdisp_propput_dontenum(ctx->global, MathW, jsval_obj(math));
+    jsdisp_release(math);
     if(FAILED(hres))
         return hres;
 
-    V_VT(&var) = VT_DISPATCH;
-    V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(math);
-    hres = jsdisp_propput_name(ctx->global, MathW, &var, NULL/*FIXME*/, NULL/*FIXME*/);
-    jsdisp_release(math);
+    hres = jsdisp_propput_dontenum(ctx->global, undefinedW, jsval_undefined());
+    if(FAILED(hres))
+        return hres;
+
+    hres = jsdisp_propput_dontenum(ctx->global, NaNW, jsval_number(NAN));
+    if(FAILED(hres))
+        return hres;
 
+    hres = jsdisp_propput_dontenum(ctx->global, InfinityW, jsval_number(INFINITY));
     return hres;
 }
index e5427e0..60f34f2 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include <assert.h>
+
 #include "jscript.h"
 #include "engine.h"
 #include <objsafe.h>
@@ -39,11 +41,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 #endif
 
 typedef struct {
-    const IActiveScriptVtbl                 *lpIActiveScriptVtbl;
-    const IActiveScriptParseVtbl            *lpIActiveScriptParseVtbl;
-    const IActiveScriptParseProcedure2Vtbl  *lpIActiveScriptParseProcedure2Vtbl;
-    const IActiveScriptPropertyVtbl         *lpIActiveScriptPropertyVtbl;
-    const IObjectSafetyVtbl                 *lpIObjectSafetyVtbl;
+    IActiveScript                IActiveScript_iface;
+    IActiveScriptParse           IActiveScriptParse_iface;
+    IActiveScriptParseProcedure2 IActiveScriptParseProcedure2_iface;
+    IActiveScriptProperty        IActiveScriptProperty_iface;
+    IObjectSafety                IObjectSafety_iface;
+    IVariantChangeType           IVariantChangeType_iface;
 
     LONG ref;
 
@@ -52,26 +55,29 @@ typedef struct {
     LONG thread_id;
     LCID lcid;
     DWORD version;
+    BOOL is_encode;
 
     IActiveScriptSite *site;
 
-    parser_ctx_t *queue_head;
-    parser_ctx_t *queue_tail;
+    bytecode_t *queue_head;
+    bytecode_t *queue_tail;
 } JScript;
 
-#define ACTSCRIPT(x)    ((IActiveScript*) &(x)->lpIActiveScriptVtbl)
-#define ASPARSE(x)      (&(x)->lpIActiveScriptParseVtbl)
-#define ASPARSEPROC(x)  (&(x)->lpIActiveScriptParseProcedure2Vtbl)
-#define ACTSCPPROP(x)   (&(x)->lpIActiveScriptPropertyVtbl)
-#define OBJSAFETY(x)    (&(x)->lpIObjectSafetyVtbl)
-
 void script_release(script_ctx_t *ctx)
 {
     if(--ctx->ref)
         return;
 
-    jsheap_free(&ctx->tmp_heap);
-    SysFreeString(ctx->last_match);
+    clear_ei(ctx);
+    if(ctx->cc)
+        release_cc(ctx->cc);
+    heap_pool_free(&ctx->tmp_heap);
+    if(ctx->last_match)
+        jsstr_release(ctx->last_match);
+
+    ctx->jscaller->ctx = NULL;
+    IServiceProvider_Release(&ctx->jscaller->IServiceProvider_iface);
+
     heap_free(ctx);
 }
 
@@ -81,7 +87,8 @@ static void change_state(JScript *This, SCRIPTSTATE state)
         return;
 
     This->ctx->state = state;
-    IActiveScriptSite_OnStateChange(This->site, state);
+    if(This->site)
+        IActiveScriptSite_OnStateChange(This->site, state);
 }
 
 static inline BOOL is_started(script_ctx_t *ctx)
@@ -91,21 +98,19 @@ static inline BOOL is_started(script_ctx_t *ctx)
         || ctx->state == SCRIPTSTATE_DISCONNECTED;
 }
 
-static HRESULT exec_global_code(JScript *This, parser_ctx_t *parser_ctx)
+static HRESULT exec_global_code(JScript *This, bytecode_t *code)
 {
     exec_ctx_t *exec_ctx;
-    jsexcept_t jsexcept;
     HRESULT hres;
 
-    hres = create_exec_ctx(This->ctx, NULL, This->ctx->global, NULL, &exec_ctx);
+    hres = create_exec_ctx(This->ctx, NULL, This->ctx->global, NULL, TRUE, &exec_ctx);
     if(FAILED(hres))
         return hres;
 
     IActiveScriptSite_OnEnterScript(This->site);
 
-    memset(&jsexcept, 0, sizeof(jsexcept));
-    hres = exec_source(exec_ctx, parser_ctx, parser_ctx->source, EXECT_PROGRAM, &jsexcept, NULL);
-    VariantClear(&jsexcept.var);
+    clear_ei(This->ctx);
+    hres = exec_source(exec_ctx, code, &code->global_code, FALSE, NULL);
     exec_release(exec_ctx);
 
     IActiveScriptSite_OnLeaveScript(This->site);
@@ -114,7 +119,7 @@ static HRESULT exec_global_code(JScript *This, parser_ctx_t *parser_ctx)
 
 static void clear_script_queue(JScript *This)
 {
-    parser_ctx_t *iter, *iter2;
+    bytecode_t *iter, *iter2;
 
     if(!This->queue_head)
         return;
@@ -123,7 +128,7 @@ static void clear_script_queue(JScript *This)
     while(iter) {
         iter2 = iter->next;
         iter->next = NULL;
-        parser_release(iter);
+        release_bytecode(iter);
         iter = iter2;
     }
 
@@ -132,7 +137,7 @@ static void clear_script_queue(JScript *This)
 
 static void exec_queued_code(JScript *This)
 {
-    parser_ctx_t *iter;
+    bytecode_t *iter;
 
     for(iter = This->queue_head; iter; iter = iter->next)
         exec_global_code(This, iter);
@@ -157,28 +162,109 @@ static HRESULT set_ctx_site(JScript *This)
     return S_OK;
 }
 
+static void decrease_state(JScript *This, SCRIPTSTATE state)
+{
+    if(This->ctx) {
+        switch(This->ctx->state) {
+        case SCRIPTSTATE_CONNECTED:
+            change_state(This, SCRIPTSTATE_DISCONNECTED);
+            if(state == SCRIPTSTATE_DISCONNECTED)
+                return;
+            /* FALLTHROUGH */
+        case SCRIPTSTATE_STARTED:
+        case SCRIPTSTATE_DISCONNECTED:
+            clear_script_queue(This);
+
+            if(This->ctx->state == SCRIPTSTATE_DISCONNECTED)
+                change_state(This, SCRIPTSTATE_INITIALIZED);
+            if(state == SCRIPTSTATE_INITIALIZED)
+                return;
+            /* FALLTHROUGH */
+        case SCRIPTSTATE_INITIALIZED:
+            if(This->ctx->host_global) {
+                IDispatch_Release(This->ctx->host_global);
+                This->ctx->host_global = NULL;
+            }
+
+            if(This->ctx->named_items) {
+                named_item_t *iter, *iter2;
+
+                iter = This->ctx->named_items;
+                while(iter) {
+                    iter2 = iter->next;
+
+                    if(iter->disp)
+                        IDispatch_Release(iter->disp);
+                    heap_free(iter->name);
+                    heap_free(iter);
+                    iter = iter2;
+                }
+
+                This->ctx->named_items = NULL;
+            }
+
+            if(This->ctx->secmgr) {
+                IInternetHostSecurityManager_Release(This->ctx->secmgr);
+                This->ctx->secmgr = NULL;
+            }
+
+            if(This->ctx->site) {
+                IActiveScriptSite_Release(This->ctx->site);
+                This->ctx->site = NULL;
+            }
+
+            if(This->ctx->global) {
+                jsdisp_release(This->ctx->global);
+                This->ctx->global = NULL;
+            }
+            /* FALLTHROUGH */
+        case SCRIPTSTATE_UNINITIALIZED:
+            change_state(This, state);
+            break;
+        default:
+            assert(0);
+        }
+
+        change_state(This, state);
+    }else if(state == SCRIPTSTATE_UNINITIALIZED) {
+        if(This->site)
+            IActiveScriptSite_OnStateChange(This->site, state);
+    }else {
+        FIXME("NULL ctx\n");
+    }
+
+    if(state == SCRIPTSTATE_UNINITIALIZED)
+        This->thread_id = 0;
+
+    if(This->site) {
+        IActiveScriptSite_Release(This->site);
+        This->site = NULL;
+    }
+}
+
 typedef struct {
-    const IServiceProviderVtbl *lpIServiceProviderVtbl;
+    IServiceProvider IServiceProvider_iface;
 
     LONG ref;
 
     IServiceProvider *sp;
 } AXSite;
 
-#define SERVPROV(x)  ((IServiceProvider*) &(x)->lpIServiceProviderVtbl)
-
-#define SERVPROV_THIS(iface) DEFINE_THIS(AXSite, IServiceProvider, iface)
+static inline AXSite *impl_from_IServiceProvider(IServiceProvider *iface)
+{
+    return CONTAINING_RECORD(iface, AXSite, IServiceProvider_iface);
+}
 
 static HRESULT WINAPI AXSite_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
 {
-    AXSite *This = SERVPROV_THIS(iface);
+    AXSite *This = impl_from_IServiceProvider(iface);
 
     if(IsEqualGUID(&IID_IUnknown, riid)) {
         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
-        *ppv = SERVPROV(This);
+        *ppv = &This->IServiceProvider_iface;
     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
-        *ppv = SERVPROV(This);
+        *ppv = &This->IServiceProvider_iface;
     }else {
         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
         *ppv = NULL;
@@ -191,7 +277,7 @@ static HRESULT WINAPI AXSite_QueryInterface(IServiceProvider *iface, REFIID riid
 
 static ULONG WINAPI AXSite_AddRef(IServiceProvider *iface)
 {
-    AXSite *This = SERVPROV_THIS(iface);
+    AXSite *This = impl_from_IServiceProvider(iface);
     LONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) ref=%d\n", This, ref);
@@ -201,13 +287,18 @@ static ULONG WINAPI AXSite_AddRef(IServiceProvider *iface)
 
 static ULONG WINAPI AXSite_Release(IServiceProvider *iface)
 {
-    AXSite *This = SERVPROV_THIS(iface);
+    AXSite *This = impl_from_IServiceProvider(iface);
     LONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) ref=%d\n", This, ref);
 
     if(!ref)
+    {
+        if(This->sp)
+            IServiceProvider_Release(This->sp);
+
         heap_free(This);
+    }
 
     return ref;
 }
@@ -215,15 +306,16 @@ static ULONG WINAPI AXSite_Release(IServiceProvider *iface)
 static HRESULT WINAPI AXSite_QueryService(IServiceProvider *iface,
         REFGUID guidService, REFIID riid, void **ppv)
 {
-    AXSite *This = SERVPROV_THIS(iface);
+    AXSite *This = impl_from_IServiceProvider(iface);
 
     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
 
+    if(!This->sp)
+        return E_NOINTERFACE;
+
     return IServiceProvider_QueryService(This->sp, guidService, riid, ppv);
 }
 
-#undef SERVPROV_THIS
-
 static IServiceProviderVtbl AXSiteVtbl = {
     AXSite_QueryInterface,
     AXSite_AddRef,
@@ -233,14 +325,13 @@ static IServiceProviderVtbl AXSiteVtbl = {
 
 IUnknown *create_ax_site(script_ctx_t *ctx)
 {
-    IServiceProvider *sp;
+    IServiceProvider *sp = NULL;
     AXSite *ret;
     HRESULT hres;
 
     hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IServiceProvider, (void**)&sp);
     if(FAILED(hres)) {
-        ERR("Could not get IServiceProvider iface: %08x\n", hres);
-        return NULL;
+        TRACE("Could not get IServiceProvider iface: %08x\n", hres);
     }
 
     ret = heap_alloc(sizeof(AXSite));
@@ -249,42 +340,48 @@ IUnknown *create_ax_site(script_ctx_t *ctx)
         return NULL;
     }
 
-    ret->lpIServiceProviderVtbl = &AXSiteVtbl;
+    ret->IServiceProvider_iface.lpVtbl = &AXSiteVtbl;
     ret->ref = 1;
     ret->sp = sp;
 
-    return (IUnknown*)SERVPROV(ret);
+    return (IUnknown*)&ret->IServiceProvider_iface;
 }
 
-#define ACTSCRIPT_THIS(iface) DEFINE_THIS(JScript, IActiveScript, iface)
+static inline JScript *impl_from_IActiveScript(IActiveScript *iface)
+{
+    return CONTAINING_RECORD(iface, JScript, IActiveScript_iface);
+}
 
 static HRESULT WINAPI JScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
 
     *ppv = NULL;
 
     if(IsEqualGUID(riid, &IID_IUnknown)) {
         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
-        *ppv = ACTSCRIPT(This);
+        *ppv = &This->IActiveScript_iface;
     }else if(IsEqualGUID(riid, &IID_IActiveScript)) {
         TRACE("(%p)->(IID_IActiveScript %p)\n", This, ppv);
-        *ppv = ACTSCRIPT(This);
+        *ppv = &This->IActiveScript_iface;
     }else if(IsEqualGUID(riid, &IID_IActiveScriptParse)) {
         TRACE("(%p)->(IID_IActiveScriptParse %p)\n", This, ppv);
-        *ppv = ASPARSE(This);
+        *ppv = &This->IActiveScriptParse_iface;
     }else if(IsEqualGUID(riid, &IID_IActiveScriptParseProcedure)) {
         TRACE("(%p)->(IID_IActiveScriptParseProcedure %p)\n", This, ppv);
-        *ppv = ASPARSEPROC(This);
+        *ppv = &This->IActiveScriptParseProcedure2_iface;
     }else if(IsEqualGUID(riid, &IID_IActiveScriptParseProcedure2)) {
         TRACE("(%p)->(IID_IActiveScriptParseProcedure2 %p)\n", This, ppv);
-        *ppv = ASPARSEPROC(This);
+        *ppv = &This->IActiveScriptParseProcedure2_iface;
     }else if(IsEqualGUID(riid, &IID_IActiveScriptProperty)) {
         TRACE("(%p)->(IID_IActiveScriptProperty %p)\n", This, ppv);
-        *ppv = ACTSCPPROP(This);
+        *ppv = &This->IActiveScriptProperty_iface;
     }else if(IsEqualGUID(riid, &IID_IObjectSafety)) {
         TRACE("(%p)->(IID_IObjectSafety %p)\n", This, ppv);
-        *ppv = OBJSAFETY(This);
+        *ppv = &This->IObjectSafety_iface;
+    }else if(IsEqualGUID(riid, &IID_IVariantChangeType)) {
+        TRACE("(%p)->(IID_IVariantChangeType %p)\n", This, ppv);
+        *ppv = &This->IVariantChangeType_iface;
     }
 
     if(*ppv) {
@@ -298,7 +395,7 @@ static HRESULT WINAPI JScript_QueryInterface(IActiveScript *iface, REFIID riid,
 
 static ULONG WINAPI JScript_AddRef(IActiveScript *iface)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
     LONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) ref=%d\n", This, ref);
@@ -308,16 +405,18 @@ static ULONG WINAPI JScript_AddRef(IActiveScript *iface)
 
 static ULONG WINAPI JScript_Release(IActiveScript *iface)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
     LONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) ref=%d\n", iface, ref);
 
     if(!ref) {
         if(This->ctx && This->ctx->state != SCRIPTSTATE_CLOSED)
-            IActiveScript_Close(ACTSCRIPT(This));
-        if(This->ctx)
+            IActiveScript_Close(&This->IActiveScript_iface);
+        if(This->ctx) {
+            This->ctx->active_script = NULL;
             script_release(This->ctx);
+        }
         heap_free(This);
         unlock_module();
     }
@@ -328,7 +427,7 @@ static ULONG WINAPI JScript_Release(IActiveScript *iface)
 static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface,
                                             IActiveScriptSite *pass)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
     LCID lcid;
     HRESULT hres;
 
@@ -356,18 +455,29 @@ static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface,
 static HRESULT WINAPI JScript_GetScriptSite(IActiveScript *iface, REFIID riid,
                                             void **ppvObject)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
     FIXME("(%p)->()\n", This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI JScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
 
     TRACE("(%p)->(%d)\n", This, ss);
 
-    if(!This->ctx || GetCurrentThreadId() != This->thread_id)
+    if(This->thread_id && GetCurrentThreadId() != This->thread_id)
+        return E_UNEXPECTED;
+
+    if(ss == SCRIPTSTATE_UNINITIALIZED) {
+        if(This->ctx && This->ctx->state == SCRIPTSTATE_CLOSED)
+            return E_UNEXPECTED;
+
+        decrease_state(This, SCRIPTSTATE_UNINITIALIZED);
+        return S_OK;
+    }
+
+    if(!This->ctx)
         return E_UNEXPECTED;
 
     switch(ss) {
@@ -378,6 +488,9 @@ static HRESULT WINAPI JScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE s
 
         exec_queued_code(This);
         break;
+    case SCRIPTSTATE_INITIALIZED:
+        FIXME("unimplemented SCRIPTSTATE_INITIALIZED\n");
+        return S_OK;
     default:
         FIXME("unimplemented state %d\n", ss);
         return E_NOTIMPL;
@@ -389,19 +502,14 @@ static HRESULT WINAPI JScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE s
 
 static HRESULT WINAPI JScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
 
     TRACE("(%p)->(%p)\n", This, pssState);
 
     if(!pssState)
         return E_POINTER;
 
-    if(!This->thread_id) {
-        *pssState = SCRIPTSTATE_UNINITIALIZED;
-        return S_OK;
-    }
-
-    if(This->thread_id != GetCurrentThreadId())
+    if(This->thread_id && This->thread_id != GetCurrentThreadId())
         return E_UNEXPECTED;
 
     *pssState = This->ctx ? This->ctx->state : SCRIPTSTATE_UNINITIALIZED;
@@ -410,75 +518,21 @@ static HRESULT WINAPI JScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *
 
 static HRESULT WINAPI JScript_Close(IActiveScript *iface)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
 
     TRACE("(%p)->()\n", This);
 
-    if(This->thread_id != GetCurrentThreadId())
+    if(This->thread_id && This->thread_id != GetCurrentThreadId())
         return E_UNEXPECTED;
 
-    if(This->ctx) {
-        if(This->ctx->state == SCRIPTSTATE_CONNECTED)
-            change_state(This, SCRIPTSTATE_DISCONNECTED);
-
-        clear_script_queue(This);
-
-        if(This->ctx->state == SCRIPTSTATE_DISCONNECTED)
-            change_state(This, SCRIPTSTATE_INITIALIZED);
-
-        if(This->ctx->host_global) {
-            IDispatch_Release(This->ctx->host_global);
-            This->ctx->host_global = NULL;
-        }
-
-        if(This->ctx->named_items) {
-            named_item_t *iter, *iter2;
-
-            iter = This->ctx->named_items;
-            while(iter) {
-                iter2 = iter->next;
-
-                if(iter->disp)
-                    IDispatch_Release(iter->disp);
-                heap_free(iter->name);
-                heap_free(iter);
-                iter = iter2;
-            }
-
-            This->ctx->named_items = NULL;
-        }
-
-        if(This->ctx->secmgr) {
-            IInternetHostSecurityManager_Release(This->ctx->secmgr);
-            This->ctx->secmgr = NULL;
-        }
-
-        if(This->ctx->site) {
-            IActiveScriptSite_Release(This->ctx->site);
-            This->ctx->site = NULL;
-        }
-
-        if (This->site)
-            change_state(This, SCRIPTSTATE_CLOSED);
-
-        if(This->ctx->global) {
-            jsdisp_release(This->ctx->global);
-            This->ctx->global = NULL;
-        }
-    }
-
-    if(This->site) {
-        IActiveScriptSite_Release(This->site);
-        This->site = NULL;
-    }
-
+    decrease_state(This, SCRIPTSTATE_CLOSED);
     return S_OK;
 }
 
 static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
                                            LPCOLESTR pstrName, DWORD dwFlags)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
     named_item_t *item;
     IDispatch *disp = NULL;
     HRESULT hres;
@@ -521,7 +575,8 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
     item->flags = dwFlags;
     item->name = heap_strdupW(pstrName);
     if(!item->name) {
-        IDispatch_Release(disp);
+        if(disp)
+            IDispatch_Release(disp);
         heap_free(item);
         return E_OUTOFMEMORY;
     }
@@ -535,7 +590,7 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
 static HRESULT WINAPI JScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
                                          DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
     FIXME("(%p)->()\n", This);
     return E_NOTIMPL;
 }
@@ -543,7 +598,7 @@ static HRESULT WINAPI JScript_AddTypeLib(IActiveScript *iface, REFGUID rguidType
 static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName,
                                                 IDispatch **ppdisp)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
 
     TRACE("(%p)->(%p)\n", This, ppdisp);
 
@@ -555,7 +610,7 @@ static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR
         return E_UNEXPECTED;
     }
 
-    *ppdisp = (IDispatch*)_IDispatchEx_(This->ctx->global);
+    *ppdisp = to_disp(This->ctx->global);
     IDispatch_AddRef(*ppdisp);
     return S_OK;
 }
@@ -563,7 +618,7 @@ static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR
 static HRESULT WINAPI JScript_GetCurrentScriptThreadID(IActiveScript *iface,
                                                        SCRIPTTHREADID *pstridThread)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
     FIXME("(%p)->()\n", This);
     return E_NOTIMPL;
 }
@@ -571,7 +626,7 @@ static HRESULT WINAPI JScript_GetCurrentScriptThreadID(IActiveScript *iface,
 static HRESULT WINAPI JScript_GetScriptThreadID(IActiveScript *iface,
                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
     FIXME("(%p)->()\n", This);
     return E_NOTIMPL;
 }
@@ -579,7 +634,7 @@ static HRESULT WINAPI JScript_GetScriptThreadID(IActiveScript *iface,
 static HRESULT WINAPI JScript_GetScriptThreadState(IActiveScript *iface,
         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
     FIXME("(%p)->()\n", This);
     return E_NOTIMPL;
 }
@@ -587,20 +642,18 @@ static HRESULT WINAPI JScript_GetScriptThreadState(IActiveScript *iface,
 static HRESULT WINAPI JScript_InterruptScriptThread(IActiveScript *iface,
         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
     FIXME("(%p)->()\n", This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI JScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
 {
-    JScript *This = ACTSCRIPT_THIS(iface);
+    JScript *This = impl_from_IActiveScript(iface);
     FIXME("(%p)->()\n", This);
     return E_NOTIMPL;
 }
 
-#undef ACTSCRIPT_THIS
-
 static const IActiveScriptVtbl JScriptVtbl = {
     JScript_QueryInterface,
     JScript_AddRef,
@@ -620,30 +673,34 @@ static const IActiveScriptVtbl JScriptVtbl = {
     JScript_Clone
 };
 
-#define ASPARSE_THIS(iface) DEFINE_THIS(JScript, IActiveScriptParse, iface)
+static inline JScript *impl_from_IActiveScriptParse(IActiveScriptParse *iface)
+{
+    return CONTAINING_RECORD(iface, JScript, IActiveScriptParse_iface);
+}
 
 static HRESULT WINAPI JScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
 {
-    JScript *This = ASPARSE_THIS(iface);
-    return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
+    JScript *This = impl_from_IActiveScriptParse(iface);
+    return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
 }
 
 static ULONG WINAPI JScriptParse_AddRef(IActiveScriptParse *iface)
 {
-    JScript *This = ASPARSE_THIS(iface);
-    return IActiveScript_AddRef(ACTSCRIPT(This));
+    JScript *This = impl_from_IActiveScriptParse(iface);
+    return IActiveScript_AddRef(&This->IActiveScript_iface);
 }
 
 static ULONG WINAPI JScriptParse_Release(IActiveScriptParse *iface)
 {
-    JScript *This = ASPARSE_THIS(iface);
-    return IActiveScript_Release(ACTSCRIPT(This));
+    JScript *This = impl_from_IActiveScriptParse(iface);
+    return IActiveScript_Release(&This->IActiveScript_iface);
 }
 
 static HRESULT WINAPI JScriptParse_InitNew(IActiveScriptParse *iface)
 {
-    JScript *This = ASPARSE_THIS(iface);
+    JScript *This = impl_from_IActiveScriptParse(iface);
     script_ctx_t *ctx;
+    HRESULT hres;
 
     TRACE("(%p)\n", This);
 
@@ -656,9 +713,19 @@ static HRESULT WINAPI JScriptParse_InitNew(IActiveScriptParse *iface)
 
     ctx->ref = 1;
     ctx->state = SCRIPTSTATE_UNINITIALIZED;
+    ctx->active_script = &This->IActiveScript_iface;
     ctx->safeopt = This->safeopt;
     ctx->version = This->version;
-    jsheap_init(&ctx->tmp_heap);
+    ctx->ei.val = jsval_undefined();
+    heap_pool_init(&ctx->tmp_heap);
+
+    hres = create_jscaller(ctx);
+    if(FAILED(hres)) {
+        heap_free(ctx);
+        return hres;
+    }
+
+    ctx->last_match = jsstr_empty();
 
     ctx = InterlockedCompareExchangePointer((void**)&This->ctx, ctx, NULL);
     if(ctx) {
@@ -675,7 +742,7 @@ static HRESULT WINAPI JScriptParse_AddScriptlet(IActiveScriptParse *iface,
         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
         BSTR *pbstrName, EXCEPINFO *pexcepinfo)
 {
-    JScript *This = ASPARSE_THIS(iface);
+    JScript *This = impl_from_IActiveScriptParse(iface);
     FIXME("(%p)->(%s %s %s %s %s %s %s %u %x %p %p)\n", This, debugstr_w(pstrDefaultName),
           debugstr_w(pstrCode), debugstr_w(pstrItemName), debugstr_w(pstrSubItemName),
           debugstr_w(pstrEventName), debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie),
@@ -688,8 +755,8 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
         LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine,
         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
 {
-    JScript *This = ASPARSE_THIS(iface);
-    parser_ctx_t *parser_ctx;
+    JScript *This = impl_from_IActiveScriptParse(iface);
+    bytecode_t *code;
     HRESULT hres;
 
     TRACE("(%p)->(%s %s %p %s %s %u %x %p %p)\n", This, debugstr_w(pstrCode),
@@ -699,26 +766,48 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
         return E_UNEXPECTED;
 
-    hres = script_parse(This->ctx, pstrCode, pstrDelimiter, &parser_ctx);
+    hres = compile_script(This->ctx, pstrCode, NULL, pstrDelimiter, (dwFlags & SCRIPTTEXT_ISEXPRESSION) != 0,
+            This->is_encode, &code);
     if(FAILED(hres))
         return hres;
 
+    if(dwFlags & SCRIPTTEXT_ISEXPRESSION) {
+        exec_ctx_t *exec_ctx;
+
+        hres = create_exec_ctx(This->ctx, NULL, This->ctx->global, NULL, TRUE, &exec_ctx);
+        if(SUCCEEDED(hres)) {
+            jsval_t r;
+
+            IActiveScriptSite_OnEnterScript(This->site);
+
+            clear_ei(This->ctx);
+            hres = exec_source(exec_ctx, code, &code->global_code, TRUE, &r);
+            if(SUCCEEDED(hres)) {
+                hres = jsval_to_variant(r, pvarResult);
+                jsval_release(r);
+            }
+            exec_release(exec_ctx);
+
+            IActiveScriptSite_OnLeaveScript(This->site);
+        }
+
+        return hres;
+    }
+
     if(!is_started(This->ctx)) {
         if(This->queue_tail)
-            This->queue_tail = This->queue_tail->next = parser_ctx;
+            This->queue_tail = This->queue_tail->next = code;
         else
-            This->queue_head = This->queue_tail = parser_ctx;
+            This->queue_head = This->queue_tail = code;
         return S_OK;
     }
 
-    hres = exec_global_code(This, parser_ctx);
-    parser_release(parser_ctx);
+    hres = exec_global_code(This, code);
 
+    release_bytecode(code);
     return hres;
 }
 
-#undef ASPARSE_THIS
-
 static const IActiveScriptParseVtbl JScriptParseVtbl = {
     JScriptParse_QueryInterface,
     JScriptParse_AddRef,
@@ -728,24 +817,27 @@ static const IActiveScriptParseVtbl JScriptParseVtbl = {
     JScriptParse_ParseScriptText
 };
 
-#define ASPARSEPROC_THIS(iface) DEFINE_THIS(JScript, IActiveScriptParseProcedure2, iface)
+static inline JScript *impl_from_IActiveScriptParseProcedure2(IActiveScriptParseProcedure2 *iface)
+{
+    return CONTAINING_RECORD(iface, JScript, IActiveScriptParseProcedure2_iface);
+}
 
 static HRESULT WINAPI JScriptParseProcedure_QueryInterface(IActiveScriptParseProcedure2 *iface, REFIID riid, void **ppv)
 {
-    JScript *This = ASPARSEPROC_THIS(iface);
-    return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
+    JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
+    return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
 }
 
 static ULONG WINAPI JScriptParseProcedure_AddRef(IActiveScriptParseProcedure2 *iface)
 {
-    JScript *This = ASPARSEPROC_THIS(iface);
-    return IActiveScript_AddRef(ACTSCRIPT(This));
+    JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
+    return IActiveScript_AddRef(&This->IActiveScript_iface);
 }
 
 static ULONG WINAPI JScriptParseProcedure_Release(IActiveScriptParseProcedure2 *iface)
 {
-    JScript *This = ASPARSEPROC_THIS(iface);
-    return IActiveScript_Release(ACTSCRIPT(This));
+    JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
+    return IActiveScript_Release(&This->IActiveScript_iface);
 }
 
 static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptParseProcedure2 *iface,
@@ -753,9 +845,9 @@ static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptPars
         LPCOLESTR pstrItemName, IUnknown *punkContext, LPCOLESTR pstrDelimiter,
         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp)
 {
-    JScript *This = ASPARSEPROC_THIS(iface);
-    parser_ctx_t *parser_ctx;
-    DispatchEx *dispex;
+    JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
+    bytecode_t *code;
+    jsdisp_t *dispex;
     HRESULT hres;
 
     TRACE("(%p)->(%s %s %s %s %p %s %s %u %x %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrFormalParams),
@@ -765,23 +857,21 @@ static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptPars
     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
         return E_UNEXPECTED;
 
-    hres = script_parse(This->ctx, pstrCode, pstrDelimiter, &parser_ctx);
+    hres = compile_script(This->ctx, pstrCode, pstrFormalParams, pstrDelimiter, FALSE, This->is_encode, &code);
     if(FAILED(hres)) {
         WARN("Parse failed %08x\n", hres);
         return hres;
     }
 
-    hres = create_source_function(parser_ctx, NULL, parser_ctx->source, NULL, NULL, 0, &dispex);
-    parser_release(parser_ctx);
+    hres = create_source_function(This->ctx, code, &code->global_code, NULL,  &dispex);
+    release_bytecode(code);
     if(FAILED(hres))
         return hres;
 
-    *ppdisp = (IDispatch*)_IDispatchEx_(dispex);
+    *ppdisp = to_disp(dispex);
     return S_OK;
 }
 
-#undef ASPARSEPROC_THIS
-
 static const IActiveScriptParseProcedure2Vtbl JScriptParseProcedureVtbl = {
     JScriptParseProcedure_QueryInterface,
     JScriptParseProcedure_AddRef,
@@ -789,30 +879,33 @@ static const IActiveScriptParseProcedure2Vtbl JScriptParseProcedureVtbl = {
     JScriptParseProcedure_ParseProcedureText,
 };
 
-#define ACTSCPPROP_THIS(iface) DEFINE_THIS(JScript, IActiveScriptProperty, iface)
+static inline JScript *impl_from_IActiveScriptProperty(IActiveScriptProperty *iface)
+{
+    return CONTAINING_RECORD(iface, JScript, IActiveScriptProperty_iface);
+}
 
 static HRESULT WINAPI JScriptProperty_QueryInterface(IActiveScriptProperty *iface, REFIID riid, void **ppv)
 {
-    JScript *This = ACTSCPPROP_THIS(iface);
-    return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
+    JScript *This = impl_from_IActiveScriptProperty(iface);
+    return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
 }
 
 static ULONG WINAPI JScriptProperty_AddRef(IActiveScriptProperty *iface)
 {
-    JScript *This = ACTSCPPROP_THIS(iface);
-    return IActiveScript_AddRef(ACTSCRIPT(This));
+    JScript *This = impl_from_IActiveScriptProperty(iface);
+    return IActiveScript_AddRef(&This->IActiveScript_iface);
 }
 
 static ULONG WINAPI JScriptProperty_Release(IActiveScriptProperty *iface)
 {
-    JScript *This = ACTSCPPROP_THIS(iface);
-    return IActiveScript_Release(ACTSCRIPT(This));
+    JScript *This = impl_from_IActiveScriptProperty(iface);
+    return IActiveScript_Release(&This->IActiveScript_iface);
 }
 
 static HRESULT WINAPI JScriptProperty_GetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
         VARIANT *pvarIndex, VARIANT *pvarValue)
 {
-    JScript *This = ACTSCPPROP_THIS(iface);
+    JScript *This = impl_from_IActiveScriptProperty(iface);
     FIXME("(%p)->(%x %p %p)\n", This, dwProperty, pvarIndex, pvarValue);
     return E_NOTIMPL;
 }
@@ -820,7 +913,7 @@ static HRESULT WINAPI JScriptProperty_GetProperty(IActiveScriptProperty *iface,
 static HRESULT WINAPI JScriptProperty_SetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
         VARIANT *pvarIndex, VARIANT *pvarValue)
 {
-    JScript *This = ACTSCPPROP_THIS(iface);
+    JScript *This = impl_from_IActiveScriptProperty(iface);
 
     TRACE("(%p)->(%x %s %s)\n", This, dwProperty, debugstr_variant(pvarIndex), debugstr_variant(pvarValue));
 
@@ -844,8 +937,6 @@ static HRESULT WINAPI JScriptProperty_SetProperty(IActiveScriptProperty *iface,
     return S_OK;
 }
 
-#undef ACTSCPPROP_THIS
-
 static const IActiveScriptPropertyVtbl JScriptPropertyVtbl = {
     JScriptProperty_QueryInterface,
     JScriptProperty_AddRef,
@@ -854,24 +945,27 @@ static const IActiveScriptPropertyVtbl JScriptPropertyVtbl = {
     JScriptProperty_SetProperty
 };
 
-#define OBJSAFETY_THIS(iface) DEFINE_THIS(JScript, IObjectSafety, iface)
+static inline JScript *impl_from_IObjectSafety(IObjectSafety *iface)
+{
+    return CONTAINING_RECORD(iface, JScript, IObjectSafety_iface);
+}
 
 static HRESULT WINAPI JScriptSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
 {
-    JScript *This = OBJSAFETY_THIS(iface);
-    return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
+    JScript *This = impl_from_IObjectSafety(iface);
+    return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
 }
 
 static ULONG WINAPI JScriptSafety_AddRef(IObjectSafety *iface)
 {
-    JScript *This = OBJSAFETY_THIS(iface);
-    return IActiveScript_AddRef(ACTSCRIPT(This));
+    JScript *This = impl_from_IObjectSafety(iface);
+    return IActiveScript_AddRef(&This->IActiveScript_iface);
 }
 
 static ULONG WINAPI JScriptSafety_Release(IObjectSafety *iface)
 {
-    JScript *This = OBJSAFETY_THIS(iface);
-    return IActiveScript_Release(ACTSCRIPT(This));
+    JScript *This = impl_from_IObjectSafety(iface);
+    return IActiveScript_Release(&This->IActiveScript_iface);
 }
 
 #define SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER)
@@ -879,7 +973,7 @@ static ULONG WINAPI JScriptSafety_Release(IObjectSafety *iface)
 static HRESULT WINAPI JScriptSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
 {
-    JScript *This = OBJSAFETY_THIS(iface);
+    JScript *This = impl_from_IObjectSafety(iface);
 
     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
 
@@ -895,19 +989,17 @@ static HRESULT WINAPI JScriptSafety_GetInterfaceSafetyOptions(IObjectSafety *ifa
 static HRESULT WINAPI JScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
 {
-    JScript *This = OBJSAFETY_THIS(iface);
+    JScript *This = impl_from_IObjectSafety(iface);
 
     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
 
     if(dwOptionSetMask & ~SUPPORTED_OPTIONS)
         return E_FAIL;
 
-    This->safeopt = dwEnabledOptions & dwEnabledOptions;
+    This->safeopt = (dwEnabledOptions & dwOptionSetMask) | (This->safeopt & ~dwOptionSetMask) | INTERFACE_USES_DISPEX;
     return S_OK;
 }
 
-#undef OBJSAFETY_THIS
-
 static const IObjectSafetyVtbl JScriptSafetyVtbl = {
     JScriptSafety_QueryInterface,
     JScriptSafety_AddRef,
@@ -916,29 +1008,85 @@ static const IObjectSafetyVtbl JScriptSafetyVtbl = {
     JScriptSafety_SetInterfaceSafetyOptions
 };
 
-HRESULT WINAPI JScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
-                                             REFIID riid, void **ppv)
+static inline JScript *impl_from_IVariantChangeType(IVariantChangeType *iface)
 {
-    JScript *ret;
+    return CONTAINING_RECORD(iface, JScript, IVariantChangeType_iface);
+}
+
+static HRESULT WINAPI VariantChangeType_QueryInterface(IVariantChangeType *iface, REFIID riid, void **ppv)
+{
+    JScript *This = impl_from_IVariantChangeType(iface);
+    return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
+}
+
+static ULONG WINAPI VariantChangeType_AddRef(IVariantChangeType *iface)
+{
+    JScript *This = impl_from_IVariantChangeType(iface);
+    return IActiveScript_AddRef(&This->IActiveScript_iface);
+}
+
+static ULONG WINAPI VariantChangeType_Release(IVariantChangeType *iface)
+{
+    JScript *This = impl_from_IVariantChangeType(iface);
+    return IActiveScript_Release(&This->IActiveScript_iface);
+}
+
+static HRESULT WINAPI VariantChangeType_ChangeType(IVariantChangeType *iface, VARIANT *dst, VARIANT *src, LCID lcid, VARTYPE vt)
+{
+    JScript *This = impl_from_IVariantChangeType(iface);
+    VARIANT res;
     HRESULT hres;
 
-    TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
+    TRACE("(%p)->(%p %p%s %x %d)\n", This, dst, src, debugstr_variant(src), lcid, vt);
 
-    lock_module();
+    if(!This->ctx) {
+        FIXME("Object uninitialized\n");
+        return E_UNEXPECTED;
+    }
+
+    hres = variant_change_type(This->ctx, &res, src, vt);
+    if(FAILED(hres))
+        return hres;
+
+    hres = VariantClear(dst);
+    if(FAILED(hres)) {
+        VariantClear(&res);
+        return hres;
+    }
+
+    *dst = res;
+    return S_OK;
+}
+
+static const IVariantChangeTypeVtbl VariantChangeTypeVtbl = {
+    VariantChangeType_QueryInterface,
+    VariantChangeType_AddRef,
+    VariantChangeType_Release,
+    VariantChangeType_ChangeType
+};
+
+HRESULT create_jscript_object(BOOL is_encode, REFIID riid, void **ppv)
+{
+    JScript *ret;
+    HRESULT hres;
 
     ret = heap_alloc_zero(sizeof(*ret));
     if(!ret)
         return E_OUTOFMEMORY;
 
-    ret->lpIActiveScriptVtbl                 = &JScriptVtbl;
-    ret->lpIActiveScriptParseVtbl            = &JScriptParseVtbl;
-    ret->lpIActiveScriptParseProcedure2Vtbl  = &JScriptParseProcedureVtbl;
-    ret->lpIActiveScriptPropertyVtbl         = &JScriptPropertyVtbl;
-    ret->lpIObjectSafetyVtbl                 = &JScriptSafetyVtbl;
+    lock_module();
+
+    ret->IActiveScript_iface.lpVtbl = &JScriptVtbl;
+    ret->IActiveScriptParse_iface.lpVtbl = &JScriptParseVtbl;
+    ret->IActiveScriptParseProcedure2_iface.lpVtbl = &JScriptParseProcedureVtbl;
+    ret->IActiveScriptProperty_iface.lpVtbl = &JScriptPropertyVtbl;
+    ret->IObjectSafety_iface.lpVtbl = &JScriptSafetyVtbl;
+    ret->IVariantChangeType_iface.lpVtbl = &VariantChangeTypeVtbl;
     ret->ref = 1;
     ret->safeopt = INTERFACE_USES_DISPEX;
+    ret->is_encode = is_encode;
 
-    hres = IActiveScript_QueryInterface(ACTSCRIPT(ret), riid, ppv);
-    IActiveScript_Release(ACTSCRIPT(ret));
+    hres = IActiveScript_QueryInterface(&ret->IActiveScript_iface, riid, ppv);
+    IActiveScript_Release(&ret->IActiveScript_iface);
     return hres;
 }
index d61db97..4a3a483 100644 (file)
 #include <wine/unicode.h>
 #include <wine/list.h>
 
-#define JSCRIPT_ERROR 0x800A0000
-
+typedef struct _jsval_t jsval_t;
+typedef struct _jsstr_t jsstr_t;
 typedef struct _script_ctx_t script_ctx_t;
 typedef struct _exec_ctx_t exec_ctx_t;
 typedef struct _dispex_prop_t dispex_prop_t;
 
-typedef struct {
-    EXCEPINFO ei;
-    VARIANT var;
-} jsexcept_t;
-
 typedef struct {
     void **blocks;
     DWORD block_cnt;
@@ -55,24 +50,61 @@ typedef struct {
     DWORD offset;
     BOOL mark;
     struct list custom_blocks;
-} jsheap_t;
+} heap_pool_t;
+
+void heap_pool_init(heap_pool_t*) DECLSPEC_HIDDEN;
+void *heap_pool_alloc(heap_pool_t*,DWORD) __WINE_ALLOC_SIZE(2) DECLSPEC_HIDDEN;
+void *heap_pool_grow(heap_pool_t*,void*,DWORD,DWORD) DECLSPEC_HIDDEN;
+void heap_pool_clear(heap_pool_t*) DECLSPEC_HIDDEN;
+void heap_pool_free(heap_pool_t*) DECLSPEC_HIDDEN;
+heap_pool_t *heap_pool_mark(heap_pool_t*) DECLSPEC_HIDDEN;
+
+static inline void *heap_alloc(size_t len)
+{
+    return HeapAlloc(GetProcessHeap(), 0, len);
+}
+
+static inline void *heap_alloc_zero(size_t len)
+{
+    return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
+}
+
+static inline void *heap_realloc(void *mem, size_t len)
+{
+    return HeapReAlloc(GetProcessHeap(), 0, mem, len);
+}
+
+static inline BOOL heap_free(void *mem)
+{
+    return HeapFree(GetProcessHeap(), 0, mem);
+}
+
+static inline LPWSTR heap_strdupW(LPCWSTR str)
+{
+    LPWSTR ret = NULL;
+
+    if(str) {
+        DWORD size;
+
+        size = (strlenW(str)+1)*sizeof(WCHAR);
+        ret = heap_alloc(size);
+        if(ret)
+            memcpy(ret, str, size);
+    }
 
-void jsheap_init(jsheap_t*);
-void *jsheap_alloc(jsheap_t*,DWORD);
-void *jsheap_grow(jsheap_t*,void*,DWORD,DWORD);
-void jsheap_clear(jsheap_t*);
-void jsheap_free(jsheap_t*);
-jsheap_t *jsheap_mark(jsheap_t*);
+    return ret;
+}
 
-typedef struct DispatchEx DispatchEx;
+typedef struct jsdisp_t jsdisp_t;
 
-extern HINSTANCE jscript_hinstance;
+extern HINSTANCE jscript_hinstance DECLSPEC_HIDDEN;
 
-#define PROPF_ARGMASK 0x00ff
-#define PROPF_METHOD  0x0100
-#define PROPF_ENUM    0x0200
-#define PROPF_CONSTR  0x0400
-#define PROPF_CONST   0x0800
+#define PROPF_ARGMASK     0x00ff
+#define PROPF_METHOD      0x0100
+#define PROPF_ENUM        0x0200
+#define PROPF_CONSTR      0x0400
+#define PROPF_CONST       0x0800
+#define PROPF_DONTDELETE  0x1000
 
 /* NOTE: Keep in sync with names in Object.toString implementation */
 typedef enum {
@@ -88,16 +120,17 @@ typedef enum {
     JSCLASS_OBJECT,
     JSCLASS_REGEXP,
     JSCLASS_STRING,
-    JSCLASS_ARGUMENTS
+    JSCLASS_ARGUMENTS,
+    JSCLASS_VBARRAY
 } jsclass_t;
 
-DispatchEx *iface_to_jsdisp(IUnknown*);
+jsdisp_t *iface_to_jsdisp(IUnknown*) DECLSPEC_HIDDEN;
 
 typedef struct {
     union {
         IDispatch *disp;
         IDispatchEx *dispex;
-        DispatchEx *jsdisp;
+        jsdisp_t *jsdisp;
     } u;
     DWORD flags;
 } vdisp_t;
@@ -120,7 +153,7 @@ static inline BOOL is_dispex(vdisp_t *vdisp)
     return (vdisp->flags & VDISP_DISPEX) != 0;
 }
 
-static inline void set_jsdisp(vdisp_t *vdisp, DispatchEx *jsdisp)
+static inline void set_jsdisp(vdisp_t *vdisp, jsdisp_t *jsdisp)
 {
     vdisp->u.jsdisp = jsdisp;
     vdisp->flags = VDISP_JSDISP | VDISP_DISPEX;
@@ -130,7 +163,7 @@ static inline void set_jsdisp(vdisp_t *vdisp, DispatchEx *jsdisp)
 static inline void set_disp(vdisp_t *vdisp, IDispatch *disp)
 {
     IDispatchEx *dispex;
-    DispatchEx *jsdisp;
+    jsdisp_t *jsdisp;
     HRESULT hres;
 
     jsdisp = iface_to_jsdisp((IUnknown*)disp);
@@ -152,12 +185,12 @@ static inline void set_disp(vdisp_t *vdisp, IDispatch *disp)
     vdisp->flags = 0;
 }
 
-static inline DispatchEx *get_jsdisp(vdisp_t *vdisp)
+static inline jsdisp_t *get_jsdisp(vdisp_t *vdisp)
 {
     return is_jsdisp(vdisp) ? vdisp->u.jsdisp : NULL;
 }
 
-typedef HRESULT (*builtin_invoke_t)(script_ctx_t*,vdisp_t*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
+typedef HRESULT (*builtin_invoke_t)(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*);
 
 typedef struct {
     const WCHAR *name;
@@ -170,12 +203,15 @@ typedef struct {
     builtin_prop_t value_prop;
     DWORD props_cnt;
     const builtin_prop_t *props;
-    void (*destructor)(DispatchEx*);
-    void (*on_put)(DispatchEx*,const WCHAR*);
+    void (*destructor)(jsdisp_t*);
+    void (*on_put)(jsdisp_t*,const WCHAR*);
+    unsigned (*idx_length)(jsdisp_t*);
+    HRESULT (*idx_get)(jsdisp_t*,unsigned,jsval_t*);
+    HRESULT (*idx_put)(jsdisp_t*,unsigned,jsval_t);
 } builtin_info_t;
 
-struct DispatchEx {
-    const IDispatchExVtbl  *lpIDispatchExVtbl;
+struct jsdisp_t {
+    IDispatchEx IDispatchEx_iface;
 
     LONG ref;
 
@@ -184,58 +220,98 @@ struct DispatchEx {
     dispex_prop_t *props;
     script_ctx_t *ctx;
 
-    DispatchEx *prototype;
+    jsdisp_t *prototype;
 
     const builtin_info_t *builtin_info;
 };
 
-#define _IDispatchEx_(x) ((IDispatchEx*) &(x)->lpIDispatchExVtbl)
+static inline IDispatch *to_disp(jsdisp_t *jsdisp)
+{
+    return (IDispatch*)&jsdisp->IDispatchEx_iface;
+}
+
+jsdisp_t *as_jsdisp(IDispatch*) DECLSPEC_HIDDEN;
+jsdisp_t *to_jsdisp(IDispatch*) DECLSPEC_HIDDEN;
+void jsdisp_free(jsdisp_t*) DECLSPEC_HIDDEN;
+
+#ifndef TRACE_REFCNT
+
+/*
+ * We do a lot of refcount calls during script execution, so having an inline
+ * version is a nice perf win. Define TRACE_REFCNT macro when debugging
+ * refcount bugs to have traces. Also, since jsdisp_t is not thread safe anyways,
+ * there is no point in using atomic operations.
+ */
+static inline jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp)
+{
+    jsdisp->ref++;
+    return jsdisp;
+}
 
-static inline void jsdisp_release(DispatchEx *jsdisp)
+static inline void jsdisp_release(jsdisp_t *jsdisp)
 {
-    IDispatchEx_Release(_IDispatchEx_(jsdisp));
+    if(!--jsdisp->ref)
+        jsdisp_free(jsdisp);
 }
 
-HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,DispatchEx*,DispatchEx**);
-HRESULT init_dispex(DispatchEx*,script_ctx_t*,const builtin_info_t*,DispatchEx*);
-HRESULT init_dispex_from_constr(DispatchEx*,script_ctx_t*,const builtin_info_t*,DispatchEx*);
-
-HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
-HRESULT jsdisp_call_value(DispatchEx*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
-HRESULT jsdisp_call(DispatchEx*,DISPID,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
-HRESULT jsdisp_call_name(DispatchEx*,const WCHAR*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
-HRESULT disp_propget(script_ctx_t*,IDispatch*,DISPID,VARIANT*,jsexcept_t*,IServiceProvider*);
-HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,VARIANT*,jsexcept_t*,IServiceProvider*);
-HRESULT jsdisp_propget(DispatchEx*,DISPID,VARIANT*,jsexcept_t*,IServiceProvider*);
-HRESULT jsdisp_propput_name(DispatchEx*,const WCHAR*,VARIANT*,jsexcept_t*,IServiceProvider*);
-HRESULT jsdisp_propput_const(DispatchEx*,const WCHAR*,VARIANT*);
-HRESULT jsdisp_propput_idx(DispatchEx*,DWORD,VARIANT*,jsexcept_t*,IServiceProvider*);
-HRESULT jsdisp_propget_name(DispatchEx*,LPCWSTR,VARIANT*,jsexcept_t*,IServiceProvider*);
-HRESULT jsdisp_get_idx(DispatchEx*,DWORD,VARIANT*,jsexcept_t*,IServiceProvider*);
-HRESULT jsdisp_get_id(DispatchEx*,const WCHAR*,DWORD,DISPID*);
-HRESULT jsdisp_delete_idx(DispatchEx*,DWORD);
+#else
+
+jsdisp_t *jsdisp_addref(jsdisp_t*) DECLSPEC_HIDDEN;
+void jsdisp_release(jsdisp_t*) DECLSPEC_HIDDEN;
+
+#endif
+
+HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN;
+HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN;
+
+HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
+HRESULT disp_call_value(script_ctx_t*,IDispatch*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
+HRESULT jsdisp_call_value(jsdisp_t*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
+HRESULT jsdisp_call(jsdisp_t*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
+HRESULT jsdisp_call_name(jsdisp_t*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
+HRESULT disp_propget(script_ctx_t*,IDispatch*,DISPID,jsval_t*) DECLSPEC_HIDDEN;
+HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,jsval_t) DECLSPEC_HIDDEN;
+HRESULT jsdisp_propget(jsdisp_t*,DISPID,jsval_t*) DECLSPEC_HIDDEN;
+HRESULT jsdisp_propput(jsdisp_t*,const WCHAR*,DWORD,jsval_t) DECLSPEC_HIDDEN;
+HRESULT jsdisp_propput_name(jsdisp_t*,const WCHAR*,jsval_t) DECLSPEC_HIDDEN;
+HRESULT jsdisp_propput_const(jsdisp_t*,const WCHAR*,jsval_t) DECLSPEC_HIDDEN;
+HRESULT jsdisp_propput_dontenum(jsdisp_t*,const WCHAR*,jsval_t) DECLSPEC_HIDDEN;
+HRESULT jsdisp_propput_idx(jsdisp_t*,DWORD,jsval_t) DECLSPEC_HIDDEN;
+HRESULT jsdisp_propget_name(jsdisp_t*,LPCWSTR,jsval_t*) DECLSPEC_HIDDEN;
+HRESULT jsdisp_get_idx(jsdisp_t*,DWORD,jsval_t*) DECLSPEC_HIDDEN;
+HRESULT jsdisp_get_id(jsdisp_t*,const WCHAR*,DWORD,DISPID*) DECLSPEC_HIDDEN;
+HRESULT disp_delete(IDispatch*,DISPID,BOOL*) DECLSPEC_HIDDEN;
+HRESULT disp_delete_name(script_ctx_t*,IDispatch*,jsstr_t*,BOOL*);
+HRESULT jsdisp_delete_idx(jsdisp_t*,DWORD) DECLSPEC_HIDDEN;
+HRESULT jsdisp_is_own_prop(jsdisp_t*,const WCHAR*,BOOL*) DECLSPEC_HIDDEN;
+HRESULT jsdisp_is_enumerable(jsdisp_t*,const WCHAR*,BOOL*) DECLSPEC_HIDDEN;
 
 HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD,
-        DispatchEx*,DispatchEx**);
-HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
-
-HRESULT throw_eval_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
-HRESULT throw_generic_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
-HRESULT throw_range_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
-HRESULT throw_reference_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
-HRESULT throw_regexp_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
-HRESULT throw_syntax_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
-HRESULT throw_type_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
-HRESULT throw_uri_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
-
-HRESULT create_object(script_ctx_t*,DispatchEx*,DispatchEx**);
-HRESULT create_math(script_ctx_t*,DispatchEx**);
-HRESULT create_array(script_ctx_t*,DWORD,DispatchEx**);
-HRESULT create_regexp(script_ctx_t*,const WCHAR *,int,DWORD,DispatchEx**);
-HRESULT create_regexp_var(script_ctx_t*,VARIANT*,VARIANT*,DispatchEx**);
-HRESULT create_string(script_ctx_t*,const WCHAR*,DWORD,DispatchEx**);
-HRESULT create_bool(script_ctx_t*,VARIANT_BOOL,DispatchEx**);
-HRESULT create_number(script_ctx_t*,VARIANT*,DispatchEx**);
+        jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_builtin_constructor(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD,
+        jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
+HRESULT Function_invoke(jsdisp_t*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
+
+HRESULT throw_eval_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN;
+HRESULT throw_generic_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN;
+HRESULT throw_range_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN;
+HRESULT throw_reference_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN;
+HRESULT throw_regexp_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN;
+HRESULT throw_syntax_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN;
+HRESULT throw_type_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN;
+HRESULT throw_uri_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN;
+
+HRESULT create_object(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_math(script_ctx_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_array(script_ctx_t*,DWORD,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_regexp(script_ctx_t*,jsstr_t*,DWORD,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_regexp_var(script_ctx_t*,jsval_t,jsval_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_string(script_ctx_t*,jsstr_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_bool(script_ctx_t*,BOOL,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_number(script_ctx_t*,double,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_vbarray(script_ctx_t*,SAFEARRAY*,jsdisp_t**) DECLSPEC_HIDDEN;
 
 typedef enum {
     NO_HINT,
@@ -243,14 +319,20 @@ typedef enum {
     HINT_NUMBER
 } hint_t;
 
-HRESULT to_primitive(script_ctx_t*,VARIANT*,jsexcept_t*,VARIANT*, hint_t);
-HRESULT to_boolean(VARIANT*,VARIANT_BOOL*);
-HRESULT to_number(script_ctx_t*,VARIANT*,jsexcept_t*,VARIANT*);
-HRESULT to_integer(script_ctx_t*,VARIANT*,jsexcept_t*,VARIANT*);
-HRESULT to_int32(script_ctx_t*,VARIANT*,jsexcept_t*,INT*);
-HRESULT to_uint32(script_ctx_t*,VARIANT*,jsexcept_t*,DWORD*);
-HRESULT to_string(script_ctx_t*,VARIANT*,jsexcept_t*,BSTR*);
-HRESULT to_object(script_ctx_t*,VARIANT*,IDispatch**);
+HRESULT to_primitive(script_ctx_t*,jsval_t,jsval_t*, hint_t) DECLSPEC_HIDDEN;
+HRESULT to_boolean(jsval_t,BOOL*) DECLSPEC_HIDDEN;
+HRESULT to_number(script_ctx_t*,jsval_t,double*) DECLSPEC_HIDDEN;
+HRESULT to_integer(script_ctx_t*,jsval_t,double*) DECLSPEC_HIDDEN;
+HRESULT to_int32(script_ctx_t*,jsval_t,INT*) DECLSPEC_HIDDEN;
+HRESULT to_uint32(script_ctx_t*,jsval_t,UINT32*) DECLSPEC_HIDDEN;
+HRESULT to_string(script_ctx_t*,jsval_t,jsstr_t**) DECLSPEC_HIDDEN;
+HRESULT to_object(script_ctx_t*,jsval_t,IDispatch**) DECLSPEC_HIDDEN;
+
+HRESULT variant_change_type(script_ctx_t*,VARIANT*,VARIANT*,VARTYPE) DECLSPEC_HIDDEN;
+
+HRESULT decode_source(WCHAR*) DECLSPEC_HIDDEN;
+
+HRESULT double_to_string(double,jsstr_t**) DECLSPEC_HIDDEN;
 
 typedef struct named_item_t {
     IDispatch *disp;
@@ -260,10 +342,40 @@ typedef struct named_item_t {
     struct named_item_t *next;
 } named_item_t;
 
+typedef struct _cc_var_t cc_var_t;
+
+typedef struct {
+    cc_var_t *vars;
+} cc_ctx_t;
+
+void release_cc(cc_ctx_t*) DECLSPEC_HIDDEN;
+
+typedef struct {
+    IServiceProvider IServiceProvider_iface;
+
+    LONG ref;
+
+    script_ctx_t *ctx;
+} JSCaller;
+
+#include "jsval.h"
+
+typedef struct {
+    EXCEPINFO ei;
+    jsval_t val;
+} jsexcept_t;
+
+typedef struct {
+    unsigned index;
+    unsigned length;
+} match_result_t;
+
 struct _script_ctx_t {
     LONG ref;
 
     SCRIPTSTATE state;
+    IActiveScript *active_script;
+
     exec_ctx_t *exec_ctx;
     named_item_t *named_items;
     IActiveScriptSite *site;
@@ -271,83 +383,77 @@ struct _script_ctx_t {
     DWORD safeopt;
     DWORD version;
     LCID lcid;
+    cc_ctx_t *cc;
+    JSCaller *jscaller;
+    jsexcept_t ei;
 
-    jsheap_t tmp_heap;
+    heap_pool_t tmp_heap;
 
     IDispatch *host_global;
 
-    BSTR last_match;
+    jsstr_t *last_match;
+    match_result_t match_parens[9];
     DWORD last_match_index;
     DWORD last_match_length;
 
-    DispatchEx *global;
-    DispatchEx *function_constr;
-    DispatchEx *activex_constr;
-    DispatchEx *array_constr;
-    DispatchEx *bool_constr;
-    DispatchEx *date_constr;
-    DispatchEx *error_constr;
-    DispatchEx *eval_error_constr;
-    DispatchEx *range_error_constr;
-    DispatchEx *reference_error_constr;
-    DispatchEx *regexp_error_constr;
-    DispatchEx *syntax_error_constr;
-    DispatchEx *type_error_constr;
-    DispatchEx *uri_error_constr;
-    DispatchEx *number_constr;
-    DispatchEx *object_constr;
-    DispatchEx *regexp_constr;
-    DispatchEx *string_constr;
+    jsdisp_t *global;
+    jsdisp_t *function_constr;
+    jsdisp_t *activex_constr;
+    jsdisp_t *array_constr;
+    jsdisp_t *bool_constr;
+    jsdisp_t *date_constr;
+    jsdisp_t *error_constr;
+    jsdisp_t *eval_error_constr;
+    jsdisp_t *range_error_constr;
+    jsdisp_t *reference_error_constr;
+    jsdisp_t *regexp_error_constr;
+    jsdisp_t *syntax_error_constr;
+    jsdisp_t *type_error_constr;
+    jsdisp_t *uri_error_constr;
+    jsdisp_t *number_constr;
+    jsdisp_t *object_constr;
+    jsdisp_t *regexp_constr;
+    jsdisp_t *string_constr;
+    jsdisp_t *vbarray_constr;
 };
 
-void script_release(script_ctx_t*);
+void script_release(script_ctx_t*) DECLSPEC_HIDDEN;
+void clear_ei(script_ctx_t*) DECLSPEC_HIDDEN;
 
 static inline void script_addref(script_ctx_t *ctx)
 {
     ctx->ref++;
 }
 
-HRESULT init_global(script_ctx_t*);
-HRESULT init_function_constr(script_ctx_t*,DispatchEx*);
-HRESULT create_object_prototype(script_ctx_t*,DispatchEx**);
+HRESULT init_global(script_ctx_t*) DECLSPEC_HIDDEN;
+HRESULT init_function_constr(script_ctx_t*,jsdisp_t*) DECLSPEC_HIDDEN;
+HRESULT create_object_prototype(script_ctx_t*,jsdisp_t**) DECLSPEC_HIDDEN;
 
-HRESULT create_activex_constr(script_ctx_t*,DispatchEx**);
-HRESULT create_array_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
-HRESULT create_bool_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
-HRESULT create_date_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
-HRESULT init_error_constr(script_ctx_t*,DispatchEx*);
-HRESULT create_number_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
-HRESULT create_object_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
-HRESULT create_regexp_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
-HRESULT create_string_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
+HRESULT create_activex_constr(script_ctx_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_array_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_bool_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_date_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT init_error_constr(script_ctx_t*,jsdisp_t*) DECLSPEC_HIDDEN;
+HRESULT create_number_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_object_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_regexp_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_string_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
+HRESULT create_vbarray_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
 
-IUnknown *create_ax_site(script_ctx_t*);
-
-typedef struct {
-    const WCHAR *str;
-    DWORD len;
-} match_result_t;
+IUnknown *create_ax_site(script_ctx_t*) DECLSPEC_HIDDEN;
+HRESULT create_jscaller(script_ctx_t*) DECLSPEC_HIDDEN;
 
 #define REM_CHECK_GLOBAL   0x0001
 #define REM_RESET_INDEX    0x0002
 #define REM_NO_CTX_UPDATE  0x0004
-HRESULT regexp_match_next(script_ctx_t*,DispatchEx*,DWORD,const WCHAR*,DWORD,const WCHAR**,match_result_t**,
-        DWORD*,DWORD*,match_result_t*);
-HRESULT regexp_match(script_ctx_t*,DispatchEx*,const WCHAR*,DWORD,BOOL,match_result_t**,DWORD*);
-HRESULT parse_regexp_flags(const WCHAR*,DWORD,DWORD*);
-HRESULT regexp_string_match(script_ctx_t*,DispatchEx*,BSTR,VARIANT*,jsexcept_t*);
-
-static inline VARIANT *get_arg(DISPPARAMS *dp, DWORD i)
-{
-    return dp->rgvarg + dp->cArgs-i-1;
-}
-
-static inline DWORD arg_cnt(const DISPPARAMS *dp)
-{
-    return dp->cArgs - dp->cNamedArgs;
-}
-
-static inline BOOL is_class(DispatchEx *jsdisp, jsclass_t class)
+#define REM_ALLOC_RESULT   0x0008
+#define REM_NO_PARENS      0x0010
+struct match_state_t;
+HRESULT regexp_match_next(script_ctx_t*,jsdisp_t*,DWORD,jsstr_t*,struct match_state_t**) DECLSPEC_HIDDEN;
+HRESULT parse_regexp_flags(const WCHAR*,DWORD,DWORD*) DECLSPEC_HIDDEN;
+HRESULT regexp_string_match(script_ctx_t*,jsdisp_t*,jsstr_t*,jsval_t*) DECLSPEC_HIDDEN;
+
+static inline BOOL is_class(jsdisp_t *jsdisp, jsclass_t class)
 {
     return jsdisp->builtin_info->class == class;
 }
@@ -357,66 +463,77 @@ static inline BOOL is_vclass(vdisp_t *vdisp, jsclass_t class)
     return is_jsdisp(vdisp) && is_class(vdisp->u.jsdisp, class);
 }
 
-static inline BOOL is_num_vt(enum VARENUM vt)
-{
-    return vt == VT_I4 || vt == VT_R8;
-}
-
-static inline DOUBLE num_val(const VARIANT *v)
-{
-    return V_VT(v) == VT_I4 ? V_I4(v) : V_R8(v);
-}
-
-static inline void num_set_val(VARIANT *v, DOUBLE d)
-{
-    if(d == (DOUBLE)(INT)d) {
-        V_VT(v) = VT_I4;
-        V_I4(v) = d;
-    }else {
-        V_VT(v) = VT_R8;
-        V_R8(v) = d;
-    }
-}
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
 
-static inline void num_set_nan(VARIANT *v)
-{
-    V_VT(v) = VT_R8;
-#ifdef NAN
-    V_R8(v) = NAN;
-#else
-    V_UI8(v) = (ULONGLONG)0x7ff80000<<32;
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
 #endif
-}
 
-static inline DOUBLE ret_nan(void)
+static inline BOOL is_int32(double d)
 {
-    VARIANT v;
-    num_set_nan(&v);
-    return V_R8(&v);
+    return INT32_MIN <= d && d <= INT32_MAX && (double)(int)d == d;
 }
 
-static inline void num_set_inf(VARIANT *v, BOOL positive)
+static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags)
 {
-    V_VT(v) = VT_R8;
-#ifdef INFINITY
-    V_R8(v) = positive ? INFINITY : -INFINITY;
-#else
-    V_UI8(v) = (ULONGLONG)0x7ff00000<<32;
-    if(!positive)
-        V_R8(v) = -V_R8(v);
-#endif
+    return (ctx->version << 28) | flags;
 }
 
-static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags)
+#define FACILITY_JSCRIPT 10
+
+#define MAKE_JSERROR(code) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_JSCRIPT, code)
+
+#define JS_E_TO_PRIMITIVE            MAKE_JSERROR(IDS_TO_PRIMITIVE)
+#define JS_E_INVALIDARG              MAKE_JSERROR(IDS_INVALID_CALL_ARG)
+#define JS_E_SUBSCRIPT_OUT_OF_RANGE  MAKE_JSERROR(IDS_SUBSCRIPT_OUT_OF_RANGE)
+#define JS_E_OBJECT_REQUIRED         MAKE_JSERROR(IDS_OBJECT_REQUIRED)
+#define JS_E_CANNOT_CREATE_OBJ       MAKE_JSERROR(IDS_CREATE_OBJ_ERROR)
+#define JS_E_INVALID_PROPERTY        MAKE_JSERROR(IDS_NO_PROPERTY)
+#define JS_E_INVALID_ACTION          MAKE_JSERROR(IDS_UNSUPPORTED_ACTION)
+#define JS_E_MISSING_ARG             MAKE_JSERROR(IDS_ARG_NOT_OPT)
+#define JS_E_SYNTAX                  MAKE_JSERROR(IDS_SYNTAX_ERROR)
+#define JS_E_MISSING_SEMICOLON       MAKE_JSERROR(IDS_SEMICOLON)
+#define JS_E_MISSING_LBRACKET        MAKE_JSERROR(IDS_LBRACKET)
+#define JS_E_MISSING_RBRACKET        MAKE_JSERROR(IDS_RBRACKET)
+#define JS_E_INVALID_CHAR            MAKE_JSERROR(IDS_INVALID_CHAR)
+#define JS_E_UNTERMINATED_STRING     MAKE_JSERROR(IDS_UNTERMINATED_STR)
+#define JS_E_MISPLACED_RETURN        MAKE_JSERROR(IDS_MISPLACED_RETURN)
+#define JS_E_INVALID_BREAK           MAKE_JSERROR(IDS_INVALID_BREAK)
+#define JS_E_INVALID_CONTINUE        MAKE_JSERROR(IDS_INVALID_CONTINUE)
+#define JS_E_LABEL_REDEFINED         MAKE_JSERROR(IDS_LABEL_REDEFINED)
+#define JS_E_LABEL_NOT_FOUND         MAKE_JSERROR(IDS_LABEL_NOT_FOUND)
+#define JS_E_DISABLED_CC             MAKE_JSERROR(IDS_DISABLED_CC)
+#define JS_E_FUNCTION_EXPECTED       MAKE_JSERROR(IDS_NOT_FUNC)
+#define JS_E_DATE_EXPECTED           MAKE_JSERROR(IDS_NOT_DATE)
+#define JS_E_NUMBER_EXPECTED         MAKE_JSERROR(IDS_NOT_NUM)
+#define JS_E_OBJECT_EXPECTED         MAKE_JSERROR(IDS_OBJECT_EXPECTED)
+#define JS_E_ILLEGAL_ASSIGN          MAKE_JSERROR(IDS_ILLEGAL_ASSIGN)
+#define JS_E_UNDEFINED_VARIABLE      MAKE_JSERROR(IDS_UNDEFINED)
+#define JS_E_BOOLEAN_EXPECTED        MAKE_JSERROR(IDS_NOT_BOOL)
+#define JS_E_VBARRAY_EXPECTED        MAKE_JSERROR(IDS_NOT_VBARRAY)
+#define JS_E_INVALID_DELETE          MAKE_JSERROR(IDS_INVALID_DELETE)
+#define JS_E_JSCRIPT_EXPECTED        MAKE_JSERROR(IDS_JSCRIPT_EXPECTED)
+#define JS_E_REGEXP_SYNTAX           MAKE_JSERROR(IDS_REGEXP_SYNTAX_ERROR)
+#define JS_E_INVALID_URI_CODING      MAKE_JSERROR(IDS_URI_INVALID_CODING)
+#define JS_E_INVALID_URI_CHAR        MAKE_JSERROR(IDS_URI_INVALID_CHAR)
+#define JS_E_FRACTION_DIGITS_OUT_OF_RANGE MAKE_JSERROR(IDS_FRACTION_DIGITS_OUT_OF_RANGE)
+#define JS_E_PRECISION_OUT_OF_RANGE  MAKE_JSERROR(IDS_PRECISION_OUT_OF_RANGE)
+#define JS_E_INVALID_LENGTH          MAKE_JSERROR(IDS_INVALID_LENGTH)
+#define JS_E_ARRAY_EXPECTED          MAKE_JSERROR(IDS_ARRAY_EXPECTED)
+
+static inline BOOL is_jscript_error(HRESULT hres)
 {
-    return (ctx->version << 28) | flags;
+    return HRESULT_FACILITY(hres) == FACILITY_JSCRIPT;
 }
 
-const char *debugstr_variant(const VARIANT*);
+const char *debugstr_variant(const VARIANT*) DECLSPEC_HIDDEN;
+const char *debugstr_jsval(const jsval_t) DECLSPEC_HIDDEN;
 
-HRESULT WINAPI JScriptFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**);
+HRESULT create_jscript_object(BOOL,REFIID,void**) DECLSPEC_HIDDEN;
 
-extern LONG module_ref;
+extern LONG module_ref DECLSPEC_HIDDEN;
 
 static inline void lock_module(void)
 {
@@ -427,40 +544,3 @@ static inline void unlock_module(void)
 {
     InterlockedDecrement(&module_ref);
 }
-
-static inline void *heap_alloc(size_t len)
-{
-    return HeapAlloc(GetProcessHeap(), 0, len);
-}
-
-static inline void *heap_alloc_zero(size_t len)
-{
-    return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
-}
-
-static inline void *heap_realloc(void *mem, size_t len)
-{
-    return HeapReAlloc(GetProcessHeap(), 0, mem, len);
-}
-
-static inline BOOL heap_free(void *mem)
-{
-    return HeapFree(GetProcessHeap(), 0, mem);
-}
-
-static inline LPWSTR heap_strdupW(LPCWSTR str)
-{
-    LPWSTR ret = NULL;
-
-    if(str) {
-        DWORD size;
-
-        size = (strlenW(str)+1)*sizeof(WCHAR);
-        ret = heap_alloc(size);
-        memcpy(ret, str, size);
-    }
-
-    return ret;
-}
-
-#define DEFINE_THIS(cls,ifc,iface) ((cls*)((BYTE*)(iface)-offsetof(cls,lp ## ifc ## Vtbl)))
diff --git a/reactos/dll/win32/jscript/jscript.inf b/reactos/dll/win32/jscript/jscript.inf
deleted file mode 100644 (file)
index 9f683ed..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-[version]
-Signature="$CHICAGO$"
-
-
-[RegisterDll]
-AddReg=Classes.Reg
-
-
-[UnregisterDll]
-DelReg=Classes.Reg
-
-
-[Classes.Reg]
-HKCR,"CLSID\%CLSID_JScript%",,,"JScript Language"
-HKCR,"CLSID\%CLSID_JScript%\Implemented Categories\%CATID_ActiveScript%",,16
-HKCR,"CLSID\%CLSID_JScript%\Implemented Categories\%CATID_ActiveScriptParse%",,16
-HKCR,"CLSID\%CLSID_JScript%\InprocServer32",,,"%MODULE%"
-HKCR,"CLSID\%CLSID_JScript%\InprocServer32","ThreadingModel",,"Both"
-HKCR,"CLSID\%CLSID_JScript%\OLEScript",,16
-HKCR,"CLSID\%CLSID_JScript%\ProgID",,,"JScript"
-
-HKCR,"CLSID\%CLSID_JScriptAuthor%",,,"JScript Language Authoring"
-HKCR,"CLSID\%CLSID_JScriptAuthor%\Implemented Categories\%CATID_ActiveScriptAuthor%",,16
-HKCR,"CLSID\%CLSID_JScriptAuthor%\InprocServer32",,,"%MODULE%"
-HKCR,"CLSID\%CLSID_JScriptAuthor%\InprocServer32","ThreadingModel",,"Both"
-HKCR,"CLSID\%CLSID_JScriptAuthor%\OLEScript",,16
-HKCR,"CLSID\%CLSID_JScriptAuthor%\ProgID",,,"JScript Author"
-
-HKCR,"CLSID\%CLSID_JScriptEncode%",,,"JScript Language Encoding"
-HKCR,"CLSID\%CLSID_JScriptEncode%\Implemented Categories\%CATID_ActiveScript%",,16
-HKCR,"CLSID\%CLSID_JScriptEncode%\Implemented Categories\%CATID_ActiveScriptParse%",,16
-HKCR,"CLSID\%CLSID_JScriptEncode%\Implemented Categories\%CATID_ActiveScriptEncode%",,16
-HKCR,"CLSID\%CLSID_JScriptEncode%\InprocServer32",,,"%MODULE%"
-HKCR,"CLSID\%CLSID_JScriptEncode%\InprocServer32","ThreadingModel",,"Both"
-HKCR,"CLSID\%CLSID_JScriptEncode%\OLEScript",,16
-HKCR,"CLSID\%CLSID_JScriptEncode%\ProgID",,,"JScript.Encode"
-
-HKCR,"Component Categories\%CATID_ActiveScriptAuthor%","409",,"Active Scripting Engine with Authoring"
-HKCR,"Component Categories\%CATID_ActiveScript%","409",,"Active Scripting Engine"
-HKCR,"Component Categories\%CATID_ActiveScriptParse%","409",,"Active Scripting Engine with Parsing"
-HKCR,"Component Categories\%CATID_ActiveScriptEncode%","409",,"Active Scripting Engine with Encoding"
-
-HKCR,"ECMAScript",,,"JScript Language"
-HKCR,"ECMAScript\CLSID",,,"%CLSID_JScript%"
-HKCR,"ECMAScript\OLEScript",,16
-
-HKCR,"JavaScript",,,"JScript Language"
-HKCR,"JavaScript\CLSID",,,"%CLSID_JScript%"
-HKCR,"JavaScript\OLEScript",,16
-
-HKCR,"JavaScript Author",,,"JScript Language Authoring"
-HKCR,"JavaScript Author\CLSID",,,"%CLSID_JScriptAuthor%"
-HKCR,"JavaScript Author\OLEScript",,16
-
-HKCR,"JavaScript1.1",,,"JScript Language"
-HKCR,"JavaScript1.1\CLSID",,,"%CLSID_JScript%"
-HKCR,"JavaScript1.1\OLEScript",,16
-
-HKCR,"JavaScript1.1 Author",,,"JScript Language Authoring"
-HKCR,"JavaScript1.1 Author\CLSID",,,"%CLSID_JScriptAuthor%"
-HKCR,"JavaScript1.1 Author\OLEScript",,16
-
-HKCR,"JavaScript1.2",,,"JScript Language"
-HKCR,"JavaScript1.2\CLSID",,,"%CLSID_JScript%"
-HKCR,"JavaScript1.2\OLEScript",,16
-
-HKCR,"JavaScript1.2 Author",,,"JScript Language Authoring"
-HKCR,"JavaScript1.2 Author\CLSID",,,"%CLSID_JScriptAuthor%"
-HKCR,"JavaScript1.2 Author\OLEScript",,16
-
-HKCR,"JavaScript1.3",,,"JScript Language"
-HKCR,"JavaScript1.3\CLSID",,,"%CLSID_JScript%"
-HKCR,"JavaScript1.3\OLEScript",,16
-
-HKCR,"JScript",,,"JScript Language"
-HKCR,"JScript\CLSID",,,"%CLSID_JScript%"
-HKCR,"JScript\OLEScript",,16
-
-HKCR,"JScript Author",,,"JScript Language Authoring"
-HKCR,"JScript Author\CLSID",,,"%CLSID_JScriptAuthor%"
-HKCR,"JScript Author\OLEScript",,16
-
-HKCR,"JScript.Encode",,,"JScript Language Encoding"
-HKCR,"JScript.Encode\CLSID",,,"%CLSID_JScriptEncode%"
-HKCR,"JScript.Encode\OLEScript",,16
-
-HKCR,"LiveScript",,,"JScript Language"
-HKCR,"LiveScript\CLSID",,,"%CLSID_JScript%"
-HKCR,"LiveScript\OLEScript",,16
-
-HKCR,"LiveScript Author",,,"JScript Language Authoring"
-HKCR,"LiveScript Author\CLSID",,,"%CLSID_JScriptAuthor%"
-HKCR,"LiveScript Author\OLEScript",,16
-
-
-[Strings]
-MODULE="jscript.dll"
diff --git a/reactos/dll/win32/jscript/jscript.rc b/reactos/dll/win32/jscript/jscript.rc
new file mode 100644 (file)
index 0000000..eb8e158
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2009 Piotr Caban
+ *
+ * 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
+ */
+
+#include "resource.h"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+    IDS_TO_PRIMITIVE        "Error converting object to primitive type"
+    IDS_INVALID_CALL_ARG    "Invalid procedure call or argument"
+    IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range"
+    IDS_OBJECT_REQUIRED     "Object required"
+    IDS_CREATE_OBJ_ERROR    "Automation server can't create object"
+    IDS_NO_PROPERTY         "Object doesn't support this property or method"
+    IDS_UNSUPPORTED_ACTION  "Object doesn't support this action"
+    IDS_ARG_NOT_OPT         "Argument not optional"
+    IDS_SYNTAX_ERROR        "Syntax error"
+    IDS_SEMICOLON           "Expected ';'"
+    IDS_LBRACKET            "Expected '('"
+    IDS_RBRACKET            "Expected ')'"
+    IDS_INVALID_CHAR        "Invalid character"
+    IDS_UNTERMINATED_STR    "Unterminated string constant"
+    IDS_MISPLACED_RETURN    "'return' statement outside of function"
+    IDS_INVALID_BREAK       "Can't have 'break' outside of loop"
+    IDS_INVALID_CONTINUE    "Can't have 'continue' outside of loop"
+    IDS_LABEL_REDEFINED     "Label redefined"
+    IDS_LABEL_NOT_FOUND     "Label not found"
+    IDS_DISABLED_CC         "Conditional compilation is turned off"
+    IDS_NOT_FUNC            "Function expected"
+    IDS_NOT_DATE            "'[object]' is not a date object"
+    IDS_NOT_NUM             "Number expected"
+    IDS_OBJECT_EXPECTED     "Object expected"
+    IDS_ILLEGAL_ASSIGN      "Illegal assignment"
+    IDS_UNDEFINED           "'|' is undefined"
+    IDS_NOT_BOOL            "Boolean object expected"
+    IDS_INVALID_DELETE      "Cannot delete '|'"
+    IDS_NOT_VBARRAY         "VBArray object expected"
+    IDS_JSCRIPT_EXPECTED    "JScript object expected"
+    IDS_REGEXP_SYNTAX_ERROR "Syntax error in regular expression"
+    IDS_URI_INVALID_CODING  "URI to be decoded is incorrect"
+    IDS_URI_INVALID_CHAR    "URI to be encoded contains invalid characters"
+    IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range"
+    IDS_PRECISION_OUT_OF_RANGE "Precision is out of range"
+    IDS_INVALID_LENGTH      "Array length must be a finite positive integer"
+    IDS_ARRAY_EXPECTED      "Array object expected"
+}
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+/* @makedep: jscript.rgs */
+2 WINE_REGISTRY jscript.rgs
+
+3 WINE_REGISTRY jscript_classes.rgs
+
+#define WINE_FILEDESCRIPTION_STR "Wine JScript"
+#define WINE_FILENAME_STR "jscript.dll"
+#define WINE_FILEVERSION 5,7,7601,16982
+#define WINE_FILEVERSION_STR "5.8.7601.16982"
+#define WINE_PRODUCTVERSION 5,8,7601,16982
+#define WINE_PRODUCTVERSION_STR "5.8.7601.16982"
+
+#include "wine/wine_common_ver.rc"
diff --git a/reactos/dll/win32/jscript/jscript.rgs b/reactos/dll/win32/jscript/jscript.rgs
new file mode 100644 (file)
index 0000000..b4da2b5
--- /dev/null
@@ -0,0 +1,123 @@
+HKCR
+{
+    NoRemove CLSID
+    {
+        '{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}'
+        {
+            'Implemented Categories'
+            {
+                '{f0b7a1a1-9847-11cf-8f20-00805f2cd064}'
+                '{f0b7a1a2-9847-11cf-8f20-00805f2cd064}'
+            }
+            OLEScript
+        }
+        '{F414C261-6AC0-11CF-B6D1-00AA00BBBB58}'
+        {
+            'Implemented Categories'
+            {
+                '{0aee2a92-bcbb-11d0-8c72-00c04fc2b085}'
+            }
+            OLEScript
+        }
+        '{F414C262-6AC0-11CF-B6D1-00AA00BBBB58}'
+        {
+            'Implemented Categories'
+            {
+                '{f0b7a1a1-9847-11cf-8f20-00805f2cd064}'
+                '{f0b7a1a2-9847-11cf-8f20-00805f2cd064}'
+                '{f0b7a1a3-9847-11cf-8f20-00805f2cd064}'
+            }
+            OLEScript
+        }
+    }
+
+    NoRemove 'Component Categories'
+    {
+        ForceRemove '{f0b7a1a1-9847-11cf-8f20-00805f2cd064}'
+        {
+            val '409' = s 'Active Scripting Engine'
+        }
+        ForceRemove '{f0b7a1a2-9847-11cf-8f20-00805f2cd064}'
+        {
+            val '409' = s 'Active Scripting Engine with Parsing'
+        }
+        ForceRemove '{f0b7a1a3-9847-11cf-8f20-00805f2cd064}'
+        {
+            val '409' = s 'Active Scripting Engine with Encoding'
+        }
+        ForceRemove '{0aee2a92-bcbb-11d0-8c72-00c04fc2b085}'
+        {
+            val '409' = s 'Active Scripting Engine with Authoring'
+        }
+    }
+
+    'ECMAScript' = s 'JScript Language'
+    {
+        CLSID = s '{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}'
+        OLEScript
+    }
+    'JavaScript' = s 'JScript Language'
+    {
+        CLSID = s '{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}'
+        OLEScript
+    }
+    'JavaScript1.1' = s 'JScript Language'
+    {
+        CLSID = s '{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}'
+        OLEScript
+    }
+    'JavaScript1.2' = s 'JScript Language'
+    {
+        CLSID = s '{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}'
+        OLEScript
+    }
+    'JavaScript1.3' = s 'JScript Language'
+    {
+        CLSID = s '{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}'
+        OLEScript
+    }
+    'LiveScript' = s 'JScript Language'
+    {
+        CLSID = s '{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}'
+        OLEScript
+    }
+    'JScript'
+    {
+        OLEScript
+    }
+
+    'JScript Author'
+    {
+        OLEScript
+    }
+    'JavaScript Author' = s 'JScript Language Authoring'
+    {
+        CLSID = s '{F414C261-6AC0-11CF-B6D1-00AA00BBBB58}'
+        OLEScript
+    }
+    'JavaScript1.1 Author' = s 'JScript Language Authoring'
+    {
+        CLSID = s '{F414C261-6AC0-11CF-B6D1-00AA00BBBB58}'
+        OLEScript
+    }
+    'JavaScript1.2 Author' = s 'JScript Language Authoring'
+    {
+        CLSID = s '{F414C261-6AC0-11CF-B6D1-00AA00BBBB58}'
+        OLEScript
+    }
+    'LiveScript Author' = s 'JScript Language Authoring'
+    {
+        CLSID = s '{F414C261-6AC0-11CF-B6D1-00AA00BBBB58}'
+        OLEScript
+    }
+
+    'JScript.Encode'
+    {
+        OLEScript
+    }
+
+    ForceRemove JSFile = s 'JScript Script File'
+    {
+        ScriptEngine = s 'JScript'
+    }
+}
diff --git a/reactos/dll/win32/jscript/jscript_classes.idl b/reactos/dll/win32/jscript/jscript_classes.idl
new file mode 100644 (file)
index 0000000..d9f481e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010 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
+ */
+
+[
+    helpstring("JScript Language"),
+    threading(both),
+    progid("JScript"),
+    uuid(f414c260-6ac0-11cf-b6d1-00aa00bbbb58)
+]
+coclass JScript {}
+
+[
+    helpstring("JScript Language Authoring"),
+    threading(both),
+    progid("JScript Author"),
+    uuid(f414c261-6ac0-11cf-b6d1-00aa00bbbb58)
+]
+coclass JScriptAuthor {}
+
+[
+    helpstring("JScript Language Encoding"),
+    threading(both),
+    progid("JScript.Encode"),
+    uuid(f414c262-6ac0-11cf-b6d1-00aa00bbbb58)
+]
+coclass JScriptEncode {}
diff --git a/reactos/dll/win32/jscript/jscript_classes.rgs b/reactos/dll/win32/jscript/jscript_classes.rgs
new file mode 100644 (file)
index 0000000..ae671fc
--- /dev/null
@@ -0,0 +1,36 @@
+HKCR
+{
+    NoRemove Interface
+    {
+    }
+    NoRemove CLSID
+    {
+        '{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}' = s 'JScript Language'
+        {
+            InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' }
+            ProgId = s 'JScript'
+        }
+        '{F414C261-6AC0-11CF-B6D1-00AA00BBBB58}' = s 'JScript Language Authoring'
+        {
+            InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' }
+            ProgId = s 'JScript Author'
+        }
+        '{F414C262-6AC0-11CF-B6D1-00AA00BBBB58}' = s 'JScript Language Encoding'
+        {
+            InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' }
+            ProgId = s 'JScript.Encode'
+        }
+    }
+    'JScript' = s 'JScript Language'
+    {
+        CLSID = s '{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}'
+    }
+    'JScript Author' = s 'JScript Language Authoring'
+    {
+        CLSID = s '{F414C261-6AC0-11CF-B6D1-00AA00BBBB58}'
+    }
+    'JScript.Encode' = s 'JScript Language Encoding'
+    {
+        CLSID = s '{F414C262-6AC0-11CF-B6D1-00AA00BBBB58}'
+    }
+}
index 25556e5..cf07cbf 100644 (file)
@@ -25,6 +25,8 @@
 #include <activaut.h>
 #include <objsafe.h>
 #include <mshtmhst.h>
+#include <rpcproxy.h>
+#include <jscript_classes.h>
 
 #include <wine/debug.h>
 
@@ -32,13 +34,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 
 LONG module_ref = 0;
 
-static const CLSID CLSID_JScript =
-    {0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
-static const CLSID CLSID_JScriptAuthor =
-    {0xf414c261,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
-static const CLSID CLSID_JScriptEncode =
-    {0xf414c262,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
-
 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
 
 HINSTANCE jscript_hinstance;
@@ -88,6 +83,19 @@ static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock)
     return S_OK;
 }
 
+static HRESULT WINAPI JScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *outer,
+        REFIID riid, void **ppv)
+{
+    TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
+
+    if(outer) {
+        *ppv = NULL;
+        return CLASS_E_NOAGGREGATION;
+    }
+
+    return create_jscript_object(FALSE, riid, ppv);
+}
+
 static const IClassFactoryVtbl JScriptFactoryVtbl = {
     ClassFactory_QueryInterface,
     ClassFactory_AddRef,
@@ -98,6 +106,29 @@ static const IClassFactoryVtbl JScriptFactoryVtbl = {
 
 static IClassFactory JScriptFactory = { &JScriptFactoryVtbl };
 
+static HRESULT WINAPI JScriptEncodeFactory_CreateInstance(IClassFactory *iface, IUnknown *outer,
+        REFIID riid, void **ppv)
+{
+    TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
+
+    if(outer) {
+        *ppv = NULL;
+        return CLASS_E_NOAGGREGATION;
+    }
+
+    return create_jscript_object(TRUE, riid, ppv);
+}
+
+static const IClassFactoryVtbl JScriptEncodeFactoryVtbl = {
+    ClassFactory_QueryInterface,
+    ClassFactory_AddRef,
+    ClassFactory_Release,
+    JScriptEncodeFactory_CreateInstance,
+    ClassFactory_LockServer
+};
+
+static IClassFactory JScriptEncodeFactory = { &JScriptEncodeFactoryVtbl };
+
 /******************************************************************
  *              DllMain (jscript.@)
  */
@@ -105,14 +136,15 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
 {
     TRACE("(%p %d %p)\n", hInstDLL, fdwReason, lpv);
 
-    switch(fdwReason)
-    {
-    case DLL_WINE_PREATTACH:
-        return FALSE;  /* prefer native version */
+    switch(fdwReason) {
     case DLL_PROCESS_ATTACH:
         DisableThreadLibraryCalls(hInstDLL);
         jscript_hinstance = hInstDLL;
+        if(!init_strings())
+            return FALSE;
         break;
+    case DLL_PROCESS_DETACH:
+        free_strings();
     }
 
     return TRUE;
@@ -128,6 +160,11 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
         return IClassFactory_QueryInterface(&JScriptFactory, riid, ppv);
     }
 
+    if(IsEqualGUID(&CLSID_JScriptEncode, rclsid)) {
+        TRACE("(CLSID_JScriptEncode %s %p)\n", debugstr_guid(riid), ppv);
+        return IClassFactory_QueryInterface(&JScriptEncodeFactory, riid, ppv);
+    }
+
     FIXME("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
     return CLASS_E_CLASSNOTAVAILABLE;
 }
@@ -142,70 +179,13 @@ HRESULT WINAPI DllCanUnloadNow(void)
     return module_ref ? S_FALSE : S_OK;
 }
 
-/***********************************************************************
- *              register_inf
- */
-
-#define INF_SET_ID(id)             \
-    do                             \
-    {                              \
-        static CHAR name[] = #id;  \
-                                   \
-        pse[i].pszName = name;     \
-        clsids[i++] = &id;         \
-    } while (0)
-
-static HRESULT register_inf(BOOL doregister)
-{
-    HRESULT hres;
-    HMODULE hAdvpack;
-    HRESULT (WINAPI *pRegInstall)(HMODULE hm, LPCSTR pszSection, const STRTABLEA* pstTable);
-    STRTABLEA strtable;
-    STRENTRYA pse[7];
-    static CLSID const *clsids[7];
-    unsigned int i = 0;
-
-    static const WCHAR advpackW[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
-
-    INF_SET_ID(CLSID_JScript);
-    INF_SET_ID(CLSID_JScriptAuthor);
-    INF_SET_ID(CLSID_JScriptEncode);
-    INF_SET_ID(CATID_ActiveScript);
-    INF_SET_ID(CATID_ActiveScriptParse);
-    INF_SET_ID(CATID_ActiveScriptEncode);
-    INF_SET_ID(CATID_ActiveScriptAuthor);
-
-    for(i = 0; i < sizeof(pse)/sizeof(pse[0]); i++) {
-        pse[i].pszValue = HeapAlloc(GetProcessHeap(), 0, 39);
-        sprintf(pse[i].pszValue, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
-                clsids[i]->Data1, clsids[i]->Data2, clsids[i]->Data3, clsids[i]->Data4[0],
-                clsids[i]->Data4[1], clsids[i]->Data4[2], clsids[i]->Data4[3], clsids[i]->Data4[4],
-                clsids[i]->Data4[5], clsids[i]->Data4[6], clsids[i]->Data4[7]);
-    }
-
-    strtable.cEntries = sizeof(pse)/sizeof(pse[0]);
-    strtable.pse = pse;
-
-    hAdvpack = LoadLibraryW(advpackW);
-    pRegInstall = (void *)GetProcAddress(hAdvpack, "RegInstall");
-
-    hres = pRegInstall(jscript_hinstance, doregister ? "RegisterDll" : "UnregisterDll", &strtable);
-
-    for(i=0; i < sizeof(pse)/sizeof(pse[0]); i++)
-        HeapFree(GetProcessHeap(), 0, pse[i].pszValue);
-
-    return hres;
-}
-
-#undef INF_SET_CLSID
-
 /***********************************************************************
  *          DllRegisterServer (jscript.@)
  */
 HRESULT WINAPI DllRegisterServer(void)
 {
     TRACE("()\n");
-    return register_inf(TRUE);
+    return __wine_register_resources(jscript_hinstance);
 }
 
 /***********************************************************************
@@ -214,5 +194,5 @@ HRESULT WINAPI DllRegisterServer(void)
 HRESULT WINAPI DllUnregisterServer(void)
 {
     TRACE("()\n");
-    return register_inf(FALSE);
+    return __wine_unregister_resources(jscript_hinstance);
 }
diff --git a/reactos/dll/win32/jscript/jsregexp.c b/reactos/dll/win32/jscript/jsregexp.c
new file mode 100644 (file)
index 0000000..09eaa7f
--- /dev/null
@@ -0,0 +1,1029 @@
+/*
+ * Copyright 2008 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
+ */
+
+#include <math.h>
+
+#include "jscript.h"
+#include "regexp.h"
+
+#include <wine/debug.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(jscript);
+
+typedef struct {
+    jsdisp_t dispex;
+
+    regexp_t *jsregexp;
+    jsstr_t *str;
+    INT last_index;
+    jsval_t last_index_val;
+} RegExpInstance;
+
+static const WCHAR sourceW[] = {'s','o','u','r','c','e',0};
+static const WCHAR globalW[] = {'g','l','o','b','a','l',0};
+static const WCHAR ignoreCaseW[] = {'i','g','n','o','r','e','C','a','s','e',0};
+static const WCHAR multilineW[] = {'m','u','l','t','i','l','i','n','e',0};
+static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
+static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
+static const WCHAR execW[] = {'e','x','e','c',0};
+static const WCHAR testW[] = {'t','e','s','t',0};
+
+static const WCHAR leftContextW[] =
+    {'l','e','f','t','C','o','n','t','e','x','t',0};
+static const WCHAR rightContextW[] =
+    {'r','i','g','h','t','C','o','n','t','e','x','t',0};
+
+static const WCHAR idx1W[] = {'$','1',0};
+static const WCHAR idx2W[] = {'$','2',0};
+static const WCHAR idx3W[] = {'$','3',0};
+static const WCHAR idx4W[] = {'$','4',0};
+static const WCHAR idx5W[] = {'$','5',0};
+static const WCHAR idx6W[] = {'$','6',0};
+static const WCHAR idx7W[] = {'$','7',0};
+static const WCHAR idx8W[] = {'$','8',0};
+static const WCHAR idx9W[] = {'$','9',0};
+
+static const WCHAR emptyW[] = {0};
+
+static inline RegExpInstance *regexp_from_vdisp(vdisp_t *vdisp)
+{
+    return (RegExpInstance*)vdisp->u.jsdisp;
+}
+
+static void set_last_index(RegExpInstance *This, DWORD last_index)
+{
+    This->last_index = last_index;
+    jsval_release(This->last_index_val);
+    This->last_index_val = jsval_number(last_index);
+}
+
+static HRESULT do_regexp_match_next(script_ctx_t *ctx, RegExpInstance *regexp,
+        DWORD rem_flags, jsstr_t *str, match_state_t *ret)
+{
+    HRESULT hres;
+
+    hres = regexp_execute(regexp->jsregexp, ctx, &ctx->tmp_heap,
+            str->str, jsstr_length(str), ret);
+    if(FAILED(hres))
+        return hres;
+    if(hres == S_FALSE) {
+        if(rem_flags & REM_RESET_INDEX)
+            set_last_index(regexp, 0);
+        return S_FALSE;
+    }
+
+    if(!(rem_flags & REM_NO_CTX_UPDATE) && ctx->last_match != str) {
+        jsstr_release(ctx->last_match);
+        ctx->last_match = jsstr_addref(str);
+    }
+
+    if(!(rem_flags & REM_NO_CTX_UPDATE)) {
+        DWORD i, n = min(sizeof(ctx->match_parens)/sizeof(ctx->match_parens[0]), ret->paren_count);
+
+        for(i=0; i < n; i++) {
+            if(ret->parens[i].index == -1) {
+                ctx->match_parens[i].index = 0;
+                ctx->match_parens[i].length = 0;
+            }else {
+                ctx->match_parens[i].index = ret->parens[i].index;
+                ctx->match_parens[i].length = ret->parens[i].length;
+            }
+        }
+
+        if(n < sizeof(ctx->match_parens)/sizeof(ctx->match_parens[0]))
+            memset(ctx->match_parens+n, 0, sizeof(ctx->match_parens) - n*sizeof(ctx->match_parens[0]));
+    }
+
+    set_last_index(regexp, ret->cp-str->str);
+
+    if(!(rem_flags & REM_NO_CTX_UPDATE)) {
+        ctx->last_match_index = ret->cp-str->str-ret->match_len;
+        ctx->last_match_length = ret->match_len;
+    }
+
+    return S_OK;
+}
+
+HRESULT regexp_match_next(script_ctx_t *ctx, jsdisp_t *dispex,
+        DWORD rem_flags, jsstr_t *str, match_state_t **ret)
+{
+    RegExpInstance *regexp = (RegExpInstance*)dispex;
+    match_state_t *match;
+    heap_pool_t *mark;
+    HRESULT hres;
+
+    if((rem_flags & REM_CHECK_GLOBAL) && !(regexp->jsregexp->flags & REG_GLOB)) {
+        if(rem_flags & REM_ALLOC_RESULT)
+            *ret = NULL;
+        return S_FALSE;
+    }
+
+    if(rem_flags & REM_ALLOC_RESULT) {
+        match = alloc_match_state(regexp->jsregexp, NULL, str->str);
+        if(!match)
+            return E_OUTOFMEMORY;
+        *ret = match;
+    }
+
+    mark = heap_pool_mark(&ctx->tmp_heap);
+
+    if(rem_flags & REM_NO_PARENS) {
+        match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, NULL);
+        if(!match) {
+            heap_pool_clear(mark);
+            return E_OUTOFMEMORY;
+        }
+        match->cp = (*ret)->cp;
+        match->match_len = (*ret)->match_len;
+    }else {
+        match = *ret;
+    }
+
+    hres = do_regexp_match_next(ctx, regexp, rem_flags, str, match);
+
+    if(rem_flags & REM_NO_PARENS) {
+        (*ret)->cp = match->cp;
+        (*ret)->match_len = match->match_len;
+    }
+
+    heap_pool_clear(mark);
+
+    if(hres != S_OK && (rem_flags & REM_ALLOC_RESULT)) {
+        heap_free(match);
+        *ret = NULL;
+    }
+
+    return hres;
+}
+
+static HRESULT regexp_match(script_ctx_t *ctx, jsdisp_t *dispex, jsstr_t *str, BOOL gflag,
+        match_result_t **match_result, DWORD *result_cnt)
+{
+    RegExpInstance *This = (RegExpInstance*)dispex;
+    match_result_t *ret = NULL;
+    match_state_t *result;
+    DWORD i=0, ret_size = 0;
+    heap_pool_t *mark;
+    HRESULT hres;
+
+    mark = heap_pool_mark(&ctx->tmp_heap);
+
+    result = alloc_match_state(This->jsregexp, &ctx->tmp_heap, str->str);
+    if(!result) {
+        heap_pool_clear(mark);
+        return E_OUTOFMEMORY;
+    }
+
+    while(1) {
+        hres = do_regexp_match_next(ctx, This, 0, str, result);
+        if(hres == S_FALSE) {
+            hres = S_OK;
+            break;
+        }
+
+        if(FAILED(hres))
+            break;
+
+        if(ret_size == i) {
+            if(ret) {
+                match_result_t *old_ret = ret;
+
+                ret = heap_realloc(old_ret, (ret_size <<= 1) * sizeof(match_result_t));
+                if(!ret)
+                    heap_free(old_ret);
+            }else {
+                ret = heap_alloc((ret_size=4) * sizeof(match_result_t));
+            }
+            if(!ret) {
+                hres = E_OUTOFMEMORY;
+                break;
+            }
+        }
+
+        ret[i].index = result->cp - str->str - result->match_len;
+        ret[i++].length = result->match_len;
+
+        if(!gflag && !(This->jsregexp->flags & REG_GLOB)) {
+            hres = S_OK;
+            break;
+        }
+    }
+
+    heap_pool_clear(mark);
+    if(FAILED(hres)) {
+        heap_free(ret);
+        return hres;
+    }
+
+    *match_result = ret;
+    *result_cnt = i;
+    return S_OK;
+}
+
+static HRESULT RegExp_source(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    TRACE("\n");
+
+    switch(flags) {
+    case DISPATCH_PROPERTYGET: {
+        RegExpInstance *This = regexp_from_vdisp(jsthis);
+        *r = jsval_string(jsstr_addref(This->str));
+        break;
+    }
+    default:
+        FIXME("Unimplemented flags %x\n", flags);
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static HRESULT RegExp_global(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT RegExp_ignoreCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT RegExp_multiline(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static INT index_from_val(script_ctx_t *ctx, jsval_t v)
+{
+    double n;
+    HRESULT hres;
+
+    hres = to_number(ctx, v, &n);
+    if(FAILED(hres)) {
+        clear_ei(ctx); /* FIXME: Move ignoring exceptions to to_primitive */
+        return 0;
+    }
+
+    n = floor(n);
+    return is_int32(n) ? n : 0;
+}
+
+static HRESULT RegExp_lastIndex(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    TRACE("\n");
+
+    switch(flags) {
+    case DISPATCH_PROPERTYGET: {
+        RegExpInstance *regexp = regexp_from_vdisp(jsthis);
+
+        return jsval_copy(regexp->last_index_val, r);
+    }
+    case DISPATCH_PROPERTYPUT: {
+        RegExpInstance *regexp = regexp_from_vdisp(jsthis);
+        HRESULT hres;
+
+        hres = jsval_copy(argv[0], &regexp->last_index_val);
+        if(FAILED(hres))
+            return hres;
+
+        regexp->last_index = index_from_val(ctx, argv[0]);
+        break;
+    }
+    default:
+        FIXME("unimplemented flags: %x\n", flags);
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static HRESULT RegExp_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT create_match_array(script_ctx_t *ctx, jsstr_t *input,
+        const match_state_t *result, IDispatch **ret)
+{
+    jsdisp_t *array;
+    jsstr_t *str;
+    DWORD i;
+    HRESULT hres = S_OK;
+
+    static const WCHAR indexW[] = {'i','n','d','e','x',0};
+    static const WCHAR inputW[] = {'i','n','p','u','t',0};
+    static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
+    static const WCHAR zeroW[] = {'0',0};
+
+    hres = create_array(ctx, result->paren_count+1, &array);
+    if(FAILED(hres))
+        return hres;
+
+    for(i=0; i < result->paren_count; i++) {
+        if(result->parens[i].index != -1)
+            str = jsstr_substr(input, result->parens[i].index, result->parens[i].length);
+        else
+            str = jsstr_empty();
+        if(!str) {
+            hres = E_OUTOFMEMORY;
+            break;
+        }
+
+        hres = jsdisp_propput_idx(array, i+1, jsval_string(str));
+        jsstr_release(str);
+        if(FAILED(hres))
+            break;
+    }
+
+    while(SUCCEEDED(hres)) {
+        hres = jsdisp_propput_name(array, indexW, jsval_number(result->cp-input->str-result->match_len));
+        if(FAILED(hres))
+            break;
+
+        hres = jsdisp_propput_name(array, lastIndexW, jsval_number(result->cp-input->str));
+        if(FAILED(hres))
+            break;
+
+        hres = jsdisp_propput_name(array, inputW, jsval_string(jsstr_addref(input)));
+        if(FAILED(hres))
+            break;
+
+        str = jsstr_alloc_len(result->cp-result->match_len, result->match_len);
+        if(!str) {
+            hres = E_OUTOFMEMORY;
+            break;
+        }
+        hres = jsdisp_propput_name(array, zeroW, jsval_string(str));
+        jsstr_release(str);
+        break;
+    }
+
+    if(FAILED(hres)) {
+        jsdisp_release(array);
+        return hres;
+    }
+
+    *ret = to_disp(array);
+    return S_OK;
+}
+
+static HRESULT run_exec(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t arg,
+        jsstr_t **input, match_state_t **result, BOOL *ret)
+{
+    RegExpInstance *regexp;
+    match_state_t *match;
+    DWORD last_index = 0;
+    jsstr_t *string;
+    HRESULT hres;
+
+    if(!is_vclass(jsthis, JSCLASS_REGEXP)) {
+        FIXME("Not a RegExp\n");
+        return E_NOTIMPL;
+    }
+
+    regexp = regexp_from_vdisp(jsthis);
+
+    hres = to_string(ctx, arg, &string);
+    if(FAILED(hres))
+        return hres;
+
+    if(regexp->jsregexp->flags & REG_GLOB) {
+        if(regexp->last_index < 0) {
+            jsstr_release(string);
+            set_last_index(regexp, 0);
+            *ret = FALSE;
+            if(input)
+                *input = jsstr_empty();
+            return S_OK;
+        }
+
+        last_index = regexp->last_index;
+    }
+
+    match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, string->str+last_index);
+    if(!match) {
+        jsstr_release(string);
+        return E_OUTOFMEMORY;
+    }
+
+    hres = regexp_match_next(ctx, &regexp->dispex, REM_RESET_INDEX, string, &match);
+    if(FAILED(hres)) {
+        jsstr_release(string);
+        return hres;
+    }
+
+    *result = match;
+    *ret = hres == S_OK;
+    if(input)
+        *input = string;
+    else
+        jsstr_release(string);
+    return S_OK;
+}
+
+static HRESULT RegExp_exec(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    match_state_t *match;
+    heap_pool_t *mark;
+    BOOL b;
+    jsstr_t *string;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    mark = heap_pool_mark(&ctx->tmp_heap);
+
+    hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(jsstr_empty()), &string, &match, &b);
+    if(FAILED(hres)) {
+        heap_pool_clear(mark);
+        return hres;
+    }
+
+    if(r) {
+        if(b) {
+            IDispatch *ret;
+
+            hres = create_match_array(ctx, string, match, &ret);
+            if(SUCCEEDED(hres))
+                *r = jsval_disp(ret);
+        }else {
+            *r = jsval_null();
+        }
+    }
+
+    heap_pool_clear(mark);
+    jsstr_release(string);
+    return hres;
+}
+
+static HRESULT RegExp_test(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    match_state_t *match;
+    jsstr_t *undef_str;
+    heap_pool_t *mark;
+    BOOL b;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    mark = heap_pool_mark(&ctx->tmp_heap);
+    hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(undef_str = jsstr_undefined()), NULL, &match, &b);
+    heap_pool_clear(mark);
+    if(!argc)
+        jsstr_release(undef_str);
+    if(FAILED(hres))
+        return hres;
+
+    if(r)
+        *r = jsval_bool(b);
+    return S_OK;
+}
+
+static HRESULT RegExp_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    TRACE("\n");
+
+    switch(flags) {
+    case INVOKE_FUNC:
+        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
+    default:
+        FIXME("unimplemented flags %x\n", flags);
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static void RegExp_destructor(jsdisp_t *dispex)
+{
+    RegExpInstance *This = (RegExpInstance*)dispex;
+
+    if(This->jsregexp)
+        regexp_destroy(This->jsregexp);
+    jsval_release(This->last_index_val);
+    jsstr_release(This->str);
+    heap_free(This);
+}
+
+static const builtin_prop_t RegExp_props[] = {
+    {execW,                  RegExp_exec,                  PROPF_METHOD|1},
+    {globalW,                RegExp_global,                0},
+    {ignoreCaseW,            RegExp_ignoreCase,            0},
+    {lastIndexW,             RegExp_lastIndex,             0},
+    {multilineW,             RegExp_multiline,             0},
+    {sourceW,                RegExp_source,                0},
+    {testW,                  RegExp_test,                  PROPF_METHOD|1},
+    {toStringW,              RegExp_toString,              PROPF_METHOD}
+};
+
+static const builtin_info_t RegExp_info = {
+    JSCLASS_REGEXP,
+    {NULL, RegExp_value, 0},
+    sizeof(RegExp_props)/sizeof(*RegExp_props),
+    RegExp_props,
+    RegExp_destructor,
+    NULL
+};
+
+static const builtin_prop_t RegExpInst_props[] = {
+    {globalW,                RegExp_global,                0},
+    {ignoreCaseW,            RegExp_ignoreCase,            0},
+    {lastIndexW,             RegExp_lastIndex,             0},
+    {multilineW,             RegExp_multiline,             0},
+    {sourceW,                RegExp_source,                0}
+};
+
+static const builtin_info_t RegExpInst_info = {
+    JSCLASS_REGEXP,
+    {NULL, RegExp_value, 0},
+    sizeof(RegExpInst_props)/sizeof(*RegExpInst_props),
+    RegExpInst_props,
+    RegExp_destructor,
+    NULL
+};
+
+static HRESULT alloc_regexp(script_ctx_t *ctx, jsdisp_t *object_prototype, RegExpInstance **ret)
+{
+    RegExpInstance *regexp;
+    HRESULT hres;
+
+    regexp = heap_alloc_zero(sizeof(RegExpInstance));
+    if(!regexp)
+        return E_OUTOFMEMORY;
+
+    if(object_prototype)
+        hres = init_dispex(&regexp->dispex, ctx, &RegExp_info, object_prototype);
+    else
+        hres = init_dispex_from_constr(&regexp->dispex, ctx, &RegExpInst_info, ctx->regexp_constr);
+
+    if(FAILED(hres)) {
+        heap_free(regexp);
+        return hres;
+    }
+
+    *ret = regexp;
+    return S_OK;
+}
+
+HRESULT create_regexp(script_ctx_t *ctx, jsstr_t *src, DWORD flags, jsdisp_t **ret)
+{
+    RegExpInstance *regexp;
+    HRESULT hres;
+
+    TRACE("%s %x\n", debugstr_jsstr(src), flags);
+
+    hres = alloc_regexp(ctx, NULL, &regexp);
+    if(FAILED(hres))
+        return hres;
+
+    regexp->str = jsstr_addref(src);
+    regexp->last_index_val = jsval_number(0);
+
+    regexp->jsregexp = regexp_new(ctx, &ctx->tmp_heap, regexp->str->str,
+            jsstr_length(regexp->str), flags, FALSE);
+    if(FAILED(hres)) {
+        WARN("regexp_new failed\n");
+        jsdisp_release(&regexp->dispex);
+        return E_FAIL;
+    }
+
+    *ret = &regexp->dispex;
+    return S_OK;
+}
+
+HRESULT create_regexp_var(script_ctx_t *ctx, jsval_t src_arg, jsval_t *flags_arg, jsdisp_t **ret)
+{
+    jsstr_t *src, *opt = NULL;
+    DWORD flags;
+    HRESULT hres;
+
+    if(is_object_instance(src_arg)) {
+        jsdisp_t *obj;
+
+        obj = iface_to_jsdisp((IUnknown*)get_object(src_arg));
+        if(obj) {
+            if(is_class(obj, JSCLASS_REGEXP)) {
+                RegExpInstance *regexp = (RegExpInstance*)obj;
+
+                hres = create_regexp(ctx, regexp->str, regexp->jsregexp->flags, ret);
+                jsdisp_release(obj);
+                return hres;
+            }
+
+            jsdisp_release(obj);
+        }
+    }
+
+    if(!is_string(src_arg)) {
+        FIXME("src_arg = %s\n", debugstr_jsval(src_arg));
+        return E_NOTIMPL;
+    }
+
+    src = get_string(src_arg);
+
+    if(flags_arg) {
+        if(!is_string(*flags_arg)) {
+            FIXME("unimplemented for %s\n", debugstr_jsval(*flags_arg));
+            return E_NOTIMPL;
+        }
+
+        opt = get_string(*flags_arg);
+    }
+
+    hres = parse_regexp_flags(opt ? opt->str : NULL, opt ? jsstr_length(opt) : 0, &flags);
+    if(FAILED(hres))
+        return hres;
+
+    return create_regexp(ctx, src, flags, ret);
+}
+
+HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *str, jsval_t *r)
+{
+    static const WCHAR indexW[] = {'i','n','d','e','x',0};
+    static const WCHAR inputW[] = {'i','n','p','u','t',0};
+    static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
+
+    RegExpInstance *regexp = (RegExpInstance*)re;
+    match_result_t *match_result;
+    unsigned match_cnt, i;
+    jsdisp_t *array;
+    HRESULT hres;
+
+    if(!(regexp->jsregexp->flags & REG_GLOB)) {
+        match_state_t *match;
+        heap_pool_t *mark;
+
+        mark = heap_pool_mark(&ctx->tmp_heap);
+        match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, str->str);
+        if(!match) {
+            heap_pool_clear(mark);
+            return E_OUTOFMEMORY;
+        }
+
+        hres = regexp_match_next(ctx, &regexp->dispex, 0, str, &match);
+        if(FAILED(hres)) {
+            heap_pool_clear(mark);
+            return hres;
+        }
+
+        if(r) {
+            if(hres == S_OK) {
+                IDispatch *ret;
+
+                hres = create_match_array(ctx, str, match, &ret);
+                if(SUCCEEDED(hres))
+                    *r = jsval_disp(ret);
+            }else {
+                *r = jsval_null();
+            }
+        }
+
+        heap_pool_clear(mark);
+        return S_OK;
+    }
+
+    hres = regexp_match(ctx, &regexp->dispex, str, FALSE, &match_result, &match_cnt);
+    if(FAILED(hres))
+        return hres;
+
+    if(!match_cnt) {
+        TRACE("no match\n");
+
+        if(r)
+            *r = jsval_null();
+        return S_OK;
+    }
+
+    hres = create_array(ctx, match_cnt, &array);
+    if(FAILED(hres))
+        return hres;
+
+    for(i=0; i < match_cnt; i++) {
+        jsstr_t *tmp_str;
+
+        tmp_str = jsstr_substr(str, match_result[i].index, match_result[i].length);
+        if(!tmp_str) {
+            hres = E_OUTOFMEMORY;
+            break;
+        }
+
+        hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
+        jsstr_release(tmp_str);
+        if(FAILED(hres))
+            break;
+    }
+
+    while(SUCCEEDED(hres)) {
+        hres = jsdisp_propput_name(array, indexW, jsval_number(match_result[match_cnt-1].index));
+        if(FAILED(hres))
+            break;
+
+        hres = jsdisp_propput_name(array, lastIndexW,
+                jsval_number(match_result[match_cnt-1].index + match_result[match_cnt-1].length));
+        if(FAILED(hres))
+            break;
+
+        hres = jsdisp_propput_name(array, inputW, jsval_string(str));
+        break;
+    }
+
+    heap_free(match_result);
+
+    if(SUCCEEDED(hres) && r)
+        *r = jsval_obj(array);
+    else
+        jsdisp_release(array);
+    return hres;
+}
+
+static HRESULT global_idx(script_ctx_t *ctx, DWORD flags, DWORD idx, jsval_t *r)
+{
+    switch(flags) {
+    case DISPATCH_PROPERTYGET: {
+        jsstr_t *ret;
+
+        ret = jsstr_substr(ctx->last_match, ctx->match_parens[idx].index, ctx->match_parens[idx].length);
+        if(!ret)
+            return E_OUTOFMEMORY;
+
+        *r = jsval_string(ret);
+        break;
+    }
+    case DISPATCH_PROPERTYPUT:
+        break;
+    default:
+        FIXME("unsupported flags\n");
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static HRESULT RegExpConstr_idx1(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+         unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    TRACE("\n");
+    return global_idx(ctx, flags, 0, r);
+}
+
+static HRESULT RegExpConstr_idx2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+         unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    TRACE("\n");
+    return global_idx(ctx, flags, 1, r);
+}
+
+static HRESULT RegExpConstr_idx3(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+         unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    TRACE("\n");
+    return global_idx(ctx, flags, 2, r);
+}
+
+static HRESULT RegExpConstr_idx4(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+         unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    TRACE("\n");
+    return global_idx(ctx, flags, 3, r);
+}
+
+static HRESULT RegExpConstr_idx5(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+         unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    TRACE("\n");
+    return global_idx(ctx, flags, 4, r);
+}
+
+static HRESULT RegExpConstr_idx6(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+         unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    TRACE("\n");
+    return global_idx(ctx, flags, 5, r);
+}
+
+static HRESULT RegExpConstr_idx7(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+         unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    TRACE("\n");
+    return global_idx(ctx, flags, 6, r);
+}
+
+static HRESULT RegExpConstr_idx8(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+         unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    TRACE("\n");
+    return global_idx(ctx, flags, 7, r);
+}
+
+static HRESULT RegExpConstr_idx9(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+         unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    TRACE("\n");
+    return global_idx(ctx, flags, 8, r);
+}
+
+static HRESULT RegExpConstr_leftContext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+         unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    TRACE("\n");
+
+    switch(flags) {
+    case DISPATCH_PROPERTYGET: {
+        jsstr_t *ret;
+
+        ret = jsstr_substr(ctx->last_match, 0, ctx->last_match_index);
+        if(!ret)
+            return E_OUTOFMEMORY;
+
+        *r = jsval_string(ret);
+        break;
+    }
+    case DISPATCH_PROPERTYPUT:
+        break;
+    default:
+        FIXME("unsupported flags\n");
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static HRESULT RegExpConstr_rightContext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
+         unsigned argc, jsval_t *argv, jsval_t *r)
+{
+    TRACE("\n");
+
+    switch(flags) {
+    case DISPATCH_PROPERTYGET: {
+        jsstr_t *ret;
+
+        ret = jsstr_substr(ctx->last_match, ctx->last_match_index+ctx->last_match_length,
+                jsstr_length(ctx->last_match) - ctx->last_match_index - ctx->last_match_length);
+        if(!ret)
+            return E_OUTOFMEMORY;
+
+        *r = jsval_string(ret);
+        break;
+    }
+    case DISPATCH_PROPERTYPUT:
+        break;
+    default:
+        FIXME("unsupported flags\n");
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    TRACE("\n");
+
+    switch(flags) {
+    case DISPATCH_METHOD:
+        if(argc) {
+            if(is_object_instance(argv[0])) {
+                jsdisp_t *jsdisp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
+                if(jsdisp) {
+                    if(is_class(jsdisp, JSCLASS_REGEXP)) {
+                        if(argc > 1 && !is_undefined(argv[1])) {
+                            jsdisp_release(jsdisp);
+                            return throw_regexp_error(ctx, JS_E_REGEXP_SYNTAX, NULL);
+                        }
+
+                        if(r)
+                            *r = jsval_obj(jsdisp);
+                        else
+                            jsdisp_release(jsdisp);
+                        return S_OK;
+                    }
+                    jsdisp_release(jsdisp);
+                }
+            }
+        }
+        /* fall through */
+    case DISPATCH_CONSTRUCT: {
+        jsdisp_t *ret;
+        HRESULT hres;
+
+        if(!argc) {
+            FIXME("no args\n");
+            return E_NOTIMPL;
+        }
+
+        hres = create_regexp_var(ctx, argv[0], argc > 1 ? argv+1 : NULL, &ret);
+        if(FAILED(hres))
+            return hres;
+
+        if(r)
+            *r = jsval_obj(ret);
+        else
+            jsdisp_release(ret);
+        return S_OK;
+    }
+    default:
+        FIXME("unimplemented flags: %x\n", flags);
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static const builtin_prop_t RegExpConstr_props[] = {
+    {idx1W,           RegExpConstr_idx1,           0},
+    {idx2W,           RegExpConstr_idx2,           0},
+    {idx3W,           RegExpConstr_idx3,           0},
+    {idx4W,           RegExpConstr_idx4,           0},
+    {idx5W,           RegExpConstr_idx5,           0},
+    {idx6W,           RegExpConstr_idx6,           0},
+    {idx7W,           RegExpConstr_idx7,           0},
+    {idx8W,           RegExpConstr_idx8,           0},
+    {idx9W,           RegExpConstr_idx9,           0},
+    {leftContextW,    RegExpConstr_leftContext,    0},
+    {rightContextW,   RegExpConstr_rightContext,   0}
+};
+
+static const builtin_info_t RegExpConstr_info = {
+    JSCLASS_FUNCTION,
+    {NULL, Function_value, 0},
+    sizeof(RegExpConstr_props)/sizeof(*RegExpConstr_props),
+    RegExpConstr_props,
+    NULL,
+    NULL
+};
+
+HRESULT create_regexp_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
+{
+    RegExpInstance *regexp;
+    HRESULT hres;
+
+    static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
+
+    hres = alloc_regexp(ctx, object_prototype, &regexp);
+    if(FAILED(hres))
+        return hres;
+
+    hres = create_builtin_constructor(ctx, RegExpConstr_value, RegExpW, &RegExpConstr_info,
+            PROPF_CONSTR|2, &regexp->dispex, ret);
+
+    jsdisp_release(&regexp->dispex);
+    return hres;
+}
+
+HRESULT parse_regexp_flags(const WCHAR *str, DWORD str_len, DWORD *ret)
+{
+    const WCHAR *p;
+    DWORD flags = 0;
+
+    for (p = str; p < str+str_len; p++) {
+        switch (*p) {
+        case 'g':
+            flags |= REG_GLOB;
+            break;
+        case 'i':
+            flags |= REG_FOLD;
+            break;
+        case 'm':
+            flags |= REG_MULTILINE;
+            break;
+        case 'y':
+            flags |= REG_STICKY;
+            break;
+        default:
+            WARN("wrong flag %c\n", *p);
+            return E_FAIL;
+        }
+    }
+
+    *ret = flags;
+    return S_OK;
+}
diff --git a/reactos/dll/win32/jscript/jsstr.c b/reactos/dll/win32/jscript/jsstr.c
new file mode 100644 (file)
index 0000000..48adf94
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * 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
+ */
+
+#include "jscript.h"
+
+#include <wine/debug.h>
+
+const char *debugstr_jsstr(jsstr_t *str)
+{
+    return debugstr_wn(str->str, jsstr_length(str));
+}
+
+jsstr_t *jsstr_alloc_buf(unsigned len)
+{
+    jsstr_t *ret;
+
+    if(len > JSSTR_MAX_LENGTH)
+        return NULL;
+
+    ret = heap_alloc(FIELD_OFFSET(jsstr_t, str[len+1]));
+    if(!ret)
+        return NULL;
+
+    ret->length_flags = len << JSSTR_LENGTH_SHIFT;
+    ret->ref = 1;
+    ret->str[len] = 0;
+    return ret;
+}
+
+jsstr_t *jsstr_alloc_len(const WCHAR *buf, unsigned len)
+{
+    jsstr_t *ret;
+
+    ret = jsstr_alloc_buf(len);
+    if(ret)
+        memcpy(ret->str, buf, len*sizeof(WCHAR));
+
+    return ret;
+}
+
+int jsstr_cmp(jsstr_t *str1, jsstr_t *str2)
+{
+    int len1 = jsstr_length(str1);
+    int len2 = jsstr_length(str2);
+    int ret;
+
+    ret = memcmp(str1->str, str2->str, min(len1, len2)*sizeof(WCHAR));
+    if(!ret)
+        ret = len1 - len2;
+
+    return ret;
+}
+
+jsstr_t *jsstr_concat(jsstr_t *str1, jsstr_t *str2)
+{
+    unsigned len1, len2;
+    jsstr_t *ret;
+
+    len1 = jsstr_length(str1);
+    if(!len1)
+        return jsstr_addref(str2);
+
+    len2 = jsstr_length(str2);
+    if(!len2)
+        return jsstr_addref(str1);
+
+    ret = jsstr_alloc_buf(len1+len2);
+    if(!ret)
+        return NULL;
+
+    jsstr_flush(str1, ret->str);
+    jsstr_flush(str2, ret->str+len1);
+    return ret;
+}
+
+static jsstr_t *empty_str, *nan_str, *undefined_str;
+
+jsstr_t *jsstr_nan(void)
+{
+    return jsstr_addref(nan_str);
+}
+
+jsstr_t *jsstr_empty(void)
+{
+    return jsstr_addref(empty_str);
+}
+
+jsstr_t *jsstr_undefined(void)
+{
+    return jsstr_addref(undefined_str);
+}
+
+BOOL init_strings(void)
+{
+    static const WCHAR NaNW[] = { 'N','a','N',0 };
+    static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
+
+    if(!(empty_str = jsstr_alloc_buf(0)))
+        return FALSE;
+    if(!(nan_str = jsstr_alloc(NaNW)))
+        return FALSE;
+    if(!(undefined_str = jsstr_alloc(undefinedW)))
+        return FALSE;
+    return TRUE;
+}
+
+void free_strings(void)
+{
+    jsstr_release(empty_str);
+    jsstr_release(nan_str);
+    jsstr_release(undefined_str);
+}
diff --git a/reactos/dll/win32/jscript/jsstr.h b/reactos/dll/win32/jscript/jsstr.h
new file mode 100644 (file)
index 0000000..c71cbea
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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
+ */
+
+struct _jsstr_t {
+    unsigned length_flags;
+    unsigned ref;
+    WCHAR str[1];
+};
+
+#define JSSTR_LENGTH_SHIFT 4
+#define JSSTR_MAX_LENGTH (1 << (32-JSSTR_LENGTH_SHIFT))
+#define JSSTR_FLAGS_MASK ((1 << JSSTR_LENGTH_SHIFT)-1)
+
+#define JSSTR_FLAG_NULLBSTR 1
+
+static inline unsigned jsstr_length(jsstr_t *str)
+{
+    return str->length_flags >> JSSTR_LENGTH_SHIFT;
+}
+
+jsstr_t *jsstr_alloc_len(const WCHAR*,unsigned) DECLSPEC_HIDDEN;
+jsstr_t *jsstr_alloc_buf(unsigned) DECLSPEC_HIDDEN;
+
+static inline jsstr_t *jsstr_alloc(const WCHAR *str)
+{
+    return jsstr_alloc_len(str, strlenW(str));
+}
+
+static inline void jsstr_release(jsstr_t *str)
+{
+    if(!--str->ref)
+        heap_free(str);
+}
+
+static inline jsstr_t *jsstr_addref(jsstr_t *str)
+{
+    str->ref++;
+    return str;
+}
+
+static inline BOOL jsstr_eq(jsstr_t *str1, jsstr_t *str2)
+{
+    unsigned len = jsstr_length(str1);
+    return len == jsstr_length(str2) && !memcmp(str1->str, str2->str, len*sizeof(WCHAR));
+}
+
+static inline unsigned jsstr_flush(jsstr_t *str, WCHAR *buf)
+{
+    unsigned len = jsstr_length(str);
+    memcpy(buf, str->str, len*sizeof(WCHAR));
+    return len;
+}
+
+static inline jsstr_t *jsstr_substr(jsstr_t *str, unsigned off, unsigned len)
+{
+    return jsstr_alloc_len(str->str+off, len);
+}
+
+int jsstr_cmp(jsstr_t*,jsstr_t*) DECLSPEC_HIDDEN;
+jsstr_t *jsstr_concat(jsstr_t*,jsstr_t*) DECLSPEC_HIDDEN;
+
+jsstr_t *jsstr_nan(void) DECLSPEC_HIDDEN;
+jsstr_t *jsstr_empty(void) DECLSPEC_HIDDEN;
+jsstr_t *jsstr_undefined(void) DECLSPEC_HIDDEN;
+
+BOOL init_strings(void) DECLSPEC_HIDDEN;
+void free_strings(void) DECLSPEC_HIDDEN;
+
+const char *debugstr_jsstr(jsstr_t*) DECLSPEC_HIDDEN;
index c0987c4..8b325aa 100644 (file)
@@ -20,6 +20,7 @@
 #include <wine/port.h>
 
 //#include <math.h>
+#include <assert.h>
 
 #include "jscript.h"
 //#include "engine.h"
@@ -41,6 +42,8 @@ const char *debugstr_variant(const VARIANT *v)
         return "{VT_NULL}";
     case VT_I4:
         return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
+    case VT_UI4:
+        return wine_dbg_sprintf("{VT_UI4: %u}", V_UI4(v));
     case VT_R8:
         return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
     case VT_BSTR:
@@ -49,11 +52,36 @@ const char *debugstr_variant(const VARIANT *v)
         return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
     case VT_BOOL:
         return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
+    case VT_ARRAY|VT_VARIANT:
+        return "{VT_ARRAY|VT_VARIANT: ...}";
     default:
         return wine_dbg_sprintf("{vt %d}", V_VT(v));
     }
 }
 
+const char *debugstr_jsval(const jsval_t v)
+{
+    switch(jsval_type(v)) {
+    case JSV_UNDEFINED:
+        return "undefined";
+    case JSV_NULL:
+        return "null";
+    case JSV_OBJECT:
+        return wine_dbg_sprintf("obj(%p)", get_object(v));
+    case JSV_STRING:
+        return wine_dbg_sprintf("str(%s)", debugstr_jsstr(get_string(v)));
+    case JSV_NUMBER:
+        return wine_dbg_sprintf("%lf", get_number(v));
+    case JSV_BOOL:
+        return get_bool(v) ? "true" : "false";
+    case JSV_VARIANT:
+        return debugstr_variant(get_variant(v));
+    }
+
+    assert(0);
+    return NULL;
+}
+
 #define MIN_BLOCK_SIZE  128
 #define ARENA_FREE_FILLER  0xaa
 
@@ -62,13 +90,13 @@ static inline DWORD block_size(DWORD block)
     return MIN_BLOCK_SIZE << block;
 }
 
-void jsheap_init(jsheap_t *heap)
+void heap_pool_init(heap_pool_t *heap)
 {
     memset(heap, 0, sizeof(*heap));
     list_init(&heap->custom_blocks);
 }
 
-void *jsheap_alloc(jsheap_t *heap, DWORD size)
+void *heap_pool_alloc(heap_pool_t *heap, DWORD size)
 {
     struct list *list;
     void *tmp;
@@ -121,18 +149,23 @@ void *jsheap_alloc(jsheap_t *heap, DWORD size)
     return list+1;
 }
 
-void *jsheap_grow(jsheap_t *heap, void *mem, DWORD size, DWORD inc)
+void *heap_pool_grow(heap_pool_t *heap, void *mem, DWORD size, DWORD inc)
 {
+    void *ret;
+
     if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
        && heap->offset+inc < block_size(heap->last_block)) {
         heap->offset += inc;
         return mem;
     }
 
-    return jsheap_alloc(heap, size+inc);
+    ret = heap_pool_alloc(heap, size+inc);
+    if(ret) /* FIXME: avoid copying for custom blocks */
+        memcpy(ret, mem, size);
+    return ret;
 }
 
-void jsheap_clear(jsheap_t *heap)
+void heap_pool_clear(heap_pool_t *heap)
 {
     struct list *tmp;
 
@@ -155,20 +188,20 @@ void jsheap_clear(jsheap_t *heap)
     heap->mark = FALSE;
 }
 
-void jsheap_free(jsheap_t *heap)
+void heap_pool_free(heap_pool_t *heap)
 {
     DWORD i;
 
-    jsheap_clear(heap);
+    heap_pool_clear(heap);
 
     for(i=0; i < heap->block_cnt; i++)
         heap_free(heap->blocks[i]);
     heap_free(heap->blocks);
 
-    jsheap_init(heap);
+    heap_pool_init(heap);
 }
 
-jsheap_t *jsheap_mark(jsheap_t *heap)
+heap_pool_t *heap_pool_mark(heap_pool_t *heap)
 {
     if(heap->mark)
         return NULL;
@@ -177,40 +210,204 @@ jsheap_t *jsheap_mark(jsheap_t *heap)
     return heap;
 }
 
-/* ECMA-262 3rd Edition    9.1 */
-HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret, hint_t hint)
+void jsval_release(jsval_t val)
 {
-    switch(V_VT(v)) {
+    switch(jsval_type(val)) {
+    case JSV_OBJECT:
+        if(get_object(val))
+            IDispatch_Release(get_object(val));
+        break;
+    case JSV_STRING:
+        jsstr_release(get_string(val));
+        break;
+    case JSV_VARIANT:
+        VariantClear(get_variant(val));
+        heap_free(get_variant(val));
+        break;
+    default:
+        break;
+    }
+}
+
+static HRESULT jsval_variant(jsval_t *val, VARIANT *var)
+{
+    VARIANT *v;
+    HRESULT hres;
+
+    __JSVAL_TYPE(*val) = JSV_VARIANT;
+    __JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT));
+    if(!v)
+        return E_OUTOFMEMORY;
+
+    V_VT(v) = VT_EMPTY;
+    hres = VariantCopy(v, var);
+    if(FAILED(hres))
+        heap_free(v);
+    return hres;
+}
+
+HRESULT jsval_copy(jsval_t v, jsval_t *r)
+{
+    switch(jsval_type(v)) {
+    case JSV_UNDEFINED:
+    case JSV_NULL:
+    case JSV_NUMBER:
+    case JSV_BOOL:
+        *r = v;
+        return S_OK;
+    case JSV_OBJECT:
+        if(get_object(v))
+            IDispatch_AddRef(get_object(v));
+        *r = v;
+        return S_OK;
+    case JSV_STRING: {
+        jsstr_addref(get_string(v));
+        *r = v;
+        return S_OK;
+    }
+    case JSV_VARIANT:
+        return jsval_variant(r, get_variant(v));
+    }
+
+    assert(0);
+    return E_FAIL;
+}
+
+HRESULT variant_to_jsval(VARIANT *var, jsval_t *r)
+{
+    switch(V_VT(var)) {
     case VT_EMPTY:
+        *r = jsval_undefined();
+        return S_OK;
     case VT_NULL:
+        *r = jsval_null();
+        return S_OK;
     case VT_BOOL:
+        *r = jsval_bool(V_BOOL(var));
+        return S_OK;
     case VT_I4:
+        *r = jsval_number(V_I4(var));
+        return S_OK;
     case VT_R8:
-        *ret = *v;
-        break;
-    case VT_BSTR:
-        V_VT(ret) = VT_BSTR;
-        V_BSTR(ret) = SysAllocString(V_BSTR(v));
-        break;
+        *r = jsval_number(V_R8(var));
+        return S_OK;
+    case VT_BSTR: {
+        jsstr_t *str;
+
+        str = jsstr_alloc_len(V_BSTR(var), SysStringLen(V_BSTR(var)));
+        if(!str)
+            return E_OUTOFMEMORY;
+        if(!V_BSTR(var))
+            str->length_flags |= JSSTR_FLAG_NULLBSTR;
+
+        *r = jsval_string(str);
+        return S_OK;
+    }
     case VT_DISPATCH: {
-        DispatchEx *jsdisp;
+        if(V_DISPATCH(var))
+            IDispatch_AddRef(V_DISPATCH(var));
+        *r = jsval_disp(V_DISPATCH(var));
+        return S_OK;
+    }
+    case VT_I2:
+        *r = jsval_number(V_I2(var));
+        return S_OK;
+    case VT_INT:
+        *r = jsval_number(V_INT(var));
+        return S_OK;
+    case VT_UNKNOWN:
+        if(V_UNKNOWN(var)) {
+            IDispatch *disp;
+            HRESULT hres;
+
+            hres = IUnknown_QueryInterface(V_UNKNOWN(var), &IID_IDispatch, (void**)&disp);
+            if(SUCCEEDED(hres)) {
+                *r = jsval_disp(disp);
+                return S_OK;
+            }
+        }
+        /* fall through */
+    default:
+        return jsval_variant(r, var);
+    }
+}
+
+HRESULT jsval_to_variant(jsval_t val, VARIANT *retv)
+{
+    switch(jsval_type(val)) {
+    case JSV_UNDEFINED:
+        V_VT(retv) = VT_EMPTY;
+        return S_OK;
+    case JSV_NULL:
+        V_VT(retv) = VT_NULL;
+        return S_OK;
+    case JSV_OBJECT:
+        V_VT(retv) = VT_DISPATCH;
+        if(get_object(val))
+            IDispatch_AddRef(get_object(val));
+        V_DISPATCH(retv) = get_object(val);
+        return S_OK;
+    case JSV_STRING: {
+        jsstr_t *str = get_string(val);
+
+        V_VT(retv) = VT_BSTR;
+        if(str->length_flags & JSSTR_FLAG_NULLBSTR) {
+            V_BSTR(retv) = NULL;
+        }else {
+            V_BSTR(retv) = SysAllocStringLen(NULL, jsstr_length(str));
+            if(V_BSTR(retv))
+                jsstr_flush(str, V_BSTR(retv));
+            else
+                return E_OUTOFMEMORY;
+        }
+        return S_OK;
+    }
+    case JSV_NUMBER: {
+        double n = get_number(val);
+
+        if(is_int32(n)) {
+            V_VT(retv) = VT_I4;
+            V_I4(retv) = n;
+        }else {
+            V_VT(retv) = VT_R8;
+            V_R8(retv) = n;
+        }
+
+        return S_OK;
+    }
+    case JSV_BOOL:
+        V_VT(retv) = VT_BOOL;
+        V_BOOL(retv) = get_bool(val) ? VARIANT_TRUE : VARIANT_FALSE;
+        return S_OK;
+    case JSV_VARIANT:
+        V_VT(retv) = VT_EMPTY;
+        return VariantCopy(retv, get_variant(val));
+    }
+
+    assert(0);
+    return E_FAIL;
+}
+
+/* ECMA-262 3rd Edition    9.1 */
+HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint)
+{
+    if(is_object_instance(val)) {
+        jsdisp_t *jsdisp;
+        jsval_t prim;
         DISPID id;
-        DISPPARAMS dp = {NULL, NULL, 0, 0};
         HRESULT hres;
 
         static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
         static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
 
-        if(!V_DISPATCH(v)) {
-            V_VT(ret) = VT_NULL;
-            break;
+        if(!get_object(val)) {
+            *ret = jsval_null();
+            return S_OK;
         }
 
-        jsdisp = iface_to_jsdisp((IUnknown*)V_DISPATCH(v));
-        if(!jsdisp) {
-            V_VT(ret) = VT_EMPTY;
-            return disp_propget(ctx, V_DISPATCH(v), DISPID_VALUE, ret, ei, NULL /*FIXME*/);
-        }
+        jsdisp = iface_to_jsdisp((IUnknown*)get_object(val));
+        if(!jsdisp)
+            return disp_propget(ctx, get_object(val), DISPID_VALUE, ret);
 
         if(hint == NO_HINT)
             hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER;
@@ -219,79 +416,73 @@ HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret
 
         hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? toStringW : valueOfW, 0, &id);
         if(SUCCEEDED(hres)) {
-            hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, &dp, ret, ei, NULL /*FIXME*/);
+            hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim);
             if(FAILED(hres)) {
                 WARN("call error - forwarding exception\n");
                 jsdisp_release(jsdisp);
                 return hres;
-            }
-            else if(V_VT(ret) != VT_DISPATCH) {
+            }else if(!is_object_instance(prim)) {
                 jsdisp_release(jsdisp);
+                *ret = prim;
                 return S_OK;
+            }else {
+                IDispatch_Release(get_object(prim));
             }
-            else
-                IDispatch_Release(V_DISPATCH(ret));
         }
 
         hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? valueOfW : toStringW, 0, &id);
         if(SUCCEEDED(hres)) {
-            hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, &dp, ret, ei, NULL /*FIXME*/);
+            hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim);
             if(FAILED(hres)) {
                 WARN("call error - forwarding exception\n");
                 jsdisp_release(jsdisp);
                 return hres;
-            }
-            else if(V_VT(ret) != VT_DISPATCH) {
+            }else if(!is_object_instance(prim)) {
                 jsdisp_release(jsdisp);
+                *ret = prim;
                 return S_OK;
+            }else {
+                IDispatch_Release(get_object(prim));
             }
-            else
-                IDispatch_Release(V_DISPATCH(ret));
         }
 
         jsdisp_release(jsdisp);
 
         WARN("failed\n");
-        return throw_type_error(ctx, ei, IDS_TO_PRIMITIVE, NULL);
-    }
-    default:
-        FIXME("Unimplemented for vt %d\n", V_VT(v));
-        return E_NOTIMPL;
+        return throw_type_error(ctx, JS_E_TO_PRIMITIVE, NULL);
     }
 
-    return S_OK;
+    return jsval_copy(val, ret);
+
 }
 
 /* ECMA-262 3rd Edition    9.2 */
-HRESULT to_boolean(VARIANT *v, VARIANT_BOOL *b)
+HRESULT to_boolean(jsval_t val, BOOL *ret)
 {
-    switch(V_VT(v)) {
-    case VT_EMPTY:
-    case VT_NULL:
-        *b = VARIANT_FALSE;
-        break;
-    case VT_I4:
-        *b = V_I4(v) ? VARIANT_TRUE : VARIANT_FALSE;
-        break;
-    case VT_R8:
-        if(isnan(V_R8(v))) *b = VARIANT_FALSE;
-        else *b = V_R8(v) ? VARIANT_TRUE : VARIANT_FALSE;
-        break;
-    case VT_BSTR:
-        *b = V_BSTR(v) && *V_BSTR(v) ? VARIANT_TRUE : VARIANT_FALSE;
-        break;
-    case VT_DISPATCH:
-        *b = V_DISPATCH(v) ? VARIANT_TRUE : VARIANT_FALSE;
-        break;
-    case VT_BOOL:
-        *b = V_BOOL(v);
-        break;
-    default:
-        FIXME("unimplemented for vt %d\n", V_VT(v));
+    switch(jsval_type(val)) {
+    case JSV_UNDEFINED:
+    case JSV_NULL:
+        *ret = FALSE;
+        return S_OK;
+    case JSV_OBJECT:
+        *ret = get_object(val) != NULL;
+        return S_OK;
+    case JSV_STRING:
+        *ret = jsstr_length(get_string(val)) != 0;
+        return S_OK;
+    case JSV_NUMBER:
+        *ret = !isnan(get_number(val)) && get_number(val);
+        return S_OK;
+    case JSV_BOOL:
+        *ret = get_bool(val);
+        return S_OK;
+    case JSV_VARIANT:
+        FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val)));
         return E_NOTIMPL;
     }
 
-    return S_OK;
+    assert(0);
+    return E_FAIL;
 }
 
 static int hex_to_int(WCHAR c)
@@ -309,14 +500,19 @@ static int hex_to_int(WCHAR c)
 }
 
 /* ECMA-262 3rd Edition    9.3.1 */
-static HRESULT str_to_number(BSTR str, VARIANT *ret)
+static HRESULT str_to_number(jsstr_t *str, double *ret)
 {
-    const WCHAR *ptr = str;
+    const WCHAR *ptr = str->str;
     BOOL neg = FALSE;
     DOUBLE d = 0.0;
 
     static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'};
 
+    if(!ptr) {
+        *ret = 0;
+        return S_OK;
+    }
+
     while(isspaceW(*ptr))
         ptr++;
 
@@ -333,9 +529,9 @@ static HRESULT str_to_number(BSTR str, VARIANT *ret)
             ptr++;
 
         if(*ptr)
-            num_set_nan(ret);
+            *ret = NAN;
         else
-            num_set_inf(ret, !neg);
+            *ret = neg ? -INFINITY : INFINITY;
         return S_OK;
     }
 
@@ -348,7 +544,7 @@ static HRESULT str_to_number(BSTR str, VARIANT *ret)
             ptr++;
         }
 
-        num_set_val(ret, d);
+        *ret = d;
         return S_OK;
     }
 
@@ -387,122 +583,107 @@ static HRESULT str_to_number(BSTR str, VARIANT *ret)
         ptr++;
 
     if(*ptr) {
-        num_set_nan(ret);
+        *ret = NAN;
         return S_OK;
     }
 
     if(neg)
         d = -d;
 
-    num_set_val(ret, d);
+    *ret = d;
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    9.3 */
-HRESULT to_number(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
+HRESULT to_number(script_ctx_t *ctx, jsval_t val, double *ret)
 {
-    switch(V_VT(v)) {
-    case VT_EMPTY:
-        num_set_nan(ret);
-        break;
-    case VT_NULL:
-        V_VT(ret) = VT_I4;
-        V_I4(ret) = 0;
-        break;
-    case VT_I4:
-    case VT_R8:
-        *ret = *v;
-        break;
-    case VT_BSTR:
-        return str_to_number(V_BSTR(v), ret);
-    case VT_DISPATCH: {
-        VARIANT prim;
+    switch(jsval_type(val)) {
+    case JSV_UNDEFINED:
+        *ret = NAN;
+        return S_OK;
+    case JSV_NULL:
+        *ret = 0;
+        return S_OK;
+    case JSV_NUMBER:
+        *ret = get_number(val);
+        return S_OK;
+    case JSV_STRING:
+        return str_to_number(get_string(val), ret);
+    case JSV_OBJECT: {
+        jsval_t prim;
         HRESULT hres;
 
-        hres = to_primitive(ctx, v, ei, &prim, HINT_NUMBER);
+        hres = to_primitive(ctx, val, &prim, HINT_NUMBER);
         if(FAILED(hres))
             return hres;
 
-        hres = to_number(ctx, &prim, ei, ret);
-        VariantClear(&prim);
+        hres = to_number(ctx, prim, ret);
+        jsval_release(prim);
         return hres;
     }
-    case VT_BOOL:
-        V_VT(ret) = VT_I4;
-        V_I4(ret) = V_BOOL(v) ? 1 : 0;
-        break;
-    default:
-        FIXME("unimplemented for vt %d\n", V_VT(v));
+    case JSV_BOOL:
+        *ret = get_bool(val) ? 1 : 0;
+        return S_OK;
+    case JSV_VARIANT:
+        FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val)));
         return E_NOTIMPL;
-    }
+    };
 
-    return S_OK;
+    assert(0);
+    return E_FAIL;
 }
 
 /* ECMA-262 3rd Edition    9.4 */
-HRESULT to_integer(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
+HRESULT to_integer(script_ctx_t *ctx, jsval_t v, double *ret)
 {
-    VARIANT num;
+    double n;
     HRESULT hres;
 
-    hres = to_number(ctx, v, ei, &num);
+    hres = to_number(ctx, v, &n);
     if(FAILED(hres))
         return hres;
 
-    if(V_VT(&num) == VT_I4) {
-        *ret = num;
-    }else if(isnan(V_R8(&num))) {
-        V_VT(ret) = VT_I4;
-        V_I4(ret) = 0;
-    }else {
-        num_set_val(ret, V_R8(&num) >= 0.0 ? floor(V_R8(&num)) : -floor(-V_R8(&num)));
-    }
-
+    if(isnan(n))
+        *ret = 0;
+    else
+        *ret = n >= 0.0 ? floor(n) : -floor(-n);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    9.5 */
-HRESULT to_int32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, INT *ret)
+HRESULT to_int32(script_ctx_t *ctx, jsval_t v, INT *ret)
 {
-    VARIANT num;
+    double n;
     HRESULT hres;
 
-    hres = to_number(ctx, v, ei, &num);
+    hres = to_number(ctx, v, &n);
     if(FAILED(hres))
         return hres;
 
-    if(V_VT(&num) == VT_I4)
-        *ret = V_I4(&num);
-    else
-        *ret = isnan(V_R8(&num)) || isinf(V_R8(&num)) ? 0 : (INT)V_R8(&num);
+    *ret = isnan(n) || isinf(n) ? 0 : n;
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    9.6 */
-HRESULT to_uint32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, DWORD *ret)
+HRESULT to_uint32(script_ctx_t *ctx, jsval_t val, DWORD *ret)
 {
-    VARIANT num;
+    INT32 n;
     HRESULT hres;
 
-    hres = to_number(ctx, v, ei, &num);
-    if(FAILED(hres))
-        return hres;
-
-    if(V_VT(&num) == VT_I4)
-        *ret = V_I4(&num);
-    else
-        *ret = isnan(V_R8(&num)) || isinf(V_R8(&num)) ? 0 : (DWORD)V_R8(&num);
-    return S_OK;
+    hres = to_int32(ctx, val, &n);
+    if(SUCCEEDED(hres))
+        *ret = n;
+    return hres;
 }
 
-static BSTR int_to_bstr(INT i)
+static jsstr_t *int_to_string(int i)
 {
     WCHAR buf[12], *p;
     BOOL neg = FALSE;
 
     if(!i) {
         static const WCHAR zeroW[] = {'0',0};
-        return SysAllocString(zeroW);
+        return jsstr_alloc(zeroW);
     }
 
     if(i < 0) {
@@ -522,68 +703,74 @@ static BSTR int_to_bstr(INT i)
     else
         p++;
 
-    return SysAllocString(p);
+    return jsstr_alloc(p);
+}
+
+HRESULT double_to_string(double n, jsstr_t **str)
+{
+    const WCHAR InfinityW[] = {'-','I','n','f','i','n','i','t','y',0};
+
+    if(isnan(n)) {
+        *str = jsstr_nan();
+    }else if(isinf(n)) {
+        *str = jsstr_alloc(n<0 ? InfinityW : InfinityW+1);
+    }else if(is_int32(n)) {
+        *str = int_to_string(n);
+    }else {
+        VARIANT strv, v;
+        HRESULT hres;
+
+        /* FIXME: Don't use VariantChangeTypeEx */
+        V_VT(&v) = VT_R8;
+        V_R8(&v) = n;
+        V_VT(&strv) = VT_EMPTY;
+        hres = VariantChangeTypeEx(&strv, &v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
+        if(FAILED(hres))
+            return hres;
+
+        *str = jsstr_alloc(V_BSTR(&strv));
+        SysFreeString(V_BSTR(&strv));
+    }
+
+    return *str ? S_OK : E_OUTOFMEMORY;
 }
 
 /* ECMA-262 3rd Edition    9.8 */
-HRESULT to_string(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, BSTR *str)
+HRESULT to_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str)
 {
-    const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
     const WCHAR nullW[] = {'n','u','l','l',0};
     const WCHAR trueW[] = {'t','r','u','e',0};
     const WCHAR falseW[] = {'f','a','l','s','e',0};
-    const WCHAR NaNW[] = {'N','a','N',0};
-    const WCHAR InfinityW[] = {'-','I','n','f','i','n','i','t','y',0};
 
-    switch(V_VT(v)) {
-    case VT_EMPTY:
-        *str = SysAllocString(undefinedW);
-        break;
-    case VT_NULL:
-        *str = SysAllocString(nullW);
-        break;
-    case VT_I4:
-        *str = int_to_bstr(V_I4(v));
-        break;
-    case VT_R8: {
-        if(isnan(V_R8(v)))
-            *str = SysAllocString(NaNW);
-        else if(isinf(V_R8(v)))
-            *str = SysAllocString(V_R8(v)<0 ? InfinityW : InfinityW+1);
-        else {
-            VARIANT strv;
-            HRESULT hres;
-
-            V_VT(&strv) = VT_EMPTY;
-            hres = VariantChangeTypeEx(&strv, v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
-            if(FAILED(hres))
-                return hres;
-
-            *str = V_BSTR(&strv);
-            return S_OK;
-        }
+    switch(jsval_type(val)) {
+    case JSV_UNDEFINED:
+        *str = jsstr_undefined();
+        return S_OK;
+    case JSV_NULL:
+        *str = jsstr_alloc(nullW);
         break;
-    }
-    case VT_BSTR:
-        *str = SysAllocString(V_BSTR(v));
+    case JSV_NUMBER:
+        return double_to_string(get_number(val), str);
+    case JSV_STRING:
+        *str = jsstr_addref(get_string(val));
         break;
-    case VT_DISPATCH: {
-        VARIANT prim;
+    case JSV_OBJECT: {
+        jsval_t prim;
         HRESULT hres;
 
-        hres = to_primitive(ctx, v, ei, &prim, HINT_STRING);
+        hres = to_primitive(ctx, val, &prim, HINT_STRING);
         if(FAILED(hres))
             return hres;
 
-        hres = to_string(ctx, &prim, ei, str);
-        VariantClear(&prim);
+        hres = to_string(ctx, prim, str);
+        jsval_release(prim);
         return hres;
     }
-    case VT_BOOL:
-        *str = SysAllocString(V_BOOL(v) ? trueW : falseW);
+    case JSV_BOOL:
+        *str = jsstr_alloc(get_bool(val) ? trueW : falseW);
         break;
     default:
-        FIXME("unsupported vt %d\n", V_VT(v));
+        FIXME("unsupported %s\n", debugstr_jsval(val));
         return E_NOTIMPL;
     }
 
@@ -591,52 +778,241 @@ HRESULT to_string(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, BSTR *str)
 }
 
 /* ECMA-262 3rd Edition    9.9 */
-HRESULT to_object(script_ctx_t *ctx, VARIANT *v, IDispatch **disp)
+HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp)
 {
-    DispatchEx *dispex;
+    jsdisp_t *dispex;
     HRESULT hres;
 
-    switch(V_VT(v)) {
-    case VT_BSTR:
-        hres = create_string(ctx, V_BSTR(v), SysStringLen(V_BSTR(v)), &dispex);
+    switch(jsval_type(val)) {
+    case JSV_STRING:
+        hres = create_string(ctx, get_string(val), &dispex);
         if(FAILED(hres))
             return hres;
 
-        *disp = (IDispatch*)_IDispatchEx_(dispex);
+        *disp = to_disp(dispex);
         break;
-    case VT_I4:
-    case VT_R8:
-        hres = create_number(ctx, v, &dispex);
+    case JSV_NUMBER:
+        hres = create_number(ctx, get_number(val), &dispex);
         if(FAILED(hres))
             return hres;
 
-        *disp = (IDispatch*)_IDispatchEx_(dispex);
+        *disp = to_disp(dispex);
         break;
-    case VT_DISPATCH:
-        if(V_DISPATCH(v)) {
-            IDispatch_AddRef(V_DISPATCH(v));
-            *disp = V_DISPATCH(v);
+    case JSV_OBJECT:
+        if(get_object(val)) {
+            *disp = get_object(val);
+            IDispatch_AddRef(*disp);
         }else {
-            DispatchEx *obj;
+            jsdisp_t *obj;
 
             hres = create_object(ctx, NULL, &obj);
             if(FAILED(hres))
                 return hres;
 
-            *disp = (IDispatch*)_IDispatchEx_(obj);
+            *disp = to_disp(obj);
         }
         break;
-    case VT_BOOL:
-        hres = create_bool(ctx, V_BOOL(v), &dispex);
+    case JSV_BOOL:
+        hres = create_bool(ctx, get_bool(val), &dispex);
         if(FAILED(hres))
             return hres;
 
-        *disp = (IDispatch*)_IDispatchEx_(dispex);
+        *disp = to_disp(dispex);
+        break;
+    case JSV_UNDEFINED:
+    case JSV_NULL:
+        WARN("object expected\n");
+        return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
+    case JSV_VARIANT:
+        switch(V_VT(get_variant(val))) {
+        case VT_ARRAY|VT_VARIANT:
+            hres = create_vbarray(ctx, V_ARRAY(get_variant(val)), &dispex);
+            if(FAILED(hres))
+                return hres;
+
+            *disp = to_disp(dispex);
+            break;
+
+        default:
+            FIXME("Unsupported %s\n", debugstr_variant(get_variant(val)));
+            return E_NOTIMPL;
+        }
+        break;
+    }
+
+    return S_OK;
+}
+
+HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTYPE vt)
+{
+    jsval_t val;
+    HRESULT hres;
+
+    clear_ei(ctx);
+    hres = variant_to_jsval(src, &val);
+    if(FAILED(hres))
+        return hres;
+
+    switch(vt) {
+    case VT_I2:
+    case VT_I4: {
+        INT i;
+
+        hres = to_int32(ctx, val, &i);
+        if(SUCCEEDED(hres)) {
+            if(vt == VT_I4)
+                V_I4(dst) = i;
+            else
+                V_I2(dst) = i;
+        }
+        break;
+    }
+    case VT_R8: {
+        double n;
+        hres = to_number(ctx, val, &n);
+        if(SUCCEEDED(hres))
+            V_R8(dst) = n;
+        break;
+    }
+    case VT_R4: {
+        double n;
+
+        hres = to_number(ctx, val, &n);
+        if(SUCCEEDED(hres))
+            V_R4(dst) = n;
+        break;
+    }
+    case VT_BOOL: {
+        BOOL b;
+
+        hres = to_boolean(val, &b);
+        if(SUCCEEDED(hres))
+            V_BOOL(dst) = b ? VARIANT_TRUE : VARIANT_FALSE;
+        break;
+    }
+    case VT_BSTR: {
+        jsstr_t *str;
+
+        hres = to_string(ctx, val, &str);
+        if(FAILED(hres))
+            break;
+
+        if(str->length_flags & JSSTR_FLAG_NULLBSTR) {
+            V_BSTR(dst) = NULL;
+            break;
+        }
+
+        V_BSTR(dst) = SysAllocStringLen(NULL, jsstr_length(str));
+        if(V_BSTR(dst))
+            jsstr_flush(str, V_BSTR(dst));
+        else
+            hres = E_OUTOFMEMORY;
+        break;
+    }
+    case VT_EMPTY:
+        hres = V_VT(src) == VT_EMPTY ? S_OK : E_NOTIMPL;
+        break;
+    case VT_NULL:
+        hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL;
         break;
     default:
-        FIXME("unsupported vt %d\n", V_VT(v));
-        return E_NOTIMPL;
+        FIXME("vt %d not implemented\n", vt);
+        hres = E_NOTIMPL;
     }
 
+    jsval_release(val);
+    if(FAILED(hres))
+        return hres;
+
+    V_VT(dst) = vt;
+    return S_OK;
+}
+
+static inline JSCaller *impl_from_IServiceProvider(IServiceProvider *iface)
+{
+    return CONTAINING_RECORD(iface, JSCaller, IServiceProvider_iface);
+}
+
+static HRESULT WINAPI JSCaller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
+{
+    JSCaller *This = impl_from_IServiceProvider(iface);
+
+    if(IsEqualGUID(&IID_IUnknown, riid)) {
+        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
+        *ppv = &This->IServiceProvider_iface;
+    }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
+        TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
+        *ppv = &This->IServiceProvider_iface;
+    }else {
+        WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI JSCaller_AddRef(IServiceProvider *iface)
+{
+    JSCaller *This = impl_from_IServiceProvider(iface);
+    LONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) ref=%d\n", This, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI JSCaller_Release(IServiceProvider *iface)
+{
+    JSCaller *This = impl_from_IServiceProvider(iface);
+    LONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) ref=%d\n", This, ref);
+
+    if(!ref) {
+        assert(!This->ctx);
+        heap_free(This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID guidService,
+        REFIID riid, void **ppv)
+{
+    JSCaller *This = impl_from_IServiceProvider(iface);
+
+    if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) {
+        TRACE("(%p)->(SID_VariantConversion)\n", This);
+        return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv);
+    }
+
+    FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
+
+    *ppv = NULL;
+    return E_NOINTERFACE;
+}
+
+static const IServiceProviderVtbl ServiceProviderVtbl = {
+    JSCaller_QueryInterface,
+    JSCaller_AddRef,
+    JSCaller_Release,
+    JSCaller_QueryService
+};
+
+HRESULT create_jscaller(script_ctx_t *ctx)
+{
+    JSCaller *ret;
+
+    ret = heap_alloc(sizeof(*ret));
+    if(!ret)
+        return E_OUTOFMEMORY;
+
+    ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
+    ret->ref = 1;
+    ret->ctx = ctx;
+
+    ctx->jscaller = ret;
     return S_OK;
 }
diff --git a/reactos/dll/win32/jscript/jsval.h b/reactos/dll/win32/jscript/jsval.h
new file mode 100644 (file)
index 0000000..963f59f
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * 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
index 80810b4..1d3e07d 100644 (file)
@@ -16,7 +16,9 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <math.h>
+#include "config.h"
+#include "wine/port.h"
+
 //#include <limits.h>
 
 #include "jscript.h"
@@ -57,7 +59,6 @@ static const WCHAR throwW[] = {'t','h','r','o','w',0};
 static const WCHAR trueW[] = {'t','r','u','e',0};
 static const WCHAR tryW[] = {'t','r','y',0};
 static const WCHAR typeofW[] = {'t','y','p','e','o','f',0};
-static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
 static const WCHAR varW[] = {'v','a','r',0};
 static const WCHAR voidW[] = {'v','o','i','d',0};
 static const WCHAR whileW[] = {'w','h','i','l','e',0};
@@ -66,11 +67,12 @@ static const WCHAR withW[] = {'w','i','t','h',0};
 static const struct {
     const WCHAR *word;
     int token;
+    BOOL no_nl;
 } keywords[] = {
-    {breakW,       kBREAK},
+    {breakW,       kBREAK, TRUE},
     {caseW,        kCASE},
     {catchW,       kCATCH},
-    {continueW,    kCONTINUE},
+    {continueW,    kCONTINUE, TRUE},
     {defaultW,     kDEFAULT},
     {deleteW,      kDELETE},
     {doW,          kDO},
@@ -84,7 +86,7 @@ static const struct {
     {instanceofW,  kINSTANCEOF},
     {newW,         kNEW},
     {nullW,        kNULL},
-    {returnW,      kRETURN},
+    {returnW,      kRETURN, TRUE},
     {switchW,      kSWITCH},
     {thisW,        kTHIS},
     {throwW,       kTHROW},
@@ -99,7 +101,7 @@ static const struct {
 
 static int lex_error(parser_ctx_t *ctx, HRESULT hres)
 {
-    ctx->hres = JSCRIPT_ERROR|hres;
+    ctx->hres = hres;
     ctx->lexer_error = TRUE;
     return -1;
 }
@@ -125,7 +127,8 @@ static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lva
     if(*p2 || (p1 < ctx->end && is_identifier_char(*p1)))
         return 1;
 
-    *lval = ctx->ptr;
+    if(lval)
+        *lval = ctx->ptr;
     ctx->ptr = p1;
     return 0;
 }
@@ -158,8 +161,10 @@ static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval)
         i = (min+max)/2;
 
         r = check_keyword(ctx, keywords[i].word, lval);
-        if(!r)
+        if(!r) {
+            ctx->implicit_nl_semicolon = keywords[i].no_nl;
             return keywords[i].token;
+        }
 
         if(r > 0)
             min = i+1;
@@ -170,14 +175,6 @@ static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval)
     return 0;
 }
 
-static void skip_spaces(parser_ctx_t *ctx)
-{
-    while(ctx->ptr < ctx->end && isspaceW(*ctx->ptr)) {
-        if(is_endline(*ctx->ptr++))
-            ctx->nl = TRUE;
-    }
-}
-
 static BOOL skip_html_comment(parser_ctx_t *ctx)
 {
     const WCHAR html_commentW[] = {'<','!','-','-',0};
@@ -194,12 +191,23 @@ static BOOL skip_html_comment(parser_ctx_t *ctx)
 
 static BOOL skip_comment(parser_ctx_t *ctx)
 {
-    if(ctx->ptr+1 >= ctx->end || *ctx->ptr != '/')
+    if(ctx->ptr+1 >= ctx->end)
         return FALSE;
 
+    if(*ctx->ptr != '/') {
+        if(*ctx->ptr == '@' && ctx->ptr+2 < ctx->end && ctx->ptr[1] == '*' && ctx->ptr[2] == '/') {
+            ctx->ptr += 3;
+            return TRUE;
+        }
+
+        return FALSE;
+    }
+
     switch(ctx->ptr[1]) {
     case '*':
         ctx->ptr += 2;
+        if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
+            return FALSE;
         while(ctx->ptr+1 < ctx->end && (ctx->ptr[0] != '*' || ctx->ptr[1] != '/'))
             ctx->ptr++;
 
@@ -212,6 +220,8 @@ static BOOL skip_comment(parser_ctx_t *ctx)
         break;
     case '/':
         ctx->ptr += 2;
+        if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
+            return FALSE;
         while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr))
             ctx->ptr++;
         break;
@@ -235,7 +245,6 @@ static BOOL unescape(WCHAR *str)
         }
 
         p++;
-        c = 0;
 
         switch(*p) {
         case '\'':
@@ -252,9 +261,6 @@ static BOOL unescape(WCHAR *str)
         case 'n':
             c = '\n';
             break;
-        case 'v':
-            c = '\v';
-            break;
         case 'f':
             c = '\f';
             break;
@@ -327,7 +333,7 @@ static int parse_identifier(parser_ctx_t *ctx, const WCHAR **ret)
     len = ctx->ptr-ptr;
 
     *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
-    memcpy(wstr, ptr, (len+1)*sizeof(WCHAR));
+    memcpy(wstr, ptr, len*sizeof(WCHAR));
     wstr[len] = 0;
 
     /* FIXME: unescape */
@@ -346,12 +352,12 @@ static int parse_string_literal(parser_ctx_t *ctx, const WCHAR **ret, WCHAR endc
     }
 
     if(ctx->ptr == ctx->end)
-        return lex_error(ctx, IDS_UNTERMINATED_STR);
+        return lex_error(ctx, JS_E_UNTERMINATED_STRING);
 
     len = ctx->ptr-ptr;
 
     *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
-    memcpy(wstr, ptr, (len+1)*sizeof(WCHAR));
+    memcpy(wstr, ptr, len*sizeof(WCHAR));
     wstr[len] = 0;
 
     ctx->ptr++;
@@ -364,12 +370,21 @@ static int parse_string_literal(parser_ctx_t *ctx, const WCHAR **ret, WCHAR endc
     return tStringLiteral;
 }
 
-static literal_t *alloc_int_literal(parser_ctx_t *ctx, LONG l)
+static literal_t *new_double_literal(parser_ctx_t *ctx, DOUBLE d)
 {
     literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
 
-    ret->type = LT_INT;
-    ret->u.lval = l;
+    ret->type = LT_DOUBLE;
+    ret->u.dval = d;
+    return ret;
+}
+
+literal_t *new_boolean_literal(parser_ctx_t *ctx, BOOL bval)
+{
+    literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
+
+    ret->type = LT_BOOL;
+    ret->u.bval = bval;
 
     return ret;
 }
@@ -379,12 +394,6 @@ static int parse_double_literal(parser_ctx_t *ctx, LONG int_part, literal_t **li
     LONGLONG d, hlp;
     int exp = 0;
 
-    if(ctx->ptr == ctx->end || (!isdigitW(*ctx->ptr) &&
-        *ctx->ptr!='.' && *ctx->ptr!='e' && *ctx->ptr!='E')) {
-        ERR("Illegal character\n");
-        return 0;
-    }
-
     d = int_part;
     while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
         hlp = d*10 + *(ctx->ptr++) - '0';
@@ -400,18 +409,20 @@ static int parse_double_literal(parser_ctx_t *ctx, LONG int_part, literal_t **li
         ctx->ptr++;
     }
 
-    if(*ctx->ptr == '.') ctx->ptr++;
+    if(*ctx->ptr == '.') {
+        ctx->ptr++;
 
-    while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
-        hlp = d*10 + *(ctx->ptr++) - '0';
-        if(d>LONGLONG_MAX/10 || hlp<0)
-            break;
+        while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
+            hlp = d*10 + *(ctx->ptr++) - '0';
+            if(d>LONGLONG_MAX/10 || hlp<0)
+                break;
 
-        d = hlp;
-        exp--;
+            d = hlp;
+            exp--;
+        }
+        while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
+            ctx->ptr++;
     }
-    while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
-        ctx->ptr++;
 
     if(ctx->ptr < ctx->end && (*ctx->ptr == 'e' || *ctx->ptr == 'E')) {
         int sign = 1, e = 0;
@@ -445,10 +456,7 @@ static int parse_double_literal(parser_ctx_t *ctx, LONG int_part, literal_t **li
         else exp += e;
     }
 
-    *literal = parser_alloc(ctx, sizeof(literal_t));
-    (*literal)->type = LT_DOUBLE;
-    (*literal)->u.dval = (double)d*pow(10, exp);
-
+    *literal = new_double_literal(ctx, exp>=0 ? d*pow(10, exp) : d/pow(10, -exp));
     return tNumericLiteral;
 }
 
@@ -457,15 +465,10 @@ static int parse_numeric_literal(parser_ctx_t *ctx, literal_t **literal)
     LONG l, d;
 
     l = *ctx->ptr++ - '0';
-    if(ctx->ptr == ctx->end) {
-        *literal = alloc_int_literal(ctx, l);
-        return tNumericLiteral;
-    }
-
     if(!l) {
         if(*ctx->ptr == 'x' || *ctx->ptr == 'X') {
             if(++ctx->ptr == ctx->end) {
-                ERR("unexpexted end of file\n");
+                ERR("unexpected end of file\n");
                 return 0;
             }
 
@@ -479,58 +482,43 @@ static int parse_numeric_literal(parser_ctx_t *ctx, literal_t **literal)
                 return lex_error(ctx, E_FAIL);
             }
 
-            *literal = alloc_int_literal(ctx, l);
+            *literal = new_double_literal(ctx, l);
             return tNumericLiteral;
         }
 
-        if(isdigitW(*ctx->ptr) || is_identifier_char(*ctx->ptr)) {
+        if(is_identifier_char(*ctx->ptr)) {
             WARN("wrong char after zero\n");
             return lex_error(ctx, E_FAIL);
         }
 
-        *literal = alloc_int_literal(ctx, 0);
-    }
-
-    while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
-    {
-        d = l*10 + *(ctx->ptr)-'0';
-
-        /* Check for integer overflow */
-        if (l > INT_MAX/10 || d < 0)
-            return parse_double_literal(ctx, l, literal);
-
-        l = d;
-        ctx->ptr++;
-    }
-
-    if(ctx->ptr < ctx->end) {
-        if(*ctx->ptr == '.' || *ctx->ptr == 'e' || *ctx->ptr == 'E')
-            return parse_double_literal(ctx, l, literal);
-
-        if(is_identifier_char(*ctx->ptr)) {
-            WARN("unexpected identifier char\n");
-            return lex_error(ctx, E_FAIL);
+        if(isdigitW(*ctx->ptr)) {
+            FIXME("octal literals not implemented\n");
+            return lex_error(ctx, E_NOTIMPL);
         }
     }
 
-    *literal = alloc_int_literal(ctx, l);
-    return tNumericLiteral;
+    return parse_double_literal(ctx, l, literal);
 }
 
-int parser_lex(void *lval, parser_ctx_t *ctx)
+static int next_token(parser_ctx_t *ctx, void *lval)
 {
-    int ret;
-
-    ctx->nl = ctx->ptr == ctx->begin;
-
     do {
-        skip_spaces(ctx);
+        while(ctx->ptr < ctx->end && isspaceW(*ctx->ptr)) {
+            if(is_endline(*ctx->ptr++))
+                ctx->nl = TRUE;
+        }
         if(ctx->ptr == ctx->end)
-            return 0;
+            return tEOF;
     }while(skip_comment(ctx) || skip_html_comment(ctx));
 
+    if(ctx->implicit_nl_semicolon) {
+        if(ctx->nl)
+            return ';';
+        ctx->implicit_nl_semicolon = FALSE;
+    }
+
     if(isalphaW(*ctx->ptr)) {
-        ret = check_keywords(ctx, lval);
+        int ret = check_keywords(ctx, lval);
         if(ret)
             return ret;
 
@@ -748,32 +736,225 @@ int parser_lex(void *lval, parser_ctx_t *ctx)
     case '_':
     case '$':
         return parse_identifier(ctx, lval);
+
+    case '@':
+        return '@';
     }
 
     WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr);
     return 0;
 }
 
+struct _cc_var_t {
+    BOOL is_num;
+    union {
+        BOOL b;
+        DOUBLE n;
+    } u;
+    struct _cc_var_t *next;
+    unsigned name_len;
+    WCHAR name[0];
+};
+
+void release_cc(cc_ctx_t *cc)
+{
+    cc_var_t *iter, *next;
+
+    for(iter = cc->vars; iter; iter = next) {
+        next = iter->next;
+        heap_free(iter);
+    }
+
+    heap_free(cc);
+}
+
+static BOOL add_cc_var(cc_ctx_t *cc, const WCHAR *name, cc_var_t *v)
+{
+    cc_var_t *new_v;
+    unsigned len;
+
+    len = strlenW(name);
+
+    new_v = heap_alloc(sizeof(cc_var_t) + (len+1)*sizeof(WCHAR));
+    if(!new_v)
+        return FALSE;
+
+    memcpy(new_v, v, sizeof(*v));
+    memcpy(new_v->name, name, (len+1)*sizeof(WCHAR));
+    new_v->name_len = len;
+    new_v->next = cc->vars;
+    cc->vars = new_v;
+    return TRUE;
+}
+
+static cc_var_t *find_cc_var(cc_ctx_t *cc, const WCHAR *name, unsigned name_len)
+{
+    cc_var_t *iter;
+
+    for(iter = cc->vars; iter; iter = iter->next) {
+        if(iter->name_len == name_len && !memcmp(iter->name, name, name_len*sizeof(WCHAR)))
+            return iter;
+    }
+
+    return NULL;
+}
+
+static int init_cc(parser_ctx_t *ctx)
+{
+    cc_ctx_t *cc;
+    cc_var_t v;
+
+    static const WCHAR _win32W[] = {'_','w','i','n','3','2',0};
+    static const WCHAR _win64W[] = {'_','w','i','n','6','4',0};
+    static const WCHAR _x86W[] = {'_','x','8','6',0};
+    static const WCHAR _amd64W[] = {'_','a','m','d','6','4',0};
+    static const WCHAR _jscriptW[] = {'_','j','s','c','r','i','p','t',0};
+    static const WCHAR _jscript_buildW[] = {'_','j','s','c','r','i','p','t','_','b','u','i','l','d',0};
+    static const WCHAR _jscript_versionW[] = {'_','j','s','c','r','i','p','t','_','v','e','r','s','i','o','n',0};
+
+    if(ctx->script->cc)
+        return 0;
+
+    cc = heap_alloc(sizeof(cc_ctx_t));
+    if(!cc)
+        return lex_error(ctx, E_OUTOFMEMORY);
+
+    cc->vars = NULL;
+    v.is_num = FALSE;
+    v.u.b = TRUE;
+    if(!add_cc_var(cc, _jscriptW, &v)
+       || !add_cc_var(cc, sizeof(void*) == 8 ? _win64W : _win32W, &v)
+       || !add_cc_var(cc, sizeof(void*) == 8 ? _amd64W : _x86W, &v)) {
+        release_cc(cc);
+        return lex_error(ctx, E_OUTOFMEMORY);
+    }
+
+    v.is_num = TRUE;
+    v.u.n = JSCRIPT_BUILD_VERSION;
+    if(!add_cc_var(cc, _jscript_buildW, &v)) {
+        release_cc(cc);
+        return lex_error(ctx, E_OUTOFMEMORY);
+    }
+
+    v.u.n = JSCRIPT_MAJOR_VERSION + (DOUBLE)JSCRIPT_MINOR_VERSION/10.0;
+    if(!add_cc_var(cc, _jscript_versionW, &v)) {
+        release_cc(cc);
+        return lex_error(ctx, E_OUTOFMEMORY);
+    }
+
+    ctx->script->cc = cc;
+    return 0;
+}
+
+static int cc_token(parser_ctx_t *ctx, void *lval)
+{
+    unsigned id_len = 0;
+    cc_var_t *var;
+
+    static const WCHAR cc_onW[] = {'c','c','_','o','n',0};
+    static const WCHAR setW[] = {'s','e','t',0};
+    static const WCHAR elifW[] = {'e','l','i','f',0};
+    static const WCHAR endW[] = {'e','n','d',0};
+
+    ctx->ptr++;
+
+    if(!check_keyword(ctx, cc_onW, NULL))
+        return init_cc(ctx);
+
+    if(!check_keyword(ctx, setW, NULL)) {
+        FIXME("@set not implemented\n");
+        return lex_error(ctx, E_NOTIMPL);
+    }
+
+    if(!check_keyword(ctx, ifW, NULL)) {
+        FIXME("@if not implemented\n");
+        return lex_error(ctx, E_NOTIMPL);
+    }
+
+    if(!check_keyword(ctx, elifW, NULL)) {
+        FIXME("@elif not implemented\n");
+        return lex_error(ctx, E_NOTIMPL);
+    }
+
+    if(!check_keyword(ctx, elseW, NULL)) {
+        FIXME("@else not implemented\n");
+        return lex_error(ctx, E_NOTIMPL);
+    }
+
+    if(!check_keyword(ctx, endW, NULL)) {
+        FIXME("@end not implemented\n");
+        return lex_error(ctx, E_NOTIMPL);
+    }
+
+    if(!ctx->script->cc)
+        return lex_error(ctx, JS_E_DISABLED_CC);
+
+    while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len]))
+        id_len++;
+    if(!id_len)
+        return '@';
+
+    TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len));
+
+    var = find_cc_var(ctx->script->cc, ctx->ptr, id_len);
+    ctx->ptr += id_len;
+    if(!var || var->is_num) {
+        *(literal_t**)lval = new_double_literal(ctx, var ? var->u.n : NAN);
+        return tNumericLiteral;
+    }
+
+    *(literal_t**)lval = new_boolean_literal(ctx, var->u.b);
+    return tBooleanLiteral;
+}
+
+int parser_lex(void *lval, parser_ctx_t *ctx)
+{
+    int ret;
+
+    ctx->nl = ctx->ptr == ctx->begin;
+
+    do {
+        ret = next_token(ctx, lval);
+    } while(ret == '@' && !(ret = cc_token(ctx, lval)));
+
+    return ret;
+}
+
 literal_t *parse_regexp(parser_ctx_t *ctx)
 {
     const WCHAR *re, *flags_ptr;
+    BOOL in_class = FALSE;
     DWORD re_len, flags;
     literal_t *ret;
     HRESULT hres;
 
     TRACE("\n");
 
-    while(*ctx->ptr != '/')
-        ctx->ptr--;
+    while(*--ctx->ptr != '/');
 
+    /* Simple regexp pre-parser; '/' if used in char class does not terminate regexp literal */
     re = ++ctx->ptr;
-    while(ctx->ptr < ctx->end && *ctx->ptr != '/') {
-        if(*ctx->ptr++ == '\\' && ctx->ptr < ctx->end)
-            ctx->ptr++;
+    while(ctx->ptr < ctx->end) {
+        if(*ctx->ptr == '\\') {
+            if(++ctx->ptr == ctx->end)
+                break;
+        }else if(in_class) {
+            if(*ctx->ptr == '\n')
+                break;
+            if(*ctx->ptr == ']')
+                in_class = FALSE;
+        }else {
+            if(*ctx->ptr == '/')
+                break;
+
+            if(*ctx->ptr == '[')
+                in_class = TRUE;
+        }
+        ctx->ptr++;
     }
 
-    if(ctx->ptr == ctx->end) {
-        WARN("unexpected end of file\n");
+    if(ctx->ptr == ctx->end || *ctx->ptr != '/') {
+        WARN("pre-parsing failed\n");
         return NULL;
     }
 
index 1068426..19acd30 100644 (file)
@@ -57,520 +57,448 @@ static const WCHAR sinW[] = {'s','i','n',0};
 static const WCHAR sqrtW[] = {'s','q','r','t',0};
 static const WCHAR tanW[] = {'t','a','n',0};
 
-static HRESULT math_constant(DOUBLE val, WORD flags, VARIANT *retv)
-{
-    switch(flags) {
-    case DISPATCH_PROPERTYGET:
-        V_VT(retv) = VT_R8;
-        V_R8(retv) = val;
-        return S_OK;
-    case DISPATCH_PROPERTYPUT:
-        return S_OK;
-    }
-
-    FIXME("unhandled flags %x\n", flags);
-    return E_NOTIMPL;
-}
-
-/* ECMA-262 3rd Edition    15.8.1.1 */
-static HRESULT Math_E(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-    return math_constant(M_E, flags, retv);
-}
-
-/* ECMA-262 3rd Edition    15.8.1.4 */
-static HRESULT Math_LOG2E(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-    return math_constant(M_LOG2E, flags, retv);
-}
-
-/* ECMA-262 3rd Edition    15.8.1.4 */
-static HRESULT Math_LOG10E(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-    return math_constant(M_LOG10E, flags, retv);
-}
-
-static HRESULT Math_LN2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-    return math_constant(M_LN2, flags, retv);
-}
-
-static HRESULT Math_LN10(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-    return math_constant(M_LN10, flags, retv);
-}
-
-/* ECMA-262 3rd Edition    15.8.1.6 */
-static HRESULT Math_PI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-    return math_constant(M_PI, flags, retv);
-}
-
-static HRESULT Math_SQRT2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-    return math_constant(M_SQRT2, flags, retv);
-}
-
-static HRESULT Math_SQRT1_2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-    return math_constant(M_SQRT1_2, flags, retv);
-}
-
 /* ECMA-262 3rd Edition    15.8.2.12 */
-static HRESULT Math_abs(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_abs(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
-    DOUBLE d;
+    double d;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv)
-            num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &d);
     if(FAILED(hres))
         return hres;
 
-    d = num_val(&v);
-    if(retv)
-        num_set_val(retv, d < 0.0 ? -d : d);
+    if(r)
+        *r = jsval_number(d < 0.0 ? -d : d);
     return S_OK;
 }
 
-static HRESULT Math_acos(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_acos(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv) num_set_val(retv, acos(num_val(&v)));
+    if(r)
+        *r = jsval_number(x < -1.0 || x > 1.0 ? NAN : acos(x));
     return S_OK;
 }
 
-static HRESULT Math_asin(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_asin(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv) num_set_val(retv, asin(num_val(&v)));
+    if(r)
+        *r = jsval_number(x < -1.0 || x > 1.0 ? NAN : asin(x));
     return S_OK;
 }
 
-static HRESULT Math_atan(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_atan(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv) num_set_val(retv, atan(num_val(&v)));
+    if(r)
+        *r = jsval_number(atan(x));
     return S_OK;
 }
 
-static HRESULT Math_atan2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_atan2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v1, v2;
+    double x, y;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(arg_cnt(dp)<2) {
-        if(retv) num_set_nan(retv);
+    if(argc<2) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v1);
+    hres = to_number(ctx, argv[0], &y);
     if(FAILED(hres))
         return hres;
 
-    hres = to_number(ctx, get_arg(dp, 1), ei, &v2);
+    hres = to_number(ctx, argv[1], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv) num_set_val(retv, atan2(num_val(&v1), num_val(&v2)));
+    if(r)
+        *r = jsval_number(atan2(y, x));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.8.2.6 */
-static HRESULT Math_ceil(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_ceil(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv)
-            num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv)
-        num_set_val(retv, ceil(num_val(&v)));
+    if(r)
+        *r = jsval_number(ceil(x));
     return S_OK;
 }
 
-static HRESULT Math_cos(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_cos(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv) num_set_val(retv, cos(num_val(&v)));
+    if(r)
+        *r = jsval_number(cos(x));
     return S_OK;
 }
 
-static HRESULT Math_exp(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_exp(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv) num_set_val(retv, exp(num_val(&v)));
+    if(r)
+        *r = jsval_number(exp(x));
     return S_OK;
 }
 
-static HRESULT Math_floor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_floor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv)
-            num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv)
-        num_set_val(retv, floor(num_val(&v)));
+    if(r)
+        *r = jsval_number(floor(x));
     return S_OK;
 }
 
-static HRESULT Math_log(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_log(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv)
-            num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv)
-        num_set_val(retv, log(num_val(&v)));
+    if(r)
+        *r = jsval_number(x < -0.0 ? NAN : log(x));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.8.2.11 */
-static HRESULT Math_max(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_max(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DOUBLE max, d;
-    VARIANT v;
     DWORD i;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv)
-            num_set_inf(retv, FALSE);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(-INFINITY);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &max);
     if(FAILED(hres))
         return hres;
 
-    max = num_val(&v);
-    for(i=1; i < arg_cnt(dp); i++) {
-        hres = to_number(ctx, get_arg(dp, i), ei, &v);
+    for(i=1; i < argc; i++) {
+        hres = to_number(ctx, argv[i], &d);
         if(FAILED(hres))
             return hres;
 
-        d = num_val(&v);
         if(d > max || isnan(d))
             max = d;
     }
 
-    if(retv)
-        num_set_val(retv, max);
+    if(r)
+        *r = jsval_number(max);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.8.2.12 */
-static HRESULT Math_min(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_min(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     DOUBLE min, d;
-    VARIANT v;
     DWORD i;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv)
-            num_set_inf(retv, TRUE);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(INFINITY);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &min);
     if(FAILED(hres))
         return hres;
 
-    min = num_val(&v);
-    for(i=1; i < arg_cnt(dp); i++) {
-        hres = to_number(ctx, get_arg(dp, i), ei, &v);
+    for(i=1; i < argc; i++) {
+        hres = to_number(ctx, argv[i], &d);
         if(FAILED(hres))
             return hres;
 
-        d = num_val(&v);
         if(d < min || isnan(d))
             min = d;
     }
 
-    if(retv)
-        num_set_val(retv, min);
+    if(r)
+        *r = jsval_number(min);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.8.2.13 */
-static HRESULT Math_pow(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_pow(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT x, y;
+    double x, y;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(arg_cnt(dp) < 2) {
-        if(retv) num_set_nan(retv);
+    if(argc < 2) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &x);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    hres = to_number(ctx, get_arg(dp, 1), ei, &y);
+    hres = to_number(ctx, argv[1], &y);
     if(FAILED(hres))
         return hres;
 
-    if(retv)
-        num_set_val(retv, pow(num_val(&x), num_val(&y)));
+    if(r)
+        *r = jsval_number(pow(x, y));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.8.2.14 */
-static HRESULT Math_random(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_random(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    UINT r;
+    UINT x;
 
     TRACE("\n");
 
-    if(!RtlGenRandom(&r, sizeof(r)))
+    if(!RtlGenRandom(&x, sizeof(x)))
         return E_UNEXPECTED;
 
-    if(retv)
-        num_set_val(retv, (DOUBLE)r/(DOUBLE)UINT_MAX);
-
+    if(r)
+        *r = jsval_number((double)x/(double)UINT_MAX);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.8.2.15 */
-static HRESULT Math_round(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_round(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv)
-        num_set_val(retv, floor(num_val(&v)+0.5));
+    if(r)
+        *r = jsval_number(floor(x+0.5));
     return S_OK;
 }
 
-static HRESULT Math_sin(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_sin(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv) num_set_val(retv, sin(num_val(&v)));
+    if(r)
+        *r = jsval_number(sin(x));
     return S_OK;
 }
 
-static HRESULT Math_sqrt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_sqrt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv) num_set_val(retv, sqrt(num_val(&v)));
+    if(r)
+        *r = jsval_number(sqrt(x));
     return S_OK;
 }
 
-static HRESULT Math_tan(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Math_tan(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT v;
+    double x;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) num_set_nan(retv);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(NAN);
         return S_OK;
     }
 
-    hres = to_number(ctx, get_arg(dp, 0), ei, &v);
+    hres = to_number(ctx, argv[0], &x);
     if(FAILED(hres))
         return hres;
 
-    if(retv) num_set_val(retv, tan(num_val(&v)));
+    if(r)
+        *r = jsval_number(tan(x));
     return S_OK;
 }
 
 static const builtin_prop_t Math_props[] = {
-    {EW,        Math_E,        0},
-    {LN10W,     Math_LN10,     0},
-    {LN2W,      Math_LN2,      0},
-    {LOG10EW,   Math_LOG10E,   0},
-    {LOG2EW,    Math_LOG2E,    0},
-    {PIW,       Math_PI,       0},
-    {SQRT1_2W,  Math_SQRT1_2,  0},
-    {SQRT2W,    Math_SQRT2,    0},
     {absW,      Math_abs,      PROPF_METHOD|1},
     {acosW,     Math_acos,     PROPF_METHOD|1},
     {asinW,     Math_asin,     PROPF_METHOD|1},
@@ -600,12 +528,27 @@ static const builtin_info_t Math_info = {
     NULL
 };
 
-HRESULT create_math(script_ctx_t *ctx, DispatchEx **ret)
+HRESULT create_math(script_ctx_t *ctx, jsdisp_t **ret)
 {
-    DispatchEx *math;
+    jsdisp_t *math;
+    unsigned i;
     HRESULT hres;
 
-    math = heap_alloc_zero(sizeof(DispatchEx));
+    struct {
+        const WCHAR *name;
+        DOUBLE val;
+    }constants[] = {
+        {EW,        M_E},        /* ECMA-262 3rd Edition    15.8.1.1 */
+        {LN10W,     M_LN10},     /* ECMA-262 3rd Edition    15.8.1.2 */
+        {LN2W,      M_LN2},      /* ECMA-262 3rd Edition    15.8.1.3 */
+        {LOG2EW,    M_LOG2E},    /* ECMA-262 3rd Edition    15.8.1.4 */
+        {LOG10EW,   M_LOG10E},   /* ECMA-262 3rd Edition    15.8.1.5 */
+        {PIW,       M_PI},       /* ECMA-262 3rd Edition    15.8.1.6 */
+        {SQRT1_2W,  M_SQRT1_2},  /* ECMA-262 3rd Edition    15.8.1.7 */
+        {SQRT2W,    M_SQRT2},    /* ECMA-262 3rd Edition    15.8.1.8 */
+    };
+
+    math = heap_alloc_zero(sizeof(jsdisp_t));
     if(!math)
         return E_OUTOFMEMORY;
 
@@ -615,6 +558,14 @@ HRESULT create_math(script_ctx_t *ctx, DispatchEx **ret)
         return hres;
     }
 
+    for(i=0; i < sizeof(constants)/sizeof(*constants); i++) {
+        hres = jsdisp_propput_const(math, constants[i].name, jsval_number(constants[i].val));
+        if(FAILED(hres)) {
+            jsdisp_release(math);
+            return hres;
+        }
+    }
+
     *ret = math;
     return S_OK;
 }
index bbf9df1..e51fdd5 100644 (file)
@@ -20,6 +20,7 @@
 #include <wine/port.h>
 
 //#include <math.h>
+#include <assert.h>
 
 #include "jscript.h"
 
@@ -28,9 +29,9 @@
 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 
 typedef struct {
-    DispatchEx dispex;
+    jsdisp_t dispex;
 
-    VARIANT num;
+    double value;
 } NumberInstance;
 
 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
@@ -41,6 +42,7 @@ static const WCHAR toPrecisionW[] = {'t','o','P','r','e','c','i','s','i','o','n'
 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
 
 #define NUMBER_TOSTRING_BUF_SIZE 64
+#define NUMBER_DTOA_SIZE 18
 
 static inline NumberInstance *number_from_vdisp(vdisp_t *vdisp)
 {
@@ -52,41 +54,211 @@ static inline NumberInstance *number_this(vdisp_t *jsthis)
     return is_vclass(jsthis, JSCLASS_NUMBER) ? number_from_vdisp(jsthis) : NULL;
 }
 
+static inline void dtoa(double d, WCHAR *buf, int size, int *dec_point)
+{
+    ULONGLONG l;
+    int i;
+
+    /* TODO: this function should print doubles with bigger precision */
+    assert(size>=2 && size<=NUMBER_DTOA_SIZE && d>=0);
+
+    if(d == 0)
+        *dec_point = 0;
+    else
+        *dec_point = floor(log10(d));
+    l = d*pow(10, size-*dec_point-1);
+
+    if(l%10 >= 5)
+        l = l/10+1;
+    else
+        l /= 10;
+
+    buf[size-1] = 0;
+    for(i=size-2; i>=0; i--) {
+        buf[i] = '0'+l%10;
+        l /= 10;
+    }
+
+    /* log10 was wrong by 1 or rounding changed number of digits */
+    if(l) {
+        (*dec_point)++;
+        memmove(buf+1, buf, size-2);
+        buf[0] = '0'+l;
+    }else if(buf[0]=='0' && buf[1]>='1' && buf[1]<='9') {
+        (*dec_point)--;
+        memmove(buf, buf+1, size-2);
+        buf[size-2] = '0';
+    }
+}
+
+static inline jsstr_t *number_to_fixed(double val, int prec)
+{
+    WCHAR buf[NUMBER_DTOA_SIZE];
+    int dec_point, size, buf_size, buf_pos;
+    BOOL neg = FALSE;
+    jsstr_t *ret;
+    WCHAR *str;
+
+    TRACE("%lf %d\n", val, prec);
+
+    if(val < 0) {
+        neg = TRUE;
+        val = -val;
+    }
+
+    if(val >= 1)
+        buf_size = log10(val)+prec+2;
+    else
+        buf_size = prec ? prec+1 : 2;
+    if(buf_size > NUMBER_DTOA_SIZE)
+        buf_size = NUMBER_DTOA_SIZE;
+
+    dtoa(val, buf, buf_size, &dec_point);
+    dec_point++;
+    size = 0;
+    if(neg)
+        size++;
+    if(dec_point > 0)
+        size += dec_point;
+    else
+        size++;
+    if(prec)
+        size += prec+1;
+
+    ret = jsstr_alloc_buf(size);
+    if(!ret)
+        return NULL;
+
+    str = ret->str;
+    size = buf_pos = 0;
+    if(neg)
+        str[size++] = '-';
+    if(dec_point > 0) {
+        for(;buf_pos<buf_size-1 && dec_point; dec_point--)
+            str[size++] = buf[buf_pos++];
+    }else {
+        str[size++] = '0';
+    }
+    for(; dec_point>0; dec_point--)
+        str[size++] = '0';
+    if(prec) {
+        str[size++] = '.';
+
+        for(; dec_point<0 && prec; dec_point++, prec--)
+            str[size++] = '0';
+        for(; buf_pos<buf_size-1 && prec; prec--)
+            str[size++] = buf[buf_pos++];
+        for(; prec; prec--) {
+            str[size++] = '0';
+        }
+    }
+    str[size++] = 0;
+    return ret;
+}
+
+static inline jsstr_t *number_to_exponential(double val, int prec)
+{
+    WCHAR buf[NUMBER_DTOA_SIZE], *pbuf;
+    int dec_point, size, buf_size, exp_size = 1;
+    BOOL neg = FALSE;
+    jsstr_t *ret;
+    WCHAR *str;
+
+    if(val < 0) {
+        neg = TRUE;
+        val = -val;
+    }
+
+    buf_size = prec+2;
+    if(buf_size<2 || buf_size>NUMBER_DTOA_SIZE)
+        buf_size = NUMBER_DTOA_SIZE;
+    dtoa(val, buf, buf_size, &dec_point);
+    buf_size--;
+    if(prec == -1)
+        for(; buf_size>1 && buf[buf_size-1]=='0'; buf_size--)
+            buf[buf_size-1] = 0;
+
+    size = 10;
+    while(dec_point>=size || dec_point<=-size) {
+        size *= 10;
+        exp_size++;
+    }
+
+    if(buf_size == 1)
+        size = buf_size+2+exp_size; /* 2 = strlen(e+) */
+    else if(prec == -1)
+        size = buf_size+3+exp_size; /* 3 = strlen(.e+) */
+    else
+        size = prec+4+exp_size; /* 4 = strlen(0.e+) */
+    if(neg)
+        size++;
+
+    ret = jsstr_alloc_buf(size);
+    if(!ret)
+        return NULL;
+
+    str = ret->str;
+    size = 0;
+    pbuf = buf;
+    if(neg)
+        str[size++] = '-';
+    str[size++] = *pbuf++;
+    if(buf_size != 1) {
+        str[size++] = '.';
+        while(*pbuf)
+            str[size++] = *pbuf++;
+        for(; prec>buf_size-1; prec--)
+            str[size++] = '0';
+    }
+    str[size++] = 'e';
+    if(dec_point >= 0) {
+        str[size++] = '+';
+    }else {
+        str[size++] = '-';
+        dec_point = -dec_point;
+    }
+    size += exp_size;
+    do {
+        str[--size] = '0'+dec_point%10;
+        dec_point /= 10;
+    }while(dec_point>0);
+    size += exp_size;
+    str[size] = 0;
+
+    return ret;
+}
+
 /* ECMA-262 3rd Edition    15.7.4.2 */
-static HRESULT Number_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Number_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     NumberInstance *number;
     INT radix = 10;
     DOUBLE val;
-    BSTR str;
+    jsstr_t *str;
     HRESULT hres;
 
     TRACE("\n");
 
     if(!(number = number_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_NUM, NULL);
+        return throw_type_error(ctx, JS_E_NUMBER_EXPECTED, NULL);
 
-    if(arg_cnt(dp)) {
-        hres = to_int32(ctx, get_arg(dp, 0), ei, &radix);
+    if(argc) {
+        hres = to_int32(ctx, argv[0], &radix);
         if(FAILED(hres))
             return hres;
 
         if(radix<2 || radix>36)
-            return throw_type_error(ctx, ei, IDS_INVALID_CALL_ARG, NULL);
+            return throw_type_error(ctx, JS_E_INVALIDARG, NULL);
     }
 
-    if(V_VT(&number->num) == VT_I4)
-        val = V_I4(&number->num);
-    else
-        val = V_R8(&number->num);
+    val = number->value;
 
     if(radix==10 || isnan(val) || isinf(val)) {
-        hres = to_string(ctx, &number->num, ei, &str);
+        hres = to_string(ctx, jsval_number(val), &str);
         if(FAILED(hres))
             return hres;
-    }
-    else {
+    }else {
         INT idx = 0;
         DOUBLE integ, frac, log_radix = 0;
         WCHAR buf[NUMBER_TOSTRING_BUF_SIZE+16];
@@ -150,7 +322,7 @@ static HRESULT Number_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, D
 
         if(exp) {
             if(log_radix==0)
-                buf[idx++] = '\0';
+                buf[idx] = 0;
             else {
                 static const WCHAR formatW[] = {'(','e','%','c','%','d',')',0};
                 WCHAR ch;
@@ -165,73 +337,181 @@ static HRESULT Number_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, D
         }
         else buf[idx] = '\0';
 
-        str = SysAllocString(buf);
+        str = jsstr_alloc(buf);
         if(!str)
             return E_OUTOFMEMORY;
     }
 
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = str;
-    }else {
-        SysFreeString(str);
-    }
+    if(r)
+        *r = jsval_string(str);
+    else
+        jsstr_release(str);
     return S_OK;
 }
 
-static HRESULT Number_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Number_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT Number_toFixed(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Number_toFixed(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    NumberInstance *number;
+    DOUBLE val;
+    INT prec = 0;
+    jsstr_t *str;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    if(!(number = number_this(jsthis)))
+        return throw_type_error(ctx, JS_E_NUMBER_EXPECTED, NULL);
+
+    if(argc) {
+        hres = to_int32(ctx, argv[0], &prec);
+        if(FAILED(hres))
+            return hres;
+
+        if(prec<0 || prec>20)
+            return throw_range_error(ctx, JS_E_FRACTION_DIGITS_OUT_OF_RANGE, NULL);
+    }
+
+    val = number->value;
+    if(isinf(val) || isnan(val)) {
+        hres = to_string(ctx, jsval_number(val), &str);
+        if(FAILED(hres))
+            return hres;
+    }else {
+        str = number_to_fixed(val, prec);
+        if(!str)
+            return E_OUTOFMEMORY;
+    }
+
+    if(r)
+        *r = jsval_string(str);
+    else
+        jsstr_release(str);
+    return S_OK;
 }
 
-static HRESULT Number_toExponential(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Number_toExponential(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    NumberInstance *number;
+    DOUBLE val;
+    INT prec = 0;
+    jsstr_t *str;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    if(!(number = number_this(jsthis)))
+        return throw_type_error(ctx, JS_E_NUMBER_EXPECTED, NULL);
+
+    if(argc) {
+        hres = to_int32(ctx, argv[0], &prec);
+        if(FAILED(hres))
+            return hres;
+
+        if(prec<0 || prec>20)
+            return throw_range_error(ctx, JS_E_FRACTION_DIGITS_OUT_OF_RANGE, NULL);
+    }
+
+    val = number->value;
+    if(isinf(val) || isnan(val)) {
+        hres = to_string(ctx, jsval_number(val), &str);
+        if(FAILED(hres))
+            return hres;
+    }else {
+        if(!prec)
+            prec--;
+        str = number_to_exponential(val, prec);
+        if(!str)
+            return E_OUTOFMEMORY;
+    }
+
+    if(r)
+        *r = jsval_string(str);
+    else
+        jsstr_release(str);
+    return S_OK;
 }
 
-static HRESULT Number_toPrecision(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Number_toPrecision(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    NumberInstance *number;
+    INT prec = 0, size;
+    jsstr_t *str;
+    DOUBLE val;
+    HRESULT hres;
+
+    if(!(number = number_this(jsthis)))
+        return throw_type_error(ctx, JS_E_NUMBER_EXPECTED, NULL);
+
+    if(argc) {
+        hres = to_int32(ctx, argv[0], &prec);
+        if(FAILED(hres))
+            return hres;
+
+        if(prec<1 || prec>21)
+            return throw_range_error(ctx, JS_E_PRECISION_OUT_OF_RANGE, NULL);
+    }
+
+    val = number->value;
+    if(isinf(val) || isnan(val) || !prec) {
+        hres = to_string(ctx, jsval_number(val), &str);
+        if(FAILED(hres))
+            return hres;
+    }else {
+        if(val != 0)
+            size = floor(log10(val>0 ? val : -val)) + 1;
+        else
+            size = 1;
+
+        if(size > prec)
+            str = number_to_exponential(val, prec-1);
+        else
+            str = number_to_fixed(val, prec-size);
+        if(!str)
+            return E_OUTOFMEMORY;
+    }
+
+    if(r)
+        *r = jsval_string(str);
+    else
+        jsstr_release(str);
+    return S_OK;
 }
 
-static HRESULT Number_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Number_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     NumberInstance *number;
 
     TRACE("\n");
 
     if(!(number = number_this(jsthis)))
-        return throw_type_error(ctx, ei, IDS_NOT_NUM, NULL);
+        return throw_type_error(ctx, JS_E_NUMBER_EXPECTED, NULL);
 
-    if(retv)
-        *retv = number->num;
+    if(r)
+        *r = jsval_number(number->value);
     return S_OK;
 }
 
-static HRESULT Number_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Number_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     NumberInstance *number = number_from_vdisp(jsthis);
 
     switch(flags) {
     case INVOKE_FUNC:
-        return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
+        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
     case DISPATCH_PROPERTYGET:
-        *retv = number->num;
+        *r = jsval_number(number->value);
         break;
 
     default:
@@ -260,50 +540,54 @@ static const builtin_info_t Number_info = {
     NULL
 };
 
-static HRESULT NumberConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static const builtin_info_t NumberInst_info = {
+    JSCLASS_NUMBER,
+    {NULL, Number_value, 0},
+    0, NULL,
+    NULL,
+    NULL
+};
+
+static HRESULT NumberConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    VARIANT num;
+    double n;
     HRESULT hres;
 
     TRACE("\n");
 
     switch(flags) {
     case INVOKE_FUNC:
-        if(!arg_cnt(dp)) {
-            if(retv) {
-                V_VT(retv) = VT_I4;
-                V_I4(retv) = 0;
-            }
+        if(!argc) {
+            if(r)
+                *r = jsval_number(0);
             return S_OK;
         }
 
-        hres = to_number(ctx, get_arg(dp, 0), ei, &num);
+        hres = to_number(ctx, argv[0], &n);
         if(FAILED(hres))
             return hres;
 
-        if(retv)
-            *retv = num;
+        if(r)
+            *r = jsval_number(n);
         break;
 
     case DISPATCH_CONSTRUCT: {
-        DispatchEx *obj;
+        jsdisp_t *obj;
 
-        if(arg_cnt(dp)) {
-            hres = to_number(ctx, get_arg(dp, 0), ei, &num);
+        if(argc) {
+            hres = to_number(ctx, argv[0], &n);
             if(FAILED(hres))
                 return hres;
         }else {
-            V_VT(&num) = VT_I4;
-            V_I4(&num) = 0;
+            n = 0;
         }
 
-        hres = create_number(ctx, &num, &obj);
+        hres = create_number(ctx, n, &obj);
         if(FAILED(hres))
             return hres;
 
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(obj);
+        *r = jsval_obj(obj);
         break;
     }
     default:
@@ -314,7 +598,7 @@ static HRESULT NumberConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
     return S_OK;
 }
 
-static HRESULT alloc_number(script_ctx_t *ctx, DispatchEx *object_prototype, NumberInstance **ret)
+static HRESULT alloc_number(script_ctx_t *ctx, jsdisp_t *object_prototype, NumberInstance **ret)
 {
     NumberInstance *number;
     HRESULT hres;
@@ -326,15 +610,17 @@ static HRESULT alloc_number(script_ctx_t *ctx, DispatchEx *object_prototype, Num
     if(object_prototype)
         hres = init_dispex(&number->dispex, ctx, &Number_info, object_prototype);
     else
-        hres = init_dispex_from_constr(&number->dispex, ctx, &Number_info, ctx->number_constr);
-    if(FAILED(hres))
+        hres = init_dispex_from_constr(&number->dispex, ctx, &NumberInst_info, ctx->number_constr);
+    if(FAILED(hres)) {
+        heap_free(number);
         return hres;
+    }
 
     *ret = number;
     return S_OK;
 }
 
-HRESULT create_number_constr(script_ctx_t *ctx, DispatchEx *object_prototype, DispatchEx **ret)
+HRESULT create_number_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
 {
     NumberInstance *number;
     HRESULT hres;
@@ -345,15 +631,15 @@ HRESULT create_number_constr(script_ctx_t *ctx, DispatchEx *object_prototype, Di
     if(FAILED(hres))
         return hres;
 
-    V_VT(&number->num) = VT_I4;
-    hres = create_builtin_function(ctx, NumberConstr_value, NumberW, NULL,
+    number->value = 0;
+    hres = create_builtin_constructor(ctx, NumberConstr_value, NumberW, NULL,
             PROPF_CONSTR|1, &number->dispex, ret);
 
     jsdisp_release(&number->dispex);
     return hres;
 }
 
-HRESULT create_number(script_ctx_t *ctx, VARIANT *num, DispatchEx **ret)
+HRESULT create_number(script_ctx_t *ctx, double value, jsdisp_t **ret)
 {
     NumberInstance *number;
     HRESULT hres;
@@ -362,7 +648,7 @@ HRESULT create_number(script_ctx_t *ctx, VARIANT *num, DispatchEx **ret)
     if(FAILED(hres))
         return hres;
 
-    number->num = *num;
+    number->value = value;
 
     *ret = &number->dispex;
     return S_OK;
index e039ee3..25cd17f 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include <assert.h>
+
 #include "jscript.h"
 
 #include <wine/debug.h>
@@ -32,10 +34,10 @@ static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','
 
 static const WCHAR default_valueW[] = {'[','o','b','j','e','c','t',' ','O','b','j','e','c','t',']',0};
 
-static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *jsdisp;
+    jsdisp_t *jsdisp;
     const WCHAR *str;
 
     static const WCHAR formatW[] = {'[','o','b','j','e','c','t',' ','%','s',']',0};
@@ -51,8 +53,8 @@ static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, D
     static const WCHAR regexpW[] = {'R','e','g','E','x','p',0};
     static const WCHAR stringW[] = {'S','t','r','i','n','g',0};
     /* Keep in sync with jsclass_t enum */
-    static const WCHAR *names[] = {objectW, arrayW, booleanW, dateW, errorW,
-        functionW, NULL, mathW, numberW, objectW, regexpW, stringW, objectW};
+    static const WCHAR *names[] = {NULL, arrayW, booleanW, dateW, errorW,
+        functionW, NULL, mathW, numberW, objectW, regexpW, stringW, objectW, objectW};
 
     TRACE("\n");
 
@@ -62,27 +64,28 @@ static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, D
     }else if(names[jsdisp->builtin_info->class]) {
         str = names[jsdisp->builtin_info->class];
     }else {
+        assert(jsdisp->builtin_info->class != JSCLASS_NONE);
         FIXME("jdisp->builtin_info->class = %d\n", jsdisp->builtin_info->class);
         return E_FAIL;
     }
 
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = SysAllocStringLen(NULL, 9+strlenW(str));
-        if(!V_BSTR(retv))
+    if(r) {
+        jsstr_t *ret;
+
+        ret = jsstr_alloc_buf(9+strlenW(str));
+        if(!ret)
             return E_OUTOFMEMORY;
 
-        sprintfW(V_BSTR(retv), formatW, str);
+        sprintfW(ret->str, formatW, str);
+        *r = jsval_string(ret);
     }
 
     return S_OK;
 }
 
-static HRESULT Object_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Object_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DISPPARAMS params = {NULL, NULL, 0, 0};
-
     TRACE("\n");
 
     if(!is_jsdisp(jsthis)) {
@@ -90,59 +93,128 @@ static HRESULT Object_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD fl
         return E_FAIL;
     }
 
-    return jsdisp_call_name(jsthis->u.jsdisp, toStringW, DISPATCH_METHOD, &params, retv, ei, sp);
+    return jsdisp_call_name(jsthis->u.jsdisp, toStringW, DISPATCH_METHOD, 0, NULL, r);
 }
 
-static HRESULT Object_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Object_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    if(retv) {
+    if(r) {
         IDispatch_AddRef(jsthis->u.disp);
-
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = jsthis->u.disp;
+        *r = jsval_disp(jsthis->u.disp);
     }
-
     return S_OK;
 }
 
-static HRESULT Object_hasOwnProperty(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Object_hasOwnProperty(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    jsstr_t *name;
+    DISPID id;
+    BSTR bstr;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    if(!argc) {
+        if(r)
+            *r = jsval_bool(FALSE);
+        return S_OK;
+    }
+
+    hres = to_string(ctx, argv[0], &name);
+    if(FAILED(hres))
+        return hres;
+
+    if(is_jsdisp(jsthis)) {
+        BOOL result;
+
+        hres = jsdisp_is_own_prop(jsthis->u.jsdisp, name->str, &result);
+        jsstr_release(name);
+        if(FAILED(hres))
+            return hres;
+
+        if(r)
+            *r = jsval_bool(result);
+        return S_OK;
+    }
+
+
+    bstr = SysAllocStringLen(NULL, jsstr_length(name));
+    if(bstr)
+        jsstr_flush(name, bstr);
+    jsstr_release(name);
+    if(!bstr)
+        return E_OUTOFMEMORY;
+
+    if(is_dispex(jsthis))
+        hres = IDispatchEx_GetDispID(jsthis->u.dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive), &id);
+    else
+        hres = IDispatch_GetIDsOfNames(jsthis->u.disp, &IID_NULL, &bstr, 1, ctx->lcid, &id);
+
+    SysFreeString(bstr);
+    if(r)
+        *r = jsval_bool(SUCCEEDED(hres));
+    return S_OK;
 }
 
-static HRESULT Object_propertyIsEnumerable(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Object_propertyIsEnumerable(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    jsstr_t *name;
+    BOOL ret;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    if(argc != 1) {
+        FIXME("argc %d not supported\n", argc);
+        return E_NOTIMPL;
+    }
+
+    if(!is_jsdisp(jsthis)) {
+        FIXME("Host object this\n");
+        return E_FAIL;
+    }
+
+    hres = to_string(ctx, argv[0], &name);
+    if(FAILED(hres))
+        return hres;
+
+    hres = jsdisp_is_enumerable(jsthis->u.jsdisp, name->str, &ret);
+    jsstr_release(name);
+    if(FAILED(hres))
+        return hres;
+
+    if(r)
+        *r = jsval_bool(ret);
+    return S_OK;
 }
 
-static HRESULT Object_isPrototypeOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Object_isPrototypeOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT Object_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT Object_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
     switch(flags) {
     case INVOKE_FUNC:
-        return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
-    case DISPATCH_PROPERTYGET:
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = SysAllocString(default_valueW);
-        if(!V_BSTR(retv))
+        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
+    case DISPATCH_PROPERTYGET: {
+        jsstr_t *ret = jsstr_alloc(default_valueW);
+        if(!ret)
             return E_OUTOFMEMORY;
+        *r = jsval_string(ret);
         break;
+    }
     default:
         FIXME("unimplemented flags %x\n", flags);
         return E_NOTIMPL;
@@ -151,7 +223,7 @@ static HRESULT Object_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
     return S_OK;
 }
 
-static void Object_destructor(DispatchEx *dispex)
+static void Object_destructor(jsdisp_t *dispex)
 {
     heap_free(dispex);
 }
@@ -174,8 +246,16 @@ static const builtin_info_t Object_info = {
     NULL
 };
 
-static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static const builtin_info_t ObjectInst_info = {
+    JSCLASS_OBJECT,
+    {NULL, Object_value, 0},
+    0, NULL,
+    Object_destructor,
+    NULL
+};
+
+static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     HRESULT hres;
 
@@ -183,35 +263,33 @@ static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
 
     switch(flags) {
     case DISPATCH_METHOD:
-        if(arg_cnt(dp)) {
-            VARIANT *arg = get_arg(dp,0);
-
-            if(V_VT(arg) != VT_EMPTY && V_VT(arg) != VT_NULL) {
+        if(argc) {
+            if(!is_undefined(argv[0]) && !is_null(argv[0]) && (!is_object_instance(argv[0]) || get_object(argv[0]))) {
                 IDispatch *disp;
 
-                hres = to_object(ctx, arg, &disp);
+                hres = to_object(ctx, argv[0], &disp);
                 if(FAILED(hres))
                     return hres;
 
-                if(retv) {
-                    V_VT(retv) = VT_DISPATCH;
-                    V_DISPATCH(retv) = disp;
-                }else {
+                if(r)
+                    *r = jsval_disp(disp);
+                else
                     IDispatch_Release(disp);
-                }
                 return S_OK;
             }
         }
         /* fall through */
     case DISPATCH_CONSTRUCT: {
-        DispatchEx *obj;
+        jsdisp_t *obj;
 
         hres = create_object(ctx, NULL, &obj);
         if(FAILED(hres))
             return hres;
 
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(obj);
+        if(r)
+            *r = jsval_obj(obj);
+        else
+            jsdisp_release(obj);
         break;
     }
 
@@ -223,29 +301,29 @@ static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
     return S_OK;
 }
 
-HRESULT create_object_constr(script_ctx_t *ctx, DispatchEx *object_prototype, DispatchEx **ret)
+HRESULT create_object_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
 {
     static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
 
-    return create_builtin_function(ctx, ObjectConstr_value, ObjectW, NULL, PROPF_CONSTR,
+    return create_builtin_constructor(ctx, ObjectConstr_value, ObjectW, NULL, PROPF_CONSTR,
             object_prototype, ret);
 }
 
-HRESULT create_object_prototype(script_ctx_t *ctx, DispatchEx **ret)
+HRESULT create_object_prototype(script_ctx_t *ctx, jsdisp_t **ret)
 {
     return create_dispex(ctx, &Object_info, NULL, ret);
 }
 
-HRESULT create_object(script_ctx_t *ctx, DispatchEx *constr, DispatchEx **ret)
+HRESULT create_object(script_ctx_t *ctx, jsdisp_t *constr, jsdisp_t **ret)
 {
-    DispatchEx *object;
+    jsdisp_t *object;
     HRESULT hres;
 
-    object = heap_alloc_zero(sizeof(DispatchEx));
+    object = heap_alloc_zero(sizeof(jsdisp_t));
     if(!object)
         return E_OUTOFMEMORY;
 
-    hres = init_dispex_from_constr(object, ctx, &Object_info, constr ? constr : ctx->object_constr);
+    hres = init_dispex_from_constr(object, ctx, &ObjectInst_info, constr ? constr : ctx->object_constr);
     if(FAILED(hres)) {
         heap_free(object);
         return hres;
index e3307bd..310ab13 100644 (file)
 #include "jscript.h"
 #include "engine.h"
 
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(jscript);
+
 #define YYLEX_PARAM ctx
 #define YYPARSE_PARAM ctx
 
@@ -90,7 +94,6 @@ static void set_error(parser_ctx_t*,UINT);
 static BOOL explicit_error(parser_ctx_t*,void*,WCHAR);
 static BOOL allow_auto_semicolon(parser_ctx_t*);
 static void program_parsed(parser_ctx_t*,source_elements_t*);
-static source_elements_t *function_body_parsed(parser_ctx_t*,source_elements_t*);
 
 typedef struct _statement_list_t {
     statement_t *head;
@@ -99,7 +102,6 @@ typedef struct _statement_list_t {
 
 static literal_t *new_string_literal(parser_ctx_t*,const WCHAR*);
 static literal_t *new_null_literal(parser_ctx_t*);
-static literal_t *new_boolean_literal(parser_ctx_t*,VARIANT_BOOL);
 
 typedef struct _property_list_t {
     prop_val_t *head;
@@ -145,9 +147,9 @@ static variable_declaration_t *new_variable_declaration(parser_ctx_t*,const WCHA
 static variable_list_t *new_variable_list(parser_ctx_t*,variable_declaration_t*);
 static variable_list_t *variable_list_add(parser_ctx_t*,variable_list_t*,variable_declaration_t*);
 
+static void *new_statement(parser_ctx_t*,statement_type_t,size_t);
 static statement_t *new_block_statement(parser_ctx_t*,statement_list_t*);
 static statement_t *new_var_statement(parser_ctx_t*,variable_list_t*);
-static statement_t *new_empty_statement(parser_ctx_t*);
 static statement_t *new_expression_statement(parser_ctx_t*,expression_t*);
 static statement_t *new_if_statement(parser_ctx_t*,expression_t*,statement_t*,statement_t*);
 static statement_t *new_while_statement(parser_ctx_t*,BOOL,expression_t*,statement_t*);
@@ -179,22 +181,15 @@ typedef struct _parameter_list_t {
 static parameter_list_t *new_parameter_list(parser_ctx_t*,const WCHAR*);
 static parameter_list_t *parameter_list_add(parser_ctx_t*,parameter_list_t*,const WCHAR*);
 
-static void push_func(parser_ctx_t*);
-static inline void pop_func(parser_ctx_t *ctx)
-{
-    ctx->func_stack = ctx->func_stack->next;
-}
-
+static void *new_expression(parser_ctx_t *ctx,expression_type_t,size_t);
 static expression_t *new_function_expression(parser_ctx_t*,const WCHAR*,parameter_list_t*,
         source_elements_t*,const WCHAR*,DWORD);
 static expression_t *new_binary_expression(parser_ctx_t*,expression_type_t,expression_t*,expression_t*);
 static expression_t *new_unary_expression(parser_ctx_t*,expression_type_t,expression_t*);
 static expression_t *new_conditional_expression(parser_ctx_t*,expression_t*,expression_t*,expression_t*);
-static expression_t *new_array_expression(parser_ctx_t*,expression_t*,expression_t*);
 static expression_t *new_member_expression(parser_ctx_t*,expression_t*,const WCHAR*);
 static expression_t *new_new_expression(parser_ctx_t*,expression_t*,argument_list_t*);
 static expression_t *new_call_expression(parser_ctx_t*,expression_t*,argument_list_t*);
-static expression_t *new_this_expression(parser_ctx_t*);
 static expression_t *new_identifier_expression(parser_ctx_t*,const WCHAR*);
 static expression_t *new_literal_expression(parser_ctx_t*,literal_t*);
 static expression_t *new_array_literal_expression(parser_ctx_t*,element_list_t*,int);
@@ -206,7 +201,7 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state
 
 
 /* Line 189 of yacc.c  */
-#line 210 "parser.tab.c"
+#line 205 "parser.tab.c"
 
 /* Enabling traces.  */
 #ifndef YYDEBUG
@@ -273,8 +268,10 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state
      tShiftOper = 295,
      tRelOper = 296,
      tNumericLiteral = 297,
-     tStringLiteral = 298,
-     LOWER_THAN_ELSE = 299
+     tBooleanLiteral = 298,
+     tStringLiteral = 299,
+     tEOF = 300,
+     LOWER_THAN_ELSE = 301
    };
 #endif
 
@@ -285,7 +282,7 @@ typedef union YYSTYPE
 {
 
 /* Line 214 of yacc.c  */
-#line 150 "parser.y"
+#line 145 "parser.y"
 
     int                     ival;
     const WCHAR             *srcptr;
@@ -309,7 +306,7 @@ typedef union YYSTYPE
 
 
 /* Line 214 of yacc.c  */
-#line 313 "parser.tab.c"
+#line 310 "parser.tab.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -321,7 +318,7 @@ typedef union YYSTYPE
 
 
 /* Line 264 of yacc.c  */
-#line 325 "parser.tab.c"
+#line 322 "parser.tab.c"
 
 #ifdef short
 # undef short
@@ -536,20 +533,20 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  3
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   1030
+#define YYLAST   1053
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  67
+#define YYNTOKENS  69
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  95
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  214
+#define YYNRULES  215
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  373
+#define YYNSTATES  375
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   299
+#define YYMAXUTOK   301
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -560,16 +557,16 @@ static const yytype_uint8 yytranslate[] =
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    61,     2,     2,     2,    59,    54,     2,
-      65,    66,    57,    55,    47,    56,    64,    58,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    50,    49,
-       2,    48,     2,    51,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,    63,     2,     2,     2,    61,    56,     2,
+      67,    68,    59,    57,    49,    58,    66,    60,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    52,    51,
+       2,    50,     2,    53,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    62,     2,    63,    53,     2,     2,     2,     2,     2,
+       2,    64,     2,    65,    55,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    46,    52,    37,    60,     2,     2,     2,
+       2,     2,     2,    48,    54,    37,    62,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -586,7 +583,8 @@ static const yytype_uint8 yytranslate[] =
        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,    38,    39,    40,    41,    42,    43,    44,    45
+      35,    36,    38,    39,    40,    41,    42,    43,    44,    45,
+      46,    47
 };
 
 #if YYDEBUG
@@ -594,126 +592,127 @@ static const yytype_uint8 yytranslate[] =
    YYRHS.  */
 static const yytype_uint16 yyprhs[] =
 {
-       0,     0,     3,     6,     8,     9,    10,    13,    22,    24,
-      26,    28,    32,    33,    35,    37,    39,    41,    43,    45,
-      47,    49,    51,    53,    55,    57,    59,    61,    63,    65,
-      67,    70,    71,    73,    77,    80,    84,    86,    90,    92,
-      96,    99,   102,   103,   105,   108,   109,   111,   114,   116,
-     119,   127,   133,   141,   147,   148,   149,   161,   162,   163,
-     176,   184,   193,   197,   201,   205,   211,   215,   221,   225,
-     231,   232,   234,   236,   239,   244,   248,   252,   256,   260,
-     265,   271,   274,   275,   277,   279,   281,   283,   287,   288,
-     290,   292,   296,   298,   300,   302,   306,   310,   312,   316,
-     320,   322,   328,   330,   336,   338,   342,   344,   348,   350,
-     354,   356,   360,   362,   366,   368,   372,   374,   378,   380,
-     384,   386,   390,   392,   396,   398,   402,   404,   408,   410,
-     414,   418,   422,   424,   428,   432,   434,   438,   440,   444,
-     448,   450,   454,   458,   462,   464,   467,   470,   473,   476,
-     479,   482,   485,   488,   491,   493,   496,   499,   501,   503,
-     505,   508,   510,   512,   517,   521,   525,   528,   531,   536,
-     540,   543,   547,   549,   553,   555,   557,   559,   561,   563,
-     567,   570,   574,   578,   584,   587,   592,   594,   597,   598,
-     600,   603,   607,   611,   617,   619,   621,   623,   624,   626,
-     628,   630,   632,   634,   636,   638,   640,   642,   644,   646,
-     648,   650,   652,   654,   656
+       0,     0,     3,     7,     9,    10,    11,    14,    23,    25,
+      27,    29,    33,    34,    36,    38,    40,    42,    44,    46,
+      48,    50,    52,    54,    56,    58,    60,    62,    64,    66,
+      68,    71,    72,    74,    78,    81,    85,    87,    91,    93,
+      97,   100,   103,   104,   106,   109,   110,   112,   115,   117,
+     120,   128,   134,   142,   148,   149,   150,   162,   163,   164,
+     177,   185,   194,   198,   202,   206,   212,   216,   222,   226,
+     232,   233,   235,   237,   240,   245,   249,   253,   257,   261,
+     266,   272,   275,   276,   278,   280,   282,   284,   288,   289,
+     291,   293,   297,   299,   301,   303,   307,   311,   313,   317,
+     321,   323,   329,   331,   337,   339,   343,   345,   349,   351,
+     355,   357,   361,   363,   367,   369,   373,   375,   379,   381,
+     385,   387,   391,   393,   397,   399,   403,   405,   409,   411,
+     415,   419,   423,   425,   429,   433,   435,   439,   441,   445,
+     449,   451,   455,   459,   463,   465,   468,   471,   474,   477,
+     480,   483,   486,   489,   492,   494,   497,   500,   502,   504,
+     506,   509,   511,   513,   518,   522,   526,   529,   532,   537,
+     541,   544,   548,   550,   554,   556,   558,   560,   562,   564,
+     568,   571,   575,   579,   585,   588,   593,   595,   598,   599,
+     601,   604,   608,   612,   618,   620,   622,   624,   625,   627,
+     629,   631,   633,   635,   637,   639,   641,   643,   645,   647,
+     649,   651,   653,   655,   657,   659
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int16 yyrhs[] =
 {
-      68,     0,    -1,    70,    69,    -1,    34,    -1,    -1,    -1,
-      70,    76,    -1,    72,   155,   159,    75,   160,    46,    73,
-      37,    -1,    36,    -1,    70,    -1,    38,    -1,    74,    47,
-      38,    -1,    -1,    74,    -1,    79,    -1,    80,    -1,    89,
-      -1,    71,    -1,    90,    -1,    91,    -1,    92,    -1,    97,
-      -1,    98,    -1,    99,    -1,   100,    -1,   101,    -1,   102,
-      -1,   108,    -1,   109,    -1,    76,    -1,    77,    76,    -1,
-      -1,    77,    -1,    46,    77,    37,    -1,    46,    37,    -1,
-      26,    81,   158,    -1,    83,    -1,    81,    47,    83,    -1,
-      84,    -1,    82,    47,    84,    -1,    38,    85,    -1,    38,
-      87,    -1,    -1,    86,    -1,    48,   118,    -1,    -1,    88,
-      -1,    48,   119,    -1,    49,    -1,   114,   158,    -1,    11,
-     159,   113,   160,    76,    10,    76,    -1,    11,   159,   113,
-     160,    76,    -1,     9,    76,    28,   159,   113,   160,   158,
-      -1,    28,   159,   113,   160,    76,    -1,    -1,    -1,    13,
-     159,   115,    93,   161,   112,    94,   161,   112,   160,    76,
-      -1,    -1,    -1,    13,   159,    26,    82,    95,   161,   112,
-      96,   161,   112,   160,    76,    -1,    13,   159,   141,    14,
-     113,   160,    76,    -1,    13,   159,    26,    84,    14,   113,
-     160,    76,    -1,     6,   155,   158,    -1,     3,   155,   158,
-      -1,    18,   112,   158,    -1,    29,   159,   114,   160,    76,
-      -1,    38,    50,    76,    -1,    19,   159,   114,   160,   103,
-      -1,    46,   104,    37,    -1,    46,   104,   107,   104,    37,
-      -1,    -1,   105,    -1,   106,    -1,   105,   106,    -1,     4,
-     114,    50,    78,    -1,     7,    50,    78,    -1,    21,   114,
-     158,    -1,    24,    79,   110,    -1,    24,    79,   111,    -1,
-      24,    79,   110,   111,    -1,     5,   159,    38,   160,    79,
-      -1,    12,    79,    -1,    -1,   114,    -1,   114,    -1,     1,
-      -1,   118,    -1,   114,    47,   118,    -1,    -1,   116,    -1,
-     119,    -1,   116,    47,   119,    -1,    39,    -1,    35,    -1,
-     120,    -1,   141,    48,   118,    -1,   141,   117,   118,    -1,
-     121,    -1,   141,    48,   119,    -1,   141,   117,   119,    -1,
-     122,    -1,   122,    51,   118,    50,   118,    -1,   123,    -1,
-     123,    51,   119,    50,   119,    -1,   124,    -1,   122,    31,
-     124,    -1,   125,    -1,   123,    31,   125,    -1,   126,    -1,
-     124,    30,   126,    -1,   127,    -1,   125,    30,   127,    -1,
-     128,    -1,   126,    52,   128,    -1,   129,    -1,   127,    52,
-     129,    -1,   130,    -1,   128,    53,   130,    -1,   131,    -1,
-     129,    53,   131,    -1,   132,    -1,   130,    54,   132,    -1,
-     133,    -1,   131,    54,   133,    -1,   134,    -1,   132,    40,
-     134,    -1,   135,    -1,   133,    40,   135,    -1,   136,    -1,
-     134,    42,   136,    -1,   134,    15,   136,    -1,   134,    14,
-     136,    -1,   136,    -1,   135,    42,   136,    -1,   135,    15,
-     136,    -1,   137,    -1,   136,    41,   137,    -1,   138,    -1,
-     137,    55,   138,    -1,   137,    56,   138,    -1,   139,    -1,
-     138,    57,   139,    -1,   138,    58,   139,    -1,   138,    59,
-     139,    -1,   140,    -1,     8,   139,    -1,    27,   139,    -1,
-      25,   139,    -1,    32,   139,    -1,    33,   139,    -1,    55,
-     139,    -1,    56,   139,    -1,    60,   139,    -1,    61,   139,
-      -1,   141,    -1,   141,    32,    -1,   141,    33,    -1,   142,
-      -1,   144,    -1,   143,    -1,    16,   142,    -1,   147,    -1,
-      71,    -1,   143,    62,   114,    63,    -1,   143,    64,    38,
-      -1,    16,   143,   145,    -1,   143,   145,    -1,   144,   145,
-      -1,   144,    62,   114,    63,    -1,   144,    64,    38,    -1,
-      65,    66,    -1,    65,   146,    66,    -1,   118,    -1,   146,
-      47,   118,    -1,    20,    -1,    38,    -1,   156,    -1,   148,
-      -1,   152,    -1,    65,   114,    66,    -1,    62,    63,    -1,
-      62,   150,    63,    -1,    62,   149,    63,    -1,    62,   149,
-      47,   151,    63,    -1,   151,   118,    -1,   149,    47,   151,
-     118,    -1,    47,    -1,   150,    47,    -1,    -1,   150,    -1,
-      46,    37,    -1,    46,   153,    37,    -1,   154,    50,   118,
-      -1,   153,    47,   154,    50,   118,    -1,    38,    -1,    44,
-      -1,    43,    -1,    -1,    38,    -1,    17,    -1,   157,    -1,
-      43,    -1,    44,    -1,    58,    -1,    35,    -1,    22,    -1,
-      23,    -1,    49,    -1,     1,    -1,    65,    -1,     1,    -1,
-      66,    -1,     1,    -1,    49,    -1,     1,    -1
+      70,     0,    -1,    72,    71,    46,    -1,    34,    -1,    -1,
+      -1,    72,    78,    -1,    74,   157,   161,    77,   162,    48,
+      75,    37,    -1,    36,    -1,    72,    -1,    38,    -1,    76,
+      49,    38,    -1,    -1,    76,    -1,    81,    -1,    82,    -1,
+      91,    -1,    73,    -1,    92,    -1,    93,    -1,    94,    -1,
+      99,    -1,   100,    -1,   101,    -1,   102,    -1,   103,    -1,
+     104,    -1,   110,    -1,   111,    -1,    78,    -1,    79,    78,
+      -1,    -1,    79,    -1,    48,    79,    37,    -1,    48,    37,
+      -1,    26,    83,   160,    -1,    85,    -1,    83,    49,    85,
+      -1,    86,    -1,    84,    49,    86,    -1,    38,    87,    -1,
+      38,    89,    -1,    -1,    88,    -1,    50,   120,    -1,    -1,
+      90,    -1,    50,   121,    -1,    51,    -1,   116,   160,    -1,
+      11,   161,   115,   162,    78,    10,    78,    -1,    11,   161,
+     115,   162,    78,    -1,     9,    78,    28,   161,   115,   162,
+     160,    -1,    28,   161,   115,   162,    78,    -1,    -1,    -1,
+      13,   161,   117,    95,   163,   114,    96,   163,   114,   162,
+      78,    -1,    -1,    -1,    13,   161,    26,    84,    97,   163,
+     114,    98,   163,   114,   162,    78,    -1,    13,   161,   143,
+      14,   115,   162,    78,    -1,    13,   161,    26,    86,    14,
+     115,   162,    78,    -1,     6,   157,   160,    -1,     3,   157,
+     160,    -1,    18,   114,   160,    -1,    29,   161,   116,   162,
+      78,    -1,    38,    52,    78,    -1,    19,   161,   116,   162,
+     105,    -1,    48,   106,    37,    -1,    48,   106,   109,   106,
+      37,    -1,    -1,   107,    -1,   108,    -1,   107,   108,    -1,
+       4,   116,    52,    80,    -1,     7,    52,    80,    -1,    21,
+     116,   160,    -1,    24,    81,   112,    -1,    24,    81,   113,
+      -1,    24,    81,   112,   113,    -1,     5,   161,    38,   162,
+      81,    -1,    12,    81,    -1,    -1,   116,    -1,   116,    -1,
+       1,    -1,   120,    -1,   116,    49,   120,    -1,    -1,   118,
+      -1,   121,    -1,   118,    49,   121,    -1,    39,    -1,    35,
+      -1,   122,    -1,   143,    50,   120,    -1,   143,   119,   120,
+      -1,   123,    -1,   143,    50,   121,    -1,   143,   119,   121,
+      -1,   124,    -1,   124,    53,   120,    52,   120,    -1,   125,
+      -1,   125,    53,   121,    52,   121,    -1,   126,    -1,   124,
+      31,   126,    -1,   127,    -1,   125,    31,   127,    -1,   128,
+      -1,   126,    30,   128,    -1,   129,    -1,   127,    30,   129,
+      -1,   130,    -1,   128,    54,   130,    -1,   131,    -1,   129,
+      54,   131,    -1,   132,    -1,   130,    55,   132,    -1,   133,
+      -1,   131,    55,   133,    -1,   134,    -1,   132,    56,   134,
+      -1,   135,    -1,   133,    56,   135,    -1,   136,    -1,   134,
+      40,   136,    -1,   137,    -1,   135,    40,   137,    -1,   138,
+      -1,   136,    42,   138,    -1,   136,    15,   138,    -1,   136,
+      14,   138,    -1,   138,    -1,   137,    42,   138,    -1,   137,
+      15,   138,    -1,   139,    -1,   138,    41,   139,    -1,   140,
+      -1,   139,    57,   140,    -1,   139,    58,   140,    -1,   141,
+      -1,   140,    59,   141,    -1,   140,    60,   141,    -1,   140,
+      61,   141,    -1,   142,    -1,     8,   141,    -1,    27,   141,
+      -1,    25,   141,    -1,    32,   141,    -1,    33,   141,    -1,
+      57,   141,    -1,    58,   141,    -1,    62,   141,    -1,    63,
+     141,    -1,   143,    -1,   143,    32,    -1,   143,    33,    -1,
+     144,    -1,   146,    -1,   145,    -1,    16,   144,    -1,   149,
+      -1,    73,    -1,   145,    64,   116,    65,    -1,   145,    66,
+      38,    -1,    16,   145,   147,    -1,   145,   147,    -1,   146,
+     147,    -1,   146,    64,   116,    65,    -1,   146,    66,    38,
+      -1,    67,    68,    -1,    67,   148,    68,    -1,   120,    -1,
+     148,    49,   120,    -1,    20,    -1,    38,    -1,   158,    -1,
+     150,    -1,   154,    -1,    67,   116,    68,    -1,    64,    65,
+      -1,    64,   152,    65,    -1,    64,   151,    65,    -1,    64,
+     151,    49,   153,    65,    -1,   153,   120,    -1,   151,    49,
+     153,   120,    -1,    49,    -1,   152,    49,    -1,    -1,   152,
+      -1,    48,    37,    -1,    48,   155,    37,    -1,   156,    52,
+     120,    -1,   155,    49,   156,    52,   120,    -1,    38,    -1,
+      45,    -1,    43,    -1,    -1,    38,    -1,    17,    -1,   159,
+      -1,    43,    -1,    45,    -1,    60,    -1,    35,    -1,    22,
+      -1,    23,    -1,    44,    -1,    51,    -1,     1,    -1,    67,
+      -1,     1,    -1,    68,    -1,     1,    -1,    51,    -1,     1,
+      -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   256,   256,   260,   261,   265,   266,   271,   275,   279,
-     283,   284,   289,   290,   294,   295,   296,   297,   298,   299,
-     300,   301,   302,   303,   304,   305,   306,   307,   308,   312,
-     313,   318,   319,   323,   324,   328,   333,   334,   339,   341,
-     346,   351,   356,   357,   361,   366,   367,   371,   376,   380,
-     385,   387,   392,   394,   397,   399,   396,   403,   405,   402,
-     408,   410,   415,   420,   425,   430,   435,   440,   445,   447,
-     452,   453,   457,   458,   463,   468,   473,   478,   479,   480,
-     485,   490,   494,   495,   498,   499,   503,   504,   509,   510,
-     514,   516,   520,   521,   525,   526,   528,   533,   535,   537,
-     542,   543,   548,   550,   555,   556,   561,   563,   568,   569,
-     574,   576,   581,   582,   587,   589,   594,   595,   600,   602,
-     607,   608,   613,   615,   620,   621,   626,   627,   632,   633,
-     635,   637,   642,   643,   645,   650,   651,   656,   658,   660,
-     665,   666,   668,   670,   675,   676,   678,   679,   681,   682,
-     683,   684,   685,   686,   690,   692,   694,   700,   701,   705,
-     706,   710,   711,   712,   714,   716,   721,   723,   725,   727,
-     732,   733,   737,   738,   743,   744,   745,   746,   747,   748,
-     752,   753,   754,   755,   760,   762,   767,   768,   772,   773,
-     777,   778,   783,   785,   790,   791,   792,   796,   797,   801,
-     802,   803,   804,   805,   807,   812,   813,   816,   817,   820,
-     821,   824,   825,   828,   829
+       0,   252,   252,   256,   257,   261,   262,   267,   271,   275,
+     279,   280,   285,   286,   290,   291,   292,   293,   294,   295,
+     296,   297,   298,   299,   300,   301,   302,   303,   304,   308,
+     309,   314,   315,   319,   320,   324,   329,   330,   335,   337,
+     342,   347,   352,   353,   357,   362,   363,   367,   372,   376,
+     381,   383,   388,   390,   393,   395,   392,   399,   401,   398,
+     404,   406,   411,   416,   421,   426,   431,   436,   441,   443,
+     448,   449,   453,   454,   459,   464,   469,   474,   475,   476,
+     481,   486,   490,   491,   494,   495,   499,   500,   505,   506,
+     510,   512,   516,   517,   521,   522,   524,   529,   531,   533,
+     538,   539,   544,   546,   551,   552,   557,   559,   564,   565,
+     570,   572,   577,   578,   583,   585,   590,   591,   596,   598,
+     603,   604,   609,   611,   616,   617,   622,   623,   628,   629,
+     631,   633,   638,   639,   641,   646,   647,   652,   654,   656,
+     661,   662,   664,   666,   671,   672,   674,   675,   677,   678,
+     679,   680,   681,   682,   686,   688,   690,   696,   697,   701,
+     702,   706,   707,   708,   710,   712,   717,   719,   721,   723,
+     728,   729,   733,   734,   739,   740,   741,   742,   743,   744,
+     748,   749,   750,   751,   756,   758,   763,   764,   768,   769,
+     773,   774,   779,   781,   786,   787,   788,   792,   793,   797,
+     798,   799,   800,   801,   803,   808,   809,   810,   813,   814,
+     817,   818,   821,   822,   825,   826
 };
 #endif
 
@@ -728,24 +727,24 @@ static const char *const yytname[] =
   "kTRUE", "kFALSE", "kTRY", "kTYPEOF", "kVAR", "kVOID", "kWHILE", "kWITH",
   "tANDAND", "tOROR", "tINC", "tDEC", "tHTMLCOMMENT", "kDIVEQ",
   "kFUNCTION", "'}'", "tIdentifier", "tAssignOper", "tEqOper",
-  "tShiftOper", "tRelOper", "tNumericLiteral", "tStringLiteral",
-  "LOWER_THAN_ELSE", "'{'", "','", "'='", "';'", "':'", "'?'", "'|'",
-  "'^'", "'&'", "'+'", "'-'", "'*'", "'/'", "'%'", "'~'", "'!'", "'['",
-  "']'", "'.'", "'('", "')'", "$accept", "Program", "HtmlComment",
-  "SourceElements", "FunctionExpression", "KFunction", "FunctionBody",
-  "FormalParameterList", "FormalParameterList_opt", "Statement",
-  "StatementList", "StatementList_opt", "Block", "VariableStatement",
-  "VariableDeclarationList", "VariableDeclarationListNoIn",
-  "VariableDeclaration", "VariableDeclarationNoIn", "Initialiser_opt",
-  "Initialiser", "InitialiserNoIn_opt", "InitialiserNoIn",
-  "EmptyStatement", "ExpressionStatement", "IfStatement",
-  "IterationStatement", "$@1", "$@2", "$@3", "$@4", "ContinueStatement",
-  "BreakStatement", "ReturnStatement", "WithStatement",
-  "LabelledStatement", "SwitchStatement", "CaseBlock", "CaseClausules_opt",
-  "CaseClausules", "CaseClausule", "DefaultClausule", "ThrowStatement",
-  "TryStatement", "Catch", "Finally", "Expression_opt", "Expression_err",
-  "Expression", "ExpressionNoIn_opt", "ExpressionNoIn", "AssignOper",
-  "AssignmentExpression", "AssignmentExpressionNoIn",
+  "tShiftOper", "tRelOper", "tNumericLiteral", "tBooleanLiteral",
+  "tStringLiteral", "tEOF", "LOWER_THAN_ELSE", "'{'", "','", "'='", "';'",
+  "':'", "'?'", "'|'", "'^'", "'&'", "'+'", "'-'", "'*'", "'/'", "'%'",
+  "'~'", "'!'", "'['", "']'", "'.'", "'('", "')'", "$accept", "Program",
+  "HtmlComment", "SourceElements", "FunctionExpression", "KFunction",
+  "FunctionBody", "FormalParameterList", "FormalParameterList_opt",
+  "Statement", "StatementList", "StatementList_opt", "Block",
+  "VariableStatement", "VariableDeclarationList",
+  "VariableDeclarationListNoIn", "VariableDeclaration",
+  "VariableDeclarationNoIn", "Initialiser_opt", "Initialiser",
+  "InitialiserNoIn_opt", "InitialiserNoIn", "EmptyStatement",
+  "ExpressionStatement", "IfStatement", "IterationStatement", "$@1", "$@2",
+  "$@3", "$@4", "ContinueStatement", "BreakStatement", "ReturnStatement",
+  "WithStatement", "LabelledStatement", "SwitchStatement", "CaseBlock",
+  "CaseClausules_opt", "CaseClausules", "CaseClausule", "DefaultClausule",
+  "ThrowStatement", "TryStatement", "Catch", "Finally", "Expression_opt",
+  "Expression_err", "Expression", "ExpressionNoIn_opt", "ExpressionNoIn",
+  "AssignOper", "AssignmentExpression", "AssignmentExpressionNoIn",
   "ConditionalExpression", "ConditionalExpressionNoIn",
   "LogicalORExpression", "LogicalORExpressionNoIn", "LogicalANDExpression",
   "LogicalANDExpressionNoIn", "BitwiseORExpression",
@@ -773,43 +772,43 @@ static const yytype_uint16 yytoknum[] =
      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,   125,   292,   293,
-     294,   295,   296,   297,   298,   299,   123,    44,    61,    59,
-      58,    63,   124,    94,    38,    43,    45,    42,    47,    37,
-     126,    33,    91,    93,    46,    40,    41
+     294,   295,   296,   297,   298,   299,   300,   301,   123,    44,
+      61,    59,    58,    63,   124,    94,    38,    43,    45,    42,
+      47,    37,   126,    33,    91,    93,    46,    40,    41
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    67,    68,    69,    69,    70,    70,    71,    72,    73,
-      74,    74,    75,    75,    76,    76,    76,    76,    76,    76,
-      76,    76,    76,    76,    76,    76,    76,    76,    76,    77,
-      77,    78,    78,    79,    79,    80,    81,    81,    82,    82,
-      83,    84,    85,    85,    86,    87,    87,    88,    89,    90,
-      91,    91,    92,    92,    93,    94,    92,    95,    96,    92,
-      92,    92,    97,    98,    99,   100,   101,   102,   103,   103,
-     104,   104,   105,   105,   106,   107,   108,   109,   109,   109,
-     110,   111,   112,   112,   113,   113,   114,   114,   115,   115,
-     116,   116,   117,   117,   118,   118,   118,   119,   119,   119,
-     120,   120,   121,   121,   122,   122,   123,   123,   124,   124,
-     125,   125,   126,   126,   127,   127,   128,   128,   129,   129,
-     130,   130,   131,   131,   132,   132,   133,   133,   134,   134,
-     134,   134,   135,   135,   135,   136,   136,   137,   137,   137,
-     138,   138,   138,   138,   139,   139,   139,   139,   139,   139,
-     139,   139,   139,   139,   140,   140,   140,   141,   141,   142,
-     142,   143,   143,   143,   143,   143,   144,   144,   144,   144,
-     145,   145,   146,   146,   147,   147,   147,   147,   147,   147,
-     148,   148,   148,   148,   149,   149,   150,   150,   151,   151,
-     152,   152,   153,   153,   154,   154,   154,   155,   155,   156,
-     156,   156,   156,   156,   156,   157,   157,   158,   158,   159,
-     159,   160,   160,   161,   161
+       0,    69,    70,    71,    71,    72,    72,    73,    74,    75,
+      76,    76,    77,    77,    78,    78,    78,    78,    78,    78,
+      78,    78,    78,    78,    78,    78,    78,    78,    78,    79,
+      79,    80,    80,    81,    81,    82,    83,    83,    84,    84,
+      85,    86,    87,    87,    88,    89,    89,    90,    91,    92,
+      93,    93,    94,    94,    95,    96,    94,    97,    98,    94,
+      94,    94,    99,   100,   101,   102,   103,   104,   105,   105,
+     106,   106,   107,   107,   108,   109,   110,   111,   111,   111,
+     112,   113,   114,   114,   115,   115,   116,   116,   117,   117,
+     118,   118,   119,   119,   120,   120,   120,   121,   121,   121,
+     122,   122,   123,   123,   124,   124,   125,   125,   126,   126,
+     127,   127,   128,   128,   129,   129,   130,   130,   131,   131,
+     132,   132,   133,   133,   134,   134,   135,   135,   136,   136,
+     136,   136,   137,   137,   137,   138,   138,   139,   139,   139,
+     140,   140,   140,   140,   141,   141,   141,   141,   141,   141,
+     141,   141,   141,   141,   142,   142,   142,   143,   143,   144,
+     144,   145,   145,   145,   145,   145,   146,   146,   146,   146,
+     147,   147,   148,   148,   149,   149,   149,   149,   149,   149,
+     150,   150,   150,   150,   151,   151,   152,   152,   153,   153,
+     154,   154,   155,   155,   156,   156,   156,   157,   157,   158,
+     158,   158,   158,   158,   158,   159,   159,   159,   160,   160,
+     161,   161,   162,   162,   163,   163
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     2,     1,     0,     0,     2,     8,     1,     1,
+       0,     2,     3,     1,     0,     0,     2,     8,     1,     1,
        1,     3,     0,     1,     1,     1,     1,     1,     1,     1,
        1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
        2,     0,     1,     3,     2,     3,     1,     3,     1,     3,
@@ -830,7 +829,7 @@ static const yytype_uint8 yyr2[] =
        2,     3,     3,     5,     2,     4,     1,     2,     0,     1,
        2,     3,     3,     5,     1,     1,     1,     0,     1,     1,
        1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
-       1,     1,     1,     1,     1
+       1,     1,     1,     1,     1,     1
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -841,116 +840,116 @@ static const yytype_uint8 yydefact[] =
        5,     0,     4,     1,   197,   197,     0,     0,     0,     0,
        0,   199,    82,     0,   174,     0,   205,   206,     0,     0,
        0,     0,     0,     0,     0,     0,     3,   204,     8,   175,
-     201,   202,     0,    48,     0,     0,   203,     0,     0,   188,
-       0,     2,    17,   197,     6,    14,    15,    16,    18,    19,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,     0,
-      86,    94,   100,   104,   108,   112,   116,   120,   124,   128,
-     135,   137,   140,   144,   154,   157,   159,   158,   161,   177,
-     178,   176,   200,   198,     0,     0,   175,     0,   162,   145,
-     154,     0,   210,   209,     0,    88,   160,   159,     0,    83,
-       0,     0,     0,     0,   147,    42,     0,    36,   146,     0,
-       0,   148,   149,     0,    34,   175,   201,   202,    29,     0,
-       0,     0,   150,   151,   152,   153,   186,   180,     0,   189,
-       0,     0,     0,   208,     0,   207,    49,     0,     0,     0,
+     201,   207,   202,     0,    48,     0,     0,   203,     0,     0,
+     188,     0,     0,    17,   197,     6,    14,    15,    16,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+       0,    86,    94,   100,   104,   108,   112,   116,   120,   124,
+     128,   135,   137,   140,   144,   154,   157,   159,   158,   161,
+     177,   178,   176,   200,   198,     0,     0,   175,     0,   162,
+     145,   154,     0,   211,   210,     0,    88,   160,   159,     0,
+      83,     0,     0,     0,     0,   147,    42,     0,    36,   146,
+       0,     0,   148,   149,     0,    34,   175,   201,   202,    29,
+       0,     0,     0,   150,   151,   152,   153,   186,   180,     0,
+     189,     0,     0,     2,     0,   209,     0,   208,    49,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   155,   156,    93,    92,     0,
+       0,     0,     0,     0,   166,     0,     0,   167,    63,    62,
+     190,   194,   196,   195,     0,    85,     0,    84,     0,    54,
+      89,    90,    97,   102,   106,   110,   114,   118,   122,   126,
+     132,   154,   165,    64,     0,    76,    34,     0,     0,    77,
+      78,     0,    40,    43,     0,    35,     0,     0,    66,    33,
+      30,   191,     0,     0,   188,   182,   187,   181,   184,   179,
+      12,    87,   105,     0,   109,   113,   117,   121,   125,   131,
+     130,   129,   136,   138,   139,   141,   142,   143,    95,    96,
+       0,   164,   170,   172,     0,     0,   169,     0,   213,   212,
+       0,    45,    57,    38,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   155,   156,    93,    92,     0,     0,     0,
-       0,     0,   166,     0,     0,   167,    63,    62,   190,   194,
-     196,   195,     0,    85,     0,    84,     0,    54,    89,    90,
-      97,   102,   106,   110,   114,   118,   122,   126,   132,   154,
-     165,    64,     0,    76,    34,     0,     0,    77,    78,     0,
-      40,    43,     0,    35,     0,     0,    66,    33,    30,   191,
-       0,     0,   188,   182,   187,   181,   184,   179,    12,    87,
-     105,     0,   109,   113,   117,   121,   125,   131,   130,   129,
-     136,   138,   139,   141,   142,   143,    95,    96,     0,   164,
-     170,   172,     0,     0,   169,     0,   212,   211,     0,    45,
-      57,    38,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,    81,    79,
-      44,    37,     0,     0,     0,   192,   189,     0,    10,    13,
-       0,     0,   163,     0,   171,   168,     0,    51,     0,    41,
-      46,     0,     0,     0,   214,   213,    82,    91,   154,   107,
-       0,   111,   115,   119,   123,   127,   134,   133,     0,    98,
-      99,    70,    67,     0,    53,    65,     0,   183,   185,     0,
-       0,   101,   173,     0,     0,    47,    39,    82,     0,    55,
-       0,     0,     0,     0,    71,    72,     0,   193,    11,     5,
-      52,    50,    58,     0,     0,   103,    60,     0,     0,    68,
-      70,    73,    80,     9,     0,     0,    61,    82,    31,    31,
-       0,     7,    82,     0,    32,    74,    75,    69,     0,     0,
-       0,    56,    59
+      81,    79,    44,    37,     0,     0,     0,   192,   189,     0,
+      10,    13,     0,     0,   163,     0,   171,   168,     0,    51,
+       0,    41,    46,     0,     0,     0,   215,   214,    82,    91,
+     154,   107,     0,   111,   115,   119,   123,   127,   134,   133,
+       0,    98,    99,    70,    67,     0,    53,    65,     0,   183,
+     185,     0,     0,   101,   173,     0,     0,    47,    39,    82,
+       0,    55,     0,     0,     0,     0,    71,    72,     0,   193,
+      11,     5,    52,    50,    58,     0,     0,   103,    60,     0,
+       0,    68,    70,    73,    80,     9,     0,     0,    61,    82,
+      31,    31,     0,     7,    82,     0,    32,    74,    75,    69,
+       0,     0,     0,    56,    59
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     1,    41,     2,    88,    43,   354,   279,   280,   118,
-     119,   365,    45,    46,   106,   250,   107,   251,   200,   201,
-     289,   290,    47,    48,    49,    50,   252,   344,   292,   355,
-      51,    52,    53,    54,    55,    56,   312,   333,   334,   335,
-     350,    57,    58,   197,   198,    98,   174,    59,   177,   178,
-     265,    60,   179,    61,   180,    62,   181,    63,   182,    64,
-     183,    65,   184,    66,   185,    67,   186,    68,   187,    69,
-      70,    71,    72,    73,    74,    75,    76,    77,   162,   242,
-      78,    79,   128,   129,   130,    80,   120,   121,    84,    81,
-      82,   136,    94,   248,   296
+      -1,     1,    42,     2,    89,    44,   356,   281,   282,   119,
+     120,   367,    46,    47,   107,   252,   108,   253,   202,   203,
+     291,   292,    48,    49,    50,    51,   254,   346,   294,   357,
+      52,    53,    54,    55,    56,    57,   314,   335,   336,   337,
+     352,    58,    59,   199,   200,    99,   176,    60,   179,   180,
+     267,    61,   181,    62,   182,    63,   183,    64,   184,    65,
+     185,    66,   186,    67,   187,    68,   188,    69,   189,    70,
+      71,    72,    73,    74,    75,    76,    77,    78,   164,   244,
+      79,    80,   129,   130,   131,    81,   121,   122,    85,    82,
+      83,   138,    95,   250,   298
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -287
+#define YYPACT_NINF -293
 static const yytype_int16 yypact[] =
 {
-    -287,    29,   490,  -287,   -18,   -18,   934,   730,    21,    21,
-     965,  -287,   934,    21,  -287,   934,  -287,  -287,    36,   934,
-      89,   934,    21,    21,   934,   934,  -287,  -287,  -287,   105,
-    -287,  -287,   550,  -287,   934,   934,  -287,   934,   934,    61,
-     934,  -287,   403,   -18,  -287,  -287,  -287,  -287,  -287,  -287,
-    -287,  -287,  -287,  -287,  -287,  -287,  -287,  -287,  -287,    15,
-    -287,  -287,    41,   106,   117,   129,   142,   158,    76,   162,
-     131,    47,  -287,  -287,   141,  -287,   113,   148,  -287,  -287,
-    -287,  -287,  -287,  -287,     5,     5,  -287,   147,  -287,  -287,
-     169,   177,  -287,  -287,   370,   832,  -287,   113,     5,   164,
-     934,    15,   610,   123,  -287,   159,    16,  -287,  -287,   370,
-     934,  -287,  -287,   730,   438,   105,   175,   176,  -287,   670,
-      86,   178,  -287,  -287,  -287,  -287,  -287,  -287,    62,    63,
-     934,    28,    21,  -287,   934,  -287,  -287,   934,   934,   934,
-     934,   934,   934,   934,   934,   934,   934,   934,   934,   934,
-     934,   934,   934,  -287,  -287,  -287,  -287,   934,   934,   934,
-     181,   781,  -287,   934,   189,  -287,  -287,  -287,  -287,  -287,
-    -287,  -287,    21,  -287,     8,   164,   191,  -287,   183,  -287,
-    -287,    56,   201,   180,   182,   179,   194,    53,   162,    10,
-    -287,  -287,    12,  -287,  -287,    21,    36,   225,  -287,   934,
-    -287,  -287,    89,  -287,     8,    12,  -287,  -287,  -287,  -287,
-      94,   934,   193,  -287,  -287,  -287,  -287,  -287,   200,  -287,
-     106,   192,   117,   129,   142,   158,    76,   162,   162,   162,
-     131,    47,    47,  -287,  -287,  -287,  -287,  -287,    68,  -287,
-    -287,  -287,    46,   109,  -287,   370,  -287,  -287,   730,   195,
-     197,   227,    18,   934,   934,   934,   934,   934,   934,   934,
-     934,   934,   934,   370,   934,   934,   199,   209,  -287,  -287,
-    -287,  -287,   730,   730,   202,  -287,   204,   883,  -287,   206,
-       8,   934,  -287,   934,  -287,  -287,     8,   239,   934,  -287,
-    -287,   191,    18,   370,  -287,  -287,   934,  -287,   160,   201,
-     218,   180,   182,   179,   194,    53,   162,   162,     8,  -287,
-    -287,   250,  -287,     8,  -287,  -287,   934,  -287,  -287,   231,
-     228,  -287,  -287,     5,   730,  -287,  -287,   934,     8,  -287,
-     934,   730,   934,    66,   250,  -287,    36,  -287,  -287,  -287,
-    -287,  -287,  -287,   730,    18,  -287,  -287,   -32,   226,  -287,
-     250,  -287,  -287,   730,   238,    18,  -287,   934,   730,   730,
-     240,  -287,   934,     8,   730,  -287,  -287,  -287,     8,   730,
-     730,  -287,  -287
+    -293,    53,   496,  -293,    26,    26,   956,   744,     8,     8,
+     986,  -293,   956,     8,  -293,   956,  -293,  -293,    39,   956,
+      71,   956,     8,     8,   956,   956,  -293,  -293,  -293,    67,
+    -293,  -293,  -293,   558,  -293,   956,   956,  -293,   956,   956,
+      41,   956,    76,   410,    26,  -293,  -293,  -293,  -293,  -293,
+    -293,  -293,  -293,  -293,  -293,  -293,  -293,  -293,  -293,  -293,
+      19,  -293,  -293,    -7,   102,   100,   108,   111,   135,    36,
+     142,   -43,    97,  -293,  -293,   129,  -293,   105,   118,  -293,
+    -293,  -293,  -293,  -293,  -293,     7,     7,  -293,   176,  -293,
+    -293,    49,   158,  -293,  -293,   372,   850,  -293,   105,     7,
+     140,   956,    19,   620,   125,  -293,   153,    47,  -293,  -293,
+     372,   956,  -293,  -293,   744,   442,    67,   155,   163,  -293,
+     682,    80,   165,  -293,  -293,  -293,  -293,  -293,  -293,    42,
+      48,   956,    31,  -293,     8,  -293,   956,  -293,  -293,   956,
+     956,   956,   956,   956,   956,   956,   956,   956,   956,   956,
+     956,   956,   956,   956,   956,  -293,  -293,  -293,  -293,   956,
+     956,   956,   180,   797,  -293,   956,   182,  -293,  -293,  -293,
+    -293,  -293,  -293,  -293,     8,  -293,     3,   140,   184,  -293,
+     181,  -293,  -293,    35,   195,   172,   178,   175,   192,    23,
+     142,   120,  -293,  -293,    11,  -293,  -293,     8,    39,   222,
+    -293,   956,  -293,  -293,    71,  -293,     3,    11,  -293,  -293,
+    -293,  -293,    90,   956,   186,  -293,  -293,  -293,  -293,  -293,
+     198,  -293,   102,   185,   100,   108,   111,   135,    36,   142,
+     142,   142,   -43,    97,    97,  -293,  -293,  -293,  -293,  -293,
+      56,  -293,  -293,  -293,    34,    66,  -293,   372,  -293,  -293,
+     744,   188,   190,   226,    10,   956,   956,   956,   956,   956,
+     956,   956,   956,   956,   956,   372,   956,   956,   193,   204,
+    -293,  -293,  -293,  -293,   744,   744,   194,  -293,   196,   903,
+    -293,   202,     3,   956,  -293,   956,  -293,  -293,     3,   234,
+     956,  -293,  -293,   184,    10,   372,  -293,  -293,   956,  -293,
+     177,   195,   214,   172,   178,   175,   192,    23,   142,   142,
+       3,  -293,  -293,   263,  -293,     3,  -293,  -293,   956,  -293,
+    -293,   230,   221,  -293,  -293,     7,   744,  -293,  -293,   956,
+       3,  -293,   956,   744,   956,     6,   263,  -293,    39,  -293,
+    -293,  -293,  -293,  -293,  -293,   744,    10,  -293,  -293,    59,
+     219,  -293,   263,  -293,  -293,   744,   239,    10,  -293,   956,
+     744,   744,   240,  -293,   956,     3,   744,  -293,  -293,  -293,
+       3,   744,   744,  -293,  -293
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-    -287,  -287,  -287,   -61,    -2,  -287,  -287,  -287,  -287,     0,
-    -141,   -80,   -15,  -287,  -287,  -287,    78,   -10,  -287,  -287,
-    -287,  -287,  -287,  -287,  -287,  -287,  -287,  -287,  -287,  -287,
-    -287,  -287,  -287,  -287,  -287,  -287,  -287,   -68,  -287,   -50,
-    -287,  -287,  -287,  -287,    88,  -286,  -105,    20,  -287,  -287,
-     212,   -77,  -209,  -287,  -287,  -287,  -287,   150,    34,   152,
-      33,   153,    35,   154,    38,   156,    40,   151,    42,   -94,
-     157,    75,    64,  -287,     2,   290,   291,  -287,    19,  -287,
-    -287,  -287,  -287,    93,    95,  -287,  -287,    96,    26,  -287,
-    -287,   -73,    25,    17,  -278
+    -293,  -293,  -293,   -63,    -2,  -293,  -293,  -293,  -293,     0,
+    -187,   -82,   -17,  -293,  -293,  -293,    77,   -10,  -293,  -293,
+    -293,  -293,  -293,  -293,  -293,  -293,  -293,  -293,  -293,  -293,
+    -293,  -293,  -293,  -293,  -293,  -293,  -293,   -68,  -293,   -51,
+    -293,  -293,  -293,  -293,    87,  -292,   -87,    15,  -293,  -293,
+     213,   -36,  -238,  -293,  -293,  -293,  -293,   150,    40,   149,
+      33,   151,    43,   152,    44,   148,    45,   156,    46,   -62,
+     145,    37,    38,  -293,    -3,   287,   288,  -293,    -9,  -293,
+    -293,  -293,  -293,    86,    89,  -293,  -293,    95,     5,  -293,
+    -293,   -60,    32,    17,  -254
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -960,262 +959,266 @@ static const yytype_int16 yypgoto[] =
 #define YYTABLE_NINF -197
 static const yytype_int16 yytable[] =
 {
-      42,   188,    44,   103,   204,    42,   133,    91,    90,   246,
-     329,   166,   167,   246,   327,   134,   133,   133,   358,   294,
-      83,    90,    92,    90,   263,   191,    90,    90,   193,     3,
-      42,    85,    99,   203,    95,   101,    90,    90,   100,    90,
-      90,   342,   153,   154,   297,   155,   300,   109,   110,   156,
-     227,   228,   229,   216,   135,   309,   310,   219,   264,   134,
-     131,   221,   134,   202,   135,   135,   357,   295,   261,   132,
-      89,   363,   137,   348,   247,   134,   368,   362,   247,   325,
-     236,   237,   102,   104,   241,   108,    93,   254,   111,   112,
-     144,   145,   138,   283,   217,   262,   165,   189,   122,   123,
-      42,   124,   125,   349,   150,   151,   152,   255,   126,   212,
-     214,    42,   284,   206,   175,   134,   190,    42,   146,   208,
-     192,   345,   270,   209,   127,   213,   215,   105,   195,   175,
-     205,   282,   169,   210,   275,   196,   139,   170,   171,    90,
-     286,    90,    90,    90,    90,    90,    90,    90,    90,    90,
-      90,    90,    90,    90,    90,   113,   134,   218,   308,   188,
-     188,   188,   188,   188,   188,   188,   188,   306,   307,   140,
-     188,   188,   285,   153,   154,   159,   155,   160,   161,   238,
-     156,   268,   141,   243,   168,   169,   148,   149,   328,   157,
-     170,   171,   153,   154,   188,   155,   142,   245,   143,   156,
-     318,   153,   154,   147,   321,   172,   322,   199,   264,   266,
-     163,   134,   164,   161,   233,   234,   235,   364,   364,   239,
-     267,   272,   273,   231,   232,  -196,  -195,   244,   211,   249,
-     253,   256,   257,   259,   260,   258,   188,   196,   278,   337,
-     126,   293,   281,   288,   291,   311,    42,   313,   287,   324,
-     340,   214,   316,   319,   332,   298,    90,   298,    90,    90,
-      90,    90,    90,    90,    90,   175,   298,   298,   330,   338,
-      42,    42,   314,   315,   339,   361,   359,   367,   353,   366,
-     271,   326,   360,   175,   351,   269,   158,   220,   299,   301,
-     298,   222,   302,   223,   226,   224,   303,   320,   225,   304,
-      96,    97,   305,   323,   230,   276,   274,   277,     0,     0,
-       0,     0,     0,   175,     0,     0,    99,     0,     0,     0,
-       0,   352,    42,     0,   341,   331,     0,     0,     0,    42,
-     336,   346,   298,     0,     0,     0,     0,     0,     0,     0,
-       0,    42,     0,   356,     0,   343,     0,    99,     0,     0,
-       0,    42,   347,    44,     0,     0,    42,    42,     0,     0,
-       0,     0,    42,     0,   208,     0,     0,    42,    42,   371,
-     372,   173,     0,     0,     0,     0,     0,    99,     6,     0,
-     369,     0,    99,     0,     0,   370,    10,    11,     0,     0,
-      14,     0,    16,    17,     0,    19,     0,    21,     0,     0,
-       0,     0,    24,    25,  -162,    27,    28,     0,    86,     0,
-       0,     0,     0,    30,    31,     0,    87,  -162,  -162,     0,
-       0,     0,     0,     0,     0,    34,    35,     0,    36,     0,
-      37,    38,    39,  -162,  -162,    40,     0,     0,     0,  -190,
-       0,     0,  -162,  -162,  -162,  -162,     0,     0,     0,     0,
-    -162,  -162,  -190,  -190,  -162,  -162,  -162,  -162,     0,     0,
-    -162,     0,  -162,     0,     0,     0,     0,  -162,  -190,  -190,
-       0,     0,     0,     0,     0,     0,     0,  -190,  -190,  -190,
-    -190,     0,     0,     0,     0,  -190,  -190,     0,     0,  -190,
-    -190,  -190,  -190,     4,     0,  -190,     5,  -190,     6,     7,
-       0,     8,  -190,     9,     0,     0,    10,    11,    12,    13,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-       0,     0,    24,    25,    26,    27,    28,     0,    29,     0,
-       0,     0,     0,    30,    31,     0,    32,     0,     0,    33,
-       0,     0,     0,     0,     0,    34,    35,     0,    36,     0,
-      37,    38,    39,     4,     0,    40,     5,     0,     6,     7,
-       0,     8,     0,     9,     0,     0,    10,    11,    12,    13,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-       0,     0,    24,    25,     0,    27,    28,   114,   115,     0,
-       0,     0,     0,   116,   117,     0,    32,     0,     0,    33,
-       0,     0,     0,     0,     0,    34,    35,     0,    36,     0,
-      37,    38,    39,     4,     0,    40,     5,     0,     6,     7,
-       0,     8,     0,     9,     0,     0,    10,    11,    12,    13,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-       0,     0,    24,    25,     0,    27,    28,   194,    29,     0,
-       0,     0,     0,    30,    31,     0,    32,     0,     0,    33,
-       0,     0,     0,     0,     0,    34,    35,     0,    36,     0,
-      37,    38,    39,     4,     0,    40,     5,     0,     6,     7,
-       0,     8,     0,     9,     0,     0,    10,    11,    12,    13,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-       0,     0,    24,    25,     0,    27,    28,   207,    29,     0,
-       0,     0,     0,    30,    31,     0,    32,     0,     0,    33,
-       0,     0,     0,     0,     0,    34,    35,     0,    36,     0,
-      37,    38,    39,     4,     0,    40,     5,     0,     6,     7,
+      43,   104,    45,    91,   248,    43,   331,    92,   135,    93,
+      86,   296,   248,   350,   150,   151,    91,   299,    91,   302,
+     135,    91,    91,   206,   139,   168,   169,   100,   311,   312,
+     102,    43,    91,    91,   190,    91,    91,   344,   263,   193,
+     329,    96,   195,   351,    90,   101,   140,   205,   135,   134,
+     146,   147,   327,     3,   110,   111,   132,   105,   137,   109,
+     136,   297,   112,   113,    84,   264,   256,   365,   136,   167,
+     137,   249,   370,   123,   124,    94,   125,   126,   148,   249,
+     136,   155,   156,   285,   229,   230,   231,   103,   257,   192,
+     127,   214,   359,   191,   347,   218,   204,   216,   137,   219,
+     221,    43,   286,   364,   223,   136,   128,   215,   136,   106,
+     177,   360,    43,   217,   208,   136,   194,   211,    43,   114,
+     210,   284,   133,   238,   239,   177,   207,   243,   171,   212,
+     197,   287,   141,   172,   265,   173,    91,   198,    91,    91,
+      91,    91,    91,    91,    91,    91,    91,    91,    91,    91,
+      91,    91,   155,   156,   142,   157,   152,   153,   154,   158,
+     288,   155,   156,   143,   157,   272,   220,   144,   158,   161,
+     266,   162,   163,   366,   366,   145,   240,   277,   310,   159,
+     245,   270,   165,   149,   166,   163,   174,   233,   234,   136,
+     235,   236,   237,   190,   190,   190,   190,   190,   190,   190,
+     190,   308,   309,   201,   190,   190,   247,  -196,   330,   155,
+     156,   268,   157,   170,   171,  -195,   158,   213,   241,   172,
+     246,   173,   251,   274,   275,   258,   259,   266,   190,   269,
+     255,   261,   262,   260,   198,   127,   280,   283,   290,   293,
+     295,   313,   315,   320,   326,   216,   318,   323,    43,   324,
+     289,   321,   300,    91,   300,    91,    91,    91,    91,    91,
+      91,    91,   177,   300,   300,   342,   332,   334,   340,   341,
+     190,   361,    43,    43,   316,   317,   363,   369,   355,   368,
+     177,   273,   339,   328,   362,   353,   271,   300,   160,   222,
+     224,   303,   227,   225,   232,   226,   301,    97,    98,   322,
+     278,   228,   304,   279,   305,   325,   306,   276,   307,     0,
+     177,     0,     0,   100,     0,     0,     0,     0,     0,     0,
+       0,   354,     0,     0,    43,     0,   343,   333,     0,   300,
+       0,    43,   338,   348,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    43,   100,   358,     0,   345,     0,   349,
+       0,     0,     0,    43,     0,    45,     0,     0,    43,    43,
+       0,     0,     0,     0,    43,     0,   210,     0,     0,    43,
+      43,   373,   374,   175,   100,     0,     0,     0,     0,   100,
+       6,     0,   371,     0,     0,     0,     0,   372,    10,    11,
+       0,     0,    14,     0,    16,    17,     0,    19,     0,    21,
+       0,     0,     0,     0,    24,    25,     0,    27,    28,     0,
+      87,  -162,     0,     0,     0,    30,    31,    32,     0,     0,
+      88,     0,     0,     0,  -162,  -162,     0,     0,     0,    35,
+      36,     0,    37,     0,    38,    39,    40,     0,     0,    41,
+    -162,  -162,     0,  -190,     0,     0,     0,     0,     0,  -162,
+    -162,  -162,  -162,     0,     0,     0,  -190,  -190,     0,  -162,
+    -162,     0,     0,  -162,  -162,  -162,  -162,     0,     0,  -162,
+       0,  -162,  -190,  -190,     0,     0,  -162,     0,     0,     0,
+       0,  -190,  -190,  -190,  -190,     0,     0,     0,     0,     0,
+       0,  -190,  -190,     0,     0,  -190,  -190,  -190,  -190,     4,
+       0,  -190,     5,  -190,     6,     7,     0,     8,  -190,     9,
+       0,     0,    10,    11,    12,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,     0,     0,    24,    25,
+      26,    27,    28,     0,    29,     0,     0,     0,     0,    30,
+      31,    32,     0,     0,    33,     0,     0,    34,     0,     0,
+       0,     0,     0,    35,    36,     0,    37,     0,    38,    39,
+      40,     4,     0,    41,     5,     0,     6,     7,     0,     8,
+       0,     9,     0,     0,    10,    11,    12,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,     0,     0,
+      24,    25,     0,    27,    28,   115,   116,     0,     0,     0,
+       0,   117,    31,   118,     0,     0,    33,     0,     0,    34,
+       0,     0,     0,     0,     0,    35,    36,     0,    37,     0,
+      38,    39,    40,     4,     0,    41,     5,     0,     6,     7,
        0,     8,     0,     9,     0,     0,    10,    11,    12,    13,
       14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-       0,     0,    24,    25,     0,    27,    28,     0,    29,     0,
-       0,     0,     0,    30,    31,     0,    32,     0,     0,    33,
-       0,     0,     0,     0,     0,    34,    35,     0,    36,     6,
-      37,    38,    39,     0,     0,    40,     0,    10,    11,     0,
-       0,    14,     0,    16,    17,     0,    19,     0,    21,     0,
-       0,     0,     0,    24,    25,     0,    27,    28,     0,    86,
-       0,     0,     0,     0,    30,    31,     0,    87,     0,     0,
-       0,     0,     0,     0,     0,     0,    34,    35,     0,    36,
-       6,    37,    38,    39,     0,     0,    40,   240,    10,    11,
-       0,     0,    14,     0,    16,    17,     0,    19,   176,    21,
-       0,     0,     0,     0,    24,    25,     0,    27,    28,     0,
-      86,     0,     0,     0,     0,    30,    31,     0,    87,     0,
-       0,     0,     0,     0,     0,     0,     0,    34,    35,     0,
-      36,     6,    37,    38,    39,     0,     0,    40,     0,    10,
+       0,     0,    24,    25,     0,    27,    28,   196,    29,     0,
+       0,     0,     0,    30,    31,    32,     0,     0,    33,     0,
+       0,    34,     0,     0,     0,     0,     0,    35,    36,     0,
+      37,     0,    38,    39,    40,     4,     0,    41,     5,     0,
+       6,     7,     0,     8,     0,     9,     0,     0,    10,    11,
+      12,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    23,     0,     0,    24,    25,     0,    27,    28,   209,
+      29,     0,     0,     0,     0,    30,    31,    32,     0,     0,
+      33,     0,     0,    34,     0,     0,     0,     0,     0,    35,
+      36,     0,    37,     0,    38,    39,    40,     4,     0,    41,
+       5,     0,     6,     7,     0,     8,     0,     9,     0,     0,
+      10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,     0,     0,    24,    25,     0,    27,
+      28,     0,    29,     0,     0,     0,     0,    30,    31,    32,
+       0,     0,    33,     0,     0,    34,     0,     0,     0,     0,
+       0,    35,    36,     0,    37,     6,    38,    39,    40,     0,
+       0,    41,     0,    10,    11,     0,     0,    14,     0,    16,
+      17,     0,    19,     0,    21,     0,     0,     0,     0,    24,
+      25,     0,    27,    28,     0,    87,     0,     0,     0,     0,
+      30,    31,    32,     0,     0,    88,     0,     0,     0,     0,
+       0,     0,     0,     0,    35,    36,     0,    37,     6,    38,
+      39,    40,     0,     0,    41,   242,    10,    11,     0,     0,
+      14,     0,    16,    17,     0,    19,   178,    21,     0,     0,
+       0,     0,    24,    25,     0,    27,    28,     0,    87,     0,
+       0,     0,     0,    30,    31,    32,     0,     0,    88,     0,
+       0,     0,     0,     0,     0,     0,     0,    35,    36,     0,
+      37,     6,    38,    39,    40,     0,     0,    41,     0,    10,
       11,     0,     0,    14,     0,    16,    17,     0,    19,     0,
       21,     0,     0,     0,     0,    24,    25,     0,    27,    28,
-       0,    86,     0,     0,     0,     0,    30,    31,     0,    87,
-       0,     0,     0,     0,     0,     0,     0,     0,    34,    35,
-       0,    36,     6,    37,    38,    39,   317,     0,    40,     0,
-      10,    11,     0,     0,    14,     0,    16,    17,     0,    19,
-       0,    21,     0,     0,     0,     0,    24,    25,     0,    27,
-      28,     0,    86,     0,     0,     0,     0,    30,    31,     0,
-      87,    10,    11,     0,     0,    14,     0,    16,    17,    34,
-      35,     0,    36,     0,    37,    38,    39,     0,     0,    40,
-      27,    28,     0,    86,     0,     0,     0,     0,    30,    31,
-       0,    87,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,    36,     0,     0,     0,    39,     0,     0,
-      40
+       0,    87,     0,     0,     0,     0,    30,    31,    32,     0,
+       0,    88,     0,     0,     0,     0,     0,     0,     0,     0,
+      35,    36,     0,    37,     6,    38,    39,    40,   319,     0,
+      41,     0,    10,    11,     0,     0,    14,     0,    16,    17,
+       0,    19,     0,    21,     0,     0,     0,     0,    24,    25,
+       0,    27,    28,     0,    87,     0,     0,     0,     0,    30,
+      31,    32,    10,    11,    88,     0,    14,     0,    16,    17,
+       0,     0,     0,    35,    36,     0,    37,     0,    38,    39,
+      40,    27,    28,    41,    87,     0,     0,     0,     0,    30,
+      31,    32,     0,     0,    88,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    37,     0,     0,     0,
+      40,     0,     0,    41
 };
 
 static const yytype_int16 yycheck[] =
 {
-       2,    95,     2,    18,   109,     7,     1,     7,     6,     1,
-     296,    84,    85,     1,   292,    47,     1,     1,    50,     1,
-      38,    19,     1,    21,    14,    98,    24,    25,   101,     0,
-      32,     5,    12,   106,     9,    15,    34,    35,    13,    37,
-      38,   327,    32,    33,   253,    35,   255,    22,    23,    39,
-     144,   145,   146,   130,    49,   264,   265,   134,    48,    47,
-      40,   138,    47,    47,    49,    49,   344,    49,    15,    43,
-       6,   357,    31,     7,    66,    47,   362,   355,    66,   288,
-     157,   158,    46,    19,   161,    21,    65,    31,    24,    25,
-      14,    15,    51,    47,    66,    42,    77,    95,    34,    35,
-     102,    37,    38,    37,    57,    58,    59,    51,    47,    47,
-      47,   113,    66,   113,    94,    47,    97,   119,    42,   119,
-     100,   330,   199,    37,    63,    63,    63,    38,     5,   109,
-     110,    63,    38,    47,   211,    12,    30,    43,    44,   137,
-     245,   139,   140,   141,   142,   143,   144,   145,   146,   147,
-     148,   149,   150,   151,   152,    50,    47,   132,   263,   253,
-     254,   255,   256,   257,   258,   259,   260,   261,   262,    52,
-     264,   265,    63,    32,    33,    62,    35,    64,    65,   159,
-      39,   196,    53,   163,    37,    38,    55,    56,   293,    48,
-      43,    44,    32,    33,   288,    35,    54,   172,    40,    39,
-     277,    32,    33,    41,   281,    28,   283,    48,    48,   192,
-      62,    47,    64,    65,   150,   151,   152,   358,   359,    38,
-     195,   204,   205,   148,   149,    50,    50,    38,    50,    38,
-      47,    30,    52,    54,    40,    53,   330,    12,    38,   316,
-      47,    14,    50,    48,    47,    46,   248,    38,   248,    10,
-     323,    47,    50,    47,     4,   253,   254,   255,   256,   257,
-     258,   259,   260,   261,   262,   245,   264,   265,    50,    38,
-     272,   273,   272,   273,    46,    37,    50,    37,   339,   359,
-     202,   291,   350,   263,   334,   197,    74,   137,   254,   256,
-     288,   139,   257,   140,   143,   141,   258,   280,   142,   259,
-      10,    10,   260,   286,   147,   212,   210,   212,    -1,    -1,
-      -1,    -1,    -1,   293,    -1,    -1,   296,    -1,    -1,    -1,
-      -1,   336,   324,    -1,   324,   308,    -1,    -1,    -1,   331,
-     313,   331,   330,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,   343,    -1,   343,    -1,   328,    -1,   327,    -1,    -1,
-      -1,   353,   332,   353,    -1,    -1,   358,   359,    -1,    -1,
-      -1,    -1,   364,    -1,   364,    -1,    -1,   369,   370,   369,
-     370,     1,    -1,    -1,    -1,    -1,    -1,   357,     8,    -1,
-     363,    -1,   362,    -1,    -1,   368,    16,    17,    -1,    -1,
-      20,    -1,    22,    23,    -1,    25,    -1,    27,    -1,    -1,
-      -1,    -1,    32,    33,     1,    35,    36,    -1,    38,    -1,
-      -1,    -1,    -1,    43,    44,    -1,    46,    14,    15,    -1,
-      -1,    -1,    -1,    -1,    -1,    55,    56,    -1,    58,    -1,
-      60,    61,    62,    30,    31,    65,    -1,    -1,    -1,     1,
-      -1,    -1,    39,    40,    41,    42,    -1,    -1,    -1,    -1,
-      47,    48,    14,    15,    51,    52,    53,    54,    -1,    -1,
-      57,    -1,    59,    -1,    -1,    -1,    -1,    64,    30,    31,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    39,    40,    41,
-      42,    -1,    -1,    -1,    -1,    47,    48,    -1,    -1,    51,
-      52,    53,    54,     3,    -1,    57,     6,    59,     8,     9,
-      -1,    11,    64,    13,    -1,    -1,    16,    17,    18,    19,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      -1,    -1,    32,    33,    34,    35,    36,    -1,    38,    -1,
-      -1,    -1,    -1,    43,    44,    -1,    46,    -1,    -1,    49,
-      -1,    -1,    -1,    -1,    -1,    55,    56,    -1,    58,    -1,
-      60,    61,    62,     3,    -1,    65,     6,    -1,     8,     9,
-      -1,    11,    -1,    13,    -1,    -1,    16,    17,    18,    19,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      -1,    -1,    32,    33,    -1,    35,    36,    37,    38,    -1,
-      -1,    -1,    -1,    43,    44,    -1,    46,    -1,    -1,    49,
-      -1,    -1,    -1,    -1,    -1,    55,    56,    -1,    58,    -1,
-      60,    61,    62,     3,    -1,    65,     6,    -1,     8,     9,
-      -1,    11,    -1,    13,    -1,    -1,    16,    17,    18,    19,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      -1,    -1,    32,    33,    -1,    35,    36,    37,    38,    -1,
-      -1,    -1,    -1,    43,    44,    -1,    46,    -1,    -1,    49,
-      -1,    -1,    -1,    -1,    -1,    55,    56,    -1,    58,    -1,
-      60,    61,    62,     3,    -1,    65,     6,    -1,     8,     9,
+       2,    18,     2,     6,     1,     7,   298,     7,     1,     1,
+       5,     1,     1,     7,    57,    58,    19,   255,    21,   257,
+       1,    24,    25,   110,    31,    85,    86,    12,   266,   267,
+      15,    33,    35,    36,    96,    38,    39,   329,    15,    99,
+     294,     9,   102,    37,     6,    13,    53,   107,     1,    44,
+      14,    15,   290,     0,    22,    23,    41,    19,    51,    21,
+      49,    51,    24,    25,    38,    42,    31,   359,    49,    78,
+      51,    68,   364,    35,    36,    67,    38,    39,    42,    68,
+      49,    32,    33,    49,   146,   147,   148,    48,    53,    98,
+      49,    49,   346,    96,   332,   131,    49,    49,    51,    68,
+     136,   103,    68,   357,   140,    49,    65,    65,    49,    38,
+      95,    52,   114,    65,   114,    49,   101,    37,   120,    52,
+     120,    65,    46,   159,   160,   110,   111,   163,    38,    49,
+       5,    65,    30,    43,    14,    45,   139,    12,   141,   142,
+     143,   144,   145,   146,   147,   148,   149,   150,   151,   152,
+     153,   154,    32,    33,    54,    35,    59,    60,    61,    39,
+     247,    32,    33,    55,    35,   201,   134,    56,    39,    64,
+      50,    66,    67,   360,   361,    40,   161,   213,   265,    50,
+     165,   198,    64,    41,    66,    67,    28,   150,   151,    49,
+     152,   153,   154,   255,   256,   257,   258,   259,   260,   261,
+     262,   263,   264,    50,   266,   267,   174,    52,   295,    32,
+      33,   194,    35,    37,    38,    52,    39,    52,    38,    43,
+      38,    45,    38,   206,   207,    30,    54,    50,   290,   197,
+      49,    56,    40,    55,    12,    49,    38,    52,    50,    49,
+      14,    48,    38,   279,    10,    49,    52,   283,   250,   285,
+     250,    49,   255,   256,   257,   258,   259,   260,   261,   262,
+     263,   264,   247,   266,   267,   325,    52,     4,    38,    48,
+     332,    52,   274,   275,   274,   275,    37,    37,   341,   361,
+     265,   204,   318,   293,   352,   336,   199,   290,    75,   139,
+     141,   258,   144,   142,   149,   143,   256,    10,    10,   282,
+     214,   145,   259,   214,   260,   288,   261,   212,   262,    -1,
+     295,    -1,    -1,   298,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,   338,    -1,    -1,   326,    -1,   326,   310,    -1,   332,
+      -1,   333,   315,   333,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   345,   329,   345,    -1,   330,    -1,   334,
+      -1,    -1,    -1,   355,    -1,   355,    -1,    -1,   360,   361,
+      -1,    -1,    -1,    -1,   366,    -1,   366,    -1,    -1,   371,
+     372,   371,   372,     1,   359,    -1,    -1,    -1,    -1,   364,
+       8,    -1,   365,    -1,    -1,    -1,    -1,   370,    16,    17,
+      -1,    -1,    20,    -1,    22,    23,    -1,    25,    -1,    27,
+      -1,    -1,    -1,    -1,    32,    33,    -1,    35,    36,    -1,
+      38,     1,    -1,    -1,    -1,    43,    44,    45,    -1,    -1,
+      48,    -1,    -1,    -1,    14,    15,    -1,    -1,    -1,    57,
+      58,    -1,    60,    -1,    62,    63,    64,    -1,    -1,    67,
+      30,    31,    -1,     1,    -1,    -1,    -1,    -1,    -1,    39,
+      40,    41,    42,    -1,    -1,    -1,    14,    15,    -1,    49,
+      50,    -1,    -1,    53,    54,    55,    56,    -1,    -1,    59,
+      -1,    61,    30,    31,    -1,    -1,    66,    -1,    -1,    -1,
+      -1,    39,    40,    41,    42,    -1,    -1,    -1,    -1,    -1,
+      -1,    49,    50,    -1,    -1,    53,    54,    55,    56,     3,
+      -1,    59,     6,    61,     8,     9,    -1,    11,    66,    13,
+      -1,    -1,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    -1,    -1,    32,    33,
+      34,    35,    36,    -1,    38,    -1,    -1,    -1,    -1,    43,
+      44,    45,    -1,    -1,    48,    -1,    -1,    51,    -1,    -1,
+      -1,    -1,    -1,    57,    58,    -1,    60,    -1,    62,    63,
+      64,     3,    -1,    67,     6,    -1,     8,     9,    -1,    11,
+      -1,    13,    -1,    -1,    16,    17,    18,    19,    20,    21,
+      22,    23,    24,    25,    26,    27,    28,    29,    -1,    -1,
+      32,    33,    -1,    35,    36,    37,    38,    -1,    -1,    -1,
+      -1,    43,    44,    45,    -1,    -1,    48,    -1,    -1,    51,
+      -1,    -1,    -1,    -1,    -1,    57,    58,    -1,    60,    -1,
+      62,    63,    64,     3,    -1,    67,     6,    -1,     8,     9,
       -1,    11,    -1,    13,    -1,    -1,    16,    17,    18,    19,
       20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
       -1,    -1,    32,    33,    -1,    35,    36,    37,    38,    -1,
-      -1,    -1,    -1,    43,    44,    -1,    46,    -1,    -1,    49,
-      -1,    -1,    -1,    -1,    -1,    55,    56,    -1,    58,    -1,
-      60,    61,    62,     3,    -1,    65,     6,    -1,     8,     9,
-      -1,    11,    -1,    13,    -1,    -1,    16,    17,    18,    19,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
+      -1,    -1,    -1,    43,    44,    45,    -1,    -1,    48,    -1,
+      -1,    51,    -1,    -1,    -1,    -1,    -1,    57,    58,    -1,
+      60,    -1,    62,    63,    64,     3,    -1,    67,     6,    -1,
+       8,     9,    -1,    11,    -1,    13,    -1,    -1,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      28,    29,    -1,    -1,    32,    33,    -1,    35,    36,    37,
+      38,    -1,    -1,    -1,    -1,    43,    44,    45,    -1,    -1,
+      48,    -1,    -1,    51,    -1,    -1,    -1,    -1,    -1,    57,
+      58,    -1,    60,    -1,    62,    63,    64,     3,    -1,    67,
+       6,    -1,     8,     9,    -1,    11,    -1,    13,    -1,    -1,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    -1,    -1,    32,    33,    -1,    35,
+      36,    -1,    38,    -1,    -1,    -1,    -1,    43,    44,    45,
+      -1,    -1,    48,    -1,    -1,    51,    -1,    -1,    -1,    -1,
+      -1,    57,    58,    -1,    60,     8,    62,    63,    64,    -1,
+      -1,    67,    -1,    16,    17,    -1,    -1,    20,    -1,    22,
+      23,    -1,    25,    -1,    27,    -1,    -1,    -1,    -1,    32,
+      33,    -1,    35,    36,    -1,    38,    -1,    -1,    -1,    -1,
+      43,    44,    45,    -1,    -1,    48,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    57,    58,    -1,    60,     8,    62,
+      63,    64,    -1,    -1,    67,    68,    16,    17,    -1,    -1,
+      20,    -1,    22,    23,    -1,    25,    26,    27,    -1,    -1,
       -1,    -1,    32,    33,    -1,    35,    36,    -1,    38,    -1,
-      -1,    -1,    -1,    43,    44,    -1,    46,    -1,    -1,    49,
-      -1,    -1,    -1,    -1,    -1,    55,    56,    -1,    58,     8,
-      60,    61,    62,    -1,    -1,    65,    -1,    16,    17,    -1,
-      -1,    20,    -1,    22,    23,    -1,    25,    -1,    27,    -1,
-      -1,    -1,    -1,    32,    33,    -1,    35,    36,    -1,    38,
-      -1,    -1,    -1,    -1,    43,    44,    -1,    46,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    55,    56,    -1,    58,
-       8,    60,    61,    62,    -1,    -1,    65,    66,    16,    17,
-      -1,    -1,    20,    -1,    22,    23,    -1,    25,    26,    27,
-      -1,    -1,    -1,    -1,    32,    33,    -1,    35,    36,    -1,
-      38,    -1,    -1,    -1,    -1,    43,    44,    -1,    46,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    55,    56,    -1,
-      58,     8,    60,    61,    62,    -1,    -1,    65,    -1,    16,
+      -1,    -1,    -1,    43,    44,    45,    -1,    -1,    48,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    57,    58,    -1,
+      60,     8,    62,    63,    64,    -1,    -1,    67,    -1,    16,
       17,    -1,    -1,    20,    -1,    22,    23,    -1,    25,    -1,
       27,    -1,    -1,    -1,    -1,    32,    33,    -1,    35,    36,
-      -1,    38,    -1,    -1,    -1,    -1,    43,    44,    -1,    46,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    55,    56,
-      -1,    58,     8,    60,    61,    62,    63,    -1,    65,    -1,
-      16,    17,    -1,    -1,    20,    -1,    22,    23,    -1,    25,
-      -1,    27,    -1,    -1,    -1,    -1,    32,    33,    -1,    35,
-      36,    -1,    38,    -1,    -1,    -1,    -1,    43,    44,    -1,
-      46,    16,    17,    -1,    -1,    20,    -1,    22,    23,    55,
-      56,    -1,    58,    -1,    60,    61,    62,    -1,    -1,    65,
-      35,    36,    -1,    38,    -1,    -1,    -1,    -1,    43,    44,
-      -1,    46,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    58,    -1,    -1,    -1,    62,    -1,    -1,
-      65
+      -1,    38,    -1,    -1,    -1,    -1,    43,    44,    45,    -1,
+      -1,    48,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      57,    58,    -1,    60,     8,    62,    63,    64,    65,    -1,
+      67,    -1,    16,    17,    -1,    -1,    20,    -1,    22,    23,
+      -1,    25,    -1,    27,    -1,    -1,    -1,    -1,    32,    33,
+      -1,    35,    36,    -1,    38,    -1,    -1,    -1,    -1,    43,
+      44,    45,    16,    17,    48,    -1,    20,    -1,    22,    23,
+      -1,    -1,    -1,    57,    58,    -1,    60,    -1,    62,    63,
+      64,    35,    36,    67,    38,    -1,    -1,    -1,    -1,    43,
+      44,    45,    -1,    -1,    48,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    60,    -1,    -1,    -1,
+      64,    -1,    -1,    67
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    68,    70,     0,     3,     6,     8,     9,    11,    13,
+       0,    70,    72,     0,     3,     6,     8,     9,    11,    13,
       16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
       26,    27,    28,    29,    32,    33,    34,    35,    36,    38,
-      43,    44,    46,    49,    55,    56,    58,    60,    61,    62,
-      65,    69,    71,    72,    76,    79,    80,    89,    90,    91,
-      92,    97,    98,    99,   100,   101,   102,   108,   109,   114,
-     118,   120,   122,   124,   126,   128,   130,   132,   134,   136,
-     137,   138,   139,   140,   141,   142,   143,   144,   147,   148,
-     152,   156,   157,    38,   155,   155,    38,    46,    71,   139,
-     141,    76,     1,    65,   159,   159,   142,   143,   112,   114,
-     159,   114,    46,    79,   139,    38,    81,    83,   139,   159,
-     159,   139,   139,    50,    37,    38,    43,    44,    76,    77,
-     153,   154,   139,   139,   139,   139,    47,    63,   149,   150,
-     151,   114,   155,     1,    47,    49,   158,    31,    51,    30,
-      52,    53,    54,    40,    14,    15,    42,    41,    55,    56,
-      57,    58,    59,    32,    33,    35,    39,    48,   117,    62,
-      64,    65,   145,    62,    64,   145,   158,   158,    37,    38,
-      43,    44,    28,     1,   113,   114,    26,   115,   116,   119,
-     121,   123,   125,   127,   129,   131,   133,   135,   136,   141,
-     145,   158,   114,   158,    37,     5,    12,   110,   111,    48,
-      85,    86,    47,   158,   113,   114,    76,    37,    76,    37,
-      47,    50,    47,    63,    47,    63,   118,    66,   159,   118,
-     124,   118,   126,   128,   130,   132,   134,   136,   136,   136,
-     137,   138,   138,   139,   139,   139,   118,   118,   114,    38,
-      66,   118,   146,   114,    38,   159,     1,    66,   160,    38,
-      82,    84,    93,    47,    31,    51,    30,    52,    53,    54,
-      40,    15,    42,    14,    48,   117,   160,   159,    79,   111,
-     118,    83,   160,   160,   154,   118,   150,   151,    38,    74,
-      75,    50,    63,    47,    66,    63,   113,    76,    48,    87,
-      88,    47,    95,    14,     1,    49,   161,   119,   141,   125,
-     119,   127,   129,   131,   133,   135,   136,   136,   113,   119,
-     119,    46,   103,    38,    76,    76,    50,    63,   118,    47,
-     160,   118,   118,   160,    10,   119,    84,   161,   113,   112,
-      50,   160,     4,   104,   105,   106,   160,   118,    38,    46,
-     158,    76,   112,   160,    94,   119,    76,   114,     7,    37,
-     107,   106,    79,    70,    73,    96,    76,   161,    50,    50,
-     104,    37,   161,   112,    77,    78,    78,    37,   112,   160,
-     160,    76,    76
+      43,    44,    45,    48,    51,    57,    58,    60,    62,    63,
+      64,    67,    71,    73,    74,    78,    81,    82,    91,    92,
+      93,    94,    99,   100,   101,   102,   103,   104,   110,   111,
+     116,   120,   122,   124,   126,   128,   130,   132,   134,   136,
+     138,   139,   140,   141,   142,   143,   144,   145,   146,   149,
+     150,   154,   158,   159,    38,   157,   157,    38,    48,    73,
+     141,   143,    78,     1,    67,   161,   161,   144,   145,   114,
+     116,   161,   116,    48,    81,   141,    38,    83,    85,   141,
+     161,   161,   141,   141,    52,    37,    38,    43,    45,    78,
+      79,   155,   156,   141,   141,   141,   141,    49,    65,   151,
+     152,   153,   116,    46,   157,     1,    49,    51,   160,    31,
+      53,    30,    54,    55,    56,    40,    14,    15,    42,    41,
+      57,    58,    59,    60,    61,    32,    33,    35,    39,    50,
+     119,    64,    66,    67,   147,    64,    66,   147,   160,   160,
+      37,    38,    43,    45,    28,     1,   115,   116,    26,   117,
+     118,   121,   123,   125,   127,   129,   131,   133,   135,   137,
+     138,   143,   147,   160,   116,   160,    37,     5,    12,   112,
+     113,    50,    87,    88,    49,   160,   115,   116,    78,    37,
+      78,    37,    49,    52,    49,    65,    49,    65,   120,    68,
+     161,   120,   126,   120,   128,   130,   132,   134,   136,   138,
+     138,   138,   139,   140,   140,   141,   141,   141,   120,   120,
+     116,    38,    68,   120,   148,   116,    38,   161,     1,    68,
+     162,    38,    84,    86,    95,    49,    31,    53,    30,    54,
+      55,    56,    40,    15,    42,    14,    50,   119,   162,   161,
+      81,   113,   120,    85,   162,   162,   156,   120,   152,   153,
+      38,    76,    77,    52,    65,    49,    68,    65,   115,    78,
+      50,    89,    90,    49,    97,    14,     1,    51,   163,   121,
+     143,   127,   121,   129,   131,   133,   135,   137,   138,   138,
+     115,   121,   121,    48,   105,    38,    78,    78,    52,    65,
+     120,    49,   162,   120,   120,   162,    10,   121,    86,   163,
+     115,   114,    52,   162,     4,   106,   107,   108,   162,   120,
+      38,    48,   160,    78,   114,   162,    96,   121,    78,   116,
+       7,    37,   109,   108,    81,    72,    75,    98,    78,   163,
+      52,    52,   106,    37,   163,   114,    79,    80,    80,    37,
+     114,   162,   162,    78,    78
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -2028,1414 +2031,1414 @@ yyreduce:
         case 2:
 
 /* Line 1455 of yacc.c  */
-#line 257 "parser.y"
-    { program_parsed(ctx, (yyvsp[(1) - (2)].source_elements)); ;}
+#line 253 "parser.y"
+    { program_parsed(ctx, (yyvsp[(1) - (3)].source_elements)); ;}
     break;
 
   case 3:
 
 /* Line 1455 of yacc.c  */
-#line 260 "parser.y"
+#line 256 "parser.y"
     {;}
     break;
 
   case 4:
 
 /* Line 1455 of yacc.c  */
-#line 261 "parser.y"
+#line 257 "parser.y"
     {;}
     break;
 
   case 5:
 
 /* Line 1455 of yacc.c  */
-#line 265 "parser.y"
+#line 261 "parser.y"
     { (yyval.source_elements) = new_source_elements(ctx); ;}
     break;
 
   case 6:
 
 /* Line 1455 of yacc.c  */
-#line 267 "parser.y"
+#line 263 "parser.y"
     { (yyval.source_elements) = source_elements_add_statement((yyvsp[(1) - (2)].source_elements), (yyvsp[(2) - (2)].statement)); ;}
     break;
 
   case 7:
 
 /* Line 1455 of yacc.c  */
-#line 272 "parser.y"
+#line 268 "parser.y"
     { (yyval.expr) = new_function_expression(ctx, (yyvsp[(2) - (8)].identifier), (yyvsp[(4) - (8)].parameter_list), (yyvsp[(7) - (8)].source_elements), (yyvsp[(1) - (8)].srcptr), (yyvsp[(8) - (8)].srcptr)-(yyvsp[(1) - (8)].srcptr)+1); ;}
     break;
 
   case 8:
 
 /* Line 1455 of yacc.c  */
-#line 275 "parser.y"
-    { push_func(ctx); (yyval.srcptr) = (yyvsp[(1) - (1)].srcptr); ;}
+#line 271 "parser.y"
+    { (yyval.srcptr) = (yyvsp[(1) - (1)].srcptr); ;}
     break;
 
   case 9:
 
 /* Line 1455 of yacc.c  */
-#line 279 "parser.y"
-    { (yyval.source_elements) = function_body_parsed(ctx, (yyvsp[(1) - (1)].source_elements)); ;}
+#line 275 "parser.y"
+    { (yyval.source_elements) = (yyvsp[(1) - (1)].source_elements); ;}
     break;
 
   case 10:
 
 /* Line 1455 of yacc.c  */
-#line 283 "parser.y"
+#line 279 "parser.y"
     { (yyval.parameter_list) = new_parameter_list(ctx, (yyvsp[(1) - (1)].identifier)); ;}
     break;
 
   case 11:
 
 /* Line 1455 of yacc.c  */
-#line 285 "parser.y"
+#line 281 "parser.y"
     { (yyval.parameter_list) = parameter_list_add(ctx, (yyvsp[(1) - (3)].parameter_list), (yyvsp[(3) - (3)].identifier)); ;}
     break;
 
   case 12:
 
 /* Line 1455 of yacc.c  */
-#line 289 "parser.y"
+#line 285 "parser.y"
     { (yyval.parameter_list) = NULL; ;}
     break;
 
   case 13:
 
 /* Line 1455 of yacc.c  */
-#line 290 "parser.y"
+#line 286 "parser.y"
     { (yyval.parameter_list) = (yyvsp[(1) - (1)].parameter_list); ;}
     break;
 
   case 14:
 
 /* Line 1455 of yacc.c  */
-#line 294 "parser.y"
+#line 290 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 15:
 
 /* Line 1455 of yacc.c  */
-#line 295 "parser.y"
+#line 291 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 16:
 
 /* Line 1455 of yacc.c  */
-#line 296 "parser.y"
+#line 292 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 17:
 
 /* Line 1455 of yacc.c  */
-#line 297 "parser.y"
-    { (yyval.statement) = new_empty_statement(ctx); ;}
+#line 293 "parser.y"
+    { (yyval.statement) = new_expression_statement(ctx, (yyvsp[(1) - (1)].expr)); ;}
     break;
 
   case 18:
 
 /* Line 1455 of yacc.c  */
-#line 298 "parser.y"
+#line 294 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 19:
 
 /* Line 1455 of yacc.c  */
-#line 299 "parser.y"
+#line 295 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 20:
 
 /* Line 1455 of yacc.c  */
-#line 300 "parser.y"
+#line 296 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 21:
 
 /* Line 1455 of yacc.c  */
-#line 301 "parser.y"
+#line 297 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 22:
 
 /* Line 1455 of yacc.c  */
-#line 302 "parser.y"
+#line 298 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 23:
 
 /* Line 1455 of yacc.c  */
-#line 303 "parser.y"
+#line 299 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 24:
 
 /* Line 1455 of yacc.c  */
-#line 304 "parser.y"
+#line 300 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 25:
 
 /* Line 1455 of yacc.c  */
-#line 305 "parser.y"
+#line 301 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 26:
 
 /* Line 1455 of yacc.c  */
-#line 306 "parser.y"
+#line 302 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 27:
 
 /* Line 1455 of yacc.c  */
-#line 307 "parser.y"
+#line 303 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 28:
 
 /* Line 1455 of yacc.c  */
-#line 308 "parser.y"
+#line 304 "parser.y"
     { (yyval.statement) = (yyvsp[(1) - (1)].statement); ;}
     break;
 
   case 29:
 
 /* Line 1455 of yacc.c  */
-#line 312 "parser.y"
+#line 308 "parser.y"
     { (yyval.statement_list) = new_statement_list(ctx, (yyvsp[(1) - (1)].statement)); ;}
     break;
 
   case 30:
 
 /* Line 1455 of yacc.c  */
-#line 314 "parser.y"
+#line 310 "parser.y"
     { (yyval.statement_list) = statement_list_add((yyvsp[(1) - (2)].statement_list), (yyvsp[(2) - (2)].statement)); ;}
     break;
 
   case 31:
 
 /* Line 1455 of yacc.c  */
-#line 318 "parser.y"
+#line 314 "parser.y"
     { (yyval.statement_list) = NULL; ;}
     break;
 
   case 32:
 
 /* Line 1455 of yacc.c  */
-#line 319 "parser.y"
+#line 315 "parser.y"
     { (yyval.statement_list) = (yyvsp[(1) - (1)].statement_list); ;}
     break;
 
   case 33:
 
 /* Line 1455 of yacc.c  */
-#line 323 "parser.y"
+#line 319 "parser.y"
     { (yyval.statement) = new_block_statement(ctx, (yyvsp[(2) - (3)].statement_list)); ;}
     break;
 
   case 34:
 
 /* Line 1455 of yacc.c  */
-#line 324 "parser.y"
+#line 320 "parser.y"
     { (yyval.statement) = new_block_statement(ctx, NULL); ;}
     break;
 
   case 35:
 
 /* Line 1455 of yacc.c  */
-#line 329 "parser.y"
+#line 325 "parser.y"
     { (yyval.statement) = new_var_statement(ctx, (yyvsp[(2) - (3)].variable_list)); ;}
     break;
 
   case 36:
 
 /* Line 1455 of yacc.c  */
-#line 333 "parser.y"
+#line 329 "parser.y"
     { (yyval.variable_list) = new_variable_list(ctx, (yyvsp[(1) - (1)].variable_declaration)); ;}
     break;
 
   case 37:
 
 /* Line 1455 of yacc.c  */
-#line 335 "parser.y"
+#line 331 "parser.y"
     { (yyval.variable_list) = variable_list_add(ctx, (yyvsp[(1) - (3)].variable_list), (yyvsp[(3) - (3)].variable_declaration)); ;}
     break;
 
   case 38:
 
 /* Line 1455 of yacc.c  */
-#line 340 "parser.y"
+#line 336 "parser.y"
     { (yyval.variable_list) = new_variable_list(ctx, (yyvsp[(1) - (1)].variable_declaration)); ;}
     break;
 
   case 39:
 
 /* Line 1455 of yacc.c  */
-#line 342 "parser.y"
+#line 338 "parser.y"
     { (yyval.variable_list) = variable_list_add(ctx, (yyvsp[(1) - (3)].variable_list), (yyvsp[(3) - (3)].variable_declaration)); ;}
     break;
 
   case 40:
 
 /* Line 1455 of yacc.c  */
-#line 347 "parser.y"
+#line 343 "parser.y"
     { (yyval.variable_declaration) = new_variable_declaration(ctx, (yyvsp[(1) - (2)].identifier), (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 41:
 
 /* Line 1455 of yacc.c  */
-#line 352 "parser.y"
+#line 348 "parser.y"
     { (yyval.variable_declaration) = new_variable_declaration(ctx, (yyvsp[(1) - (2)].identifier), (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 42:
 
 /* Line 1455 of yacc.c  */
-#line 356 "parser.y"
+#line 352 "parser.y"
     { (yyval.expr) = NULL; ;}
     break;
 
   case 43:
 
 /* Line 1455 of yacc.c  */
-#line 357 "parser.y"
+#line 353 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 44:
 
 /* Line 1455 of yacc.c  */
-#line 362 "parser.y"
+#line 358 "parser.y"
     { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;}
     break;
 
   case 45:
 
 /* Line 1455 of yacc.c  */
-#line 366 "parser.y"
+#line 362 "parser.y"
     { (yyval.expr) = NULL; ;}
     break;
 
   case 46:
 
 /* Line 1455 of yacc.c  */
-#line 367 "parser.y"
+#line 363 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 47:
 
 /* Line 1455 of yacc.c  */
-#line 372 "parser.y"
+#line 368 "parser.y"
     { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;}
     break;
 
   case 48:
 
 /* Line 1455 of yacc.c  */
-#line 376 "parser.y"
-    { (yyval.statement) = new_empty_statement(ctx); ;}
+#line 372 "parser.y"
+    { (yyval.statement) = new_statement(ctx, STAT_EMPTY, 0); ;}
     break;
 
   case 49:
 
 /* Line 1455 of yacc.c  */
-#line 381 "parser.y"
+#line 377 "parser.y"
     { (yyval.statement) = new_expression_statement(ctx, (yyvsp[(1) - (2)].expr)); ;}
     break;
 
   case 50:
 
 /* Line 1455 of yacc.c  */
-#line 386 "parser.y"
+#line 382 "parser.y"
     { (yyval.statement) = new_if_statement(ctx, (yyvsp[(3) - (7)].expr), (yyvsp[(5) - (7)].statement), (yyvsp[(7) - (7)].statement)); ;}
     break;
 
   case 51:
 
 /* Line 1455 of yacc.c  */
-#line 388 "parser.y"
+#line 384 "parser.y"
     { (yyval.statement) = new_if_statement(ctx, (yyvsp[(3) - (5)].expr), (yyvsp[(5) - (5)].statement), NULL); ;}
     break;
 
   case 52:
 
 /* Line 1455 of yacc.c  */
-#line 393 "parser.y"
+#line 389 "parser.y"
     { (yyval.statement) = new_while_statement(ctx, TRUE, (yyvsp[(5) - (7)].expr), (yyvsp[(2) - (7)].statement)); ;}
     break;
 
   case 53:
 
 /* Line 1455 of yacc.c  */
-#line 395 "parser.y"
+#line 391 "parser.y"
     { (yyval.statement) = new_while_statement(ctx, FALSE, (yyvsp[(3) - (5)].expr), (yyvsp[(5) - (5)].statement)); ;}
     break;
 
   case 54:
 
 /* Line 1455 of yacc.c  */
-#line 397 "parser.y"
+#line 393 "parser.y"
     { if(!explicit_error(ctx, (yyvsp[(3) - (3)].expr), ';')) YYABORT; ;}
     break;
 
   case 55:
 
 /* Line 1455 of yacc.c  */
-#line 399 "parser.y"
+#line 395 "parser.y"
     { if(!explicit_error(ctx, (yyvsp[(6) - (6)].expr), ';')) YYABORT; ;}
     break;
 
   case 56:
 
 /* Line 1455 of yacc.c  */
-#line 401 "parser.y"
+#line 397 "parser.y"
     { (yyval.statement) = new_for_statement(ctx, NULL, (yyvsp[(3) - (11)].expr), (yyvsp[(6) - (11)].expr), (yyvsp[(9) - (11)].expr), (yyvsp[(11) - (11)].statement)); ;}
     break;
 
   case 57:
 
 /* Line 1455 of yacc.c  */
-#line 403 "parser.y"
+#line 399 "parser.y"
     { if(!explicit_error(ctx, (yyvsp[(4) - (4)].variable_list), ';')) YYABORT; ;}
     break;
 
   case 58:
 
 /* Line 1455 of yacc.c  */
-#line 405 "parser.y"
+#line 401 "parser.y"
     { if(!explicit_error(ctx, (yyvsp[(7) - (7)].expr), ';')) YYABORT; ;}
     break;
 
   case 59:
 
 /* Line 1455 of yacc.c  */
-#line 407 "parser.y"
+#line 403 "parser.y"
     { (yyval.statement) = new_for_statement(ctx, (yyvsp[(4) - (12)].variable_list), NULL, (yyvsp[(7) - (12)].expr), (yyvsp[(10) - (12)].expr), (yyvsp[(12) - (12)].statement)); ;}
     break;
 
   case 60:
 
 /* Line 1455 of yacc.c  */
-#line 409 "parser.y"
+#line 405 "parser.y"
     { (yyval.statement) = new_forin_statement(ctx, NULL, (yyvsp[(3) - (7)].expr), (yyvsp[(5) - (7)].expr), (yyvsp[(7) - (7)].statement)); ;}
     break;
 
   case 61:
 
 /* Line 1455 of yacc.c  */
-#line 411 "parser.y"
+#line 407 "parser.y"
     { (yyval.statement) = new_forin_statement(ctx, (yyvsp[(4) - (8)].variable_declaration), NULL, (yyvsp[(6) - (8)].expr), (yyvsp[(8) - (8)].statement)); ;}
     break;
 
   case 62:
 
 /* Line 1455 of yacc.c  */
-#line 416 "parser.y"
+#line 412 "parser.y"
     { (yyval.statement) = new_continue_statement(ctx, (yyvsp[(2) - (3)].identifier)); ;}
     break;
 
   case 63:
 
 /* Line 1455 of yacc.c  */
-#line 421 "parser.y"
+#line 417 "parser.y"
     { (yyval.statement) = new_break_statement(ctx, (yyvsp[(2) - (3)].identifier)); ;}
     break;
 
   case 64:
 
 /* Line 1455 of yacc.c  */
-#line 426 "parser.y"
+#line 422 "parser.y"
     { (yyval.statement) = new_return_statement(ctx, (yyvsp[(2) - (3)].expr)); ;}
     break;
 
   case 65:
 
 /* Line 1455 of yacc.c  */
-#line 431 "parser.y"
+#line 427 "parser.y"
     { (yyval.statement) = new_with_statement(ctx, (yyvsp[(3) - (5)].expr), (yyvsp[(5) - (5)].statement)); ;}
     break;
 
   case 66:
 
 /* Line 1455 of yacc.c  */
-#line 436 "parser.y"
+#line 432 "parser.y"
     { (yyval.statement) = new_labelled_statement(ctx, (yyvsp[(1) - (3)].identifier), (yyvsp[(3) - (3)].statement)); ;}
     break;
 
   case 67:
 
 /* Line 1455 of yacc.c  */
-#line 441 "parser.y"
+#line 437 "parser.y"
     { (yyval.statement) = new_switch_statement(ctx, (yyvsp[(3) - (5)].expr), (yyvsp[(5) - (5)].case_clausule)); ;}
     break;
 
   case 68:
 
 /* Line 1455 of yacc.c  */
-#line 446 "parser.y"
+#line 442 "parser.y"
     { (yyval.case_clausule) = new_case_block(ctx, (yyvsp[(2) - (3)].case_list), NULL, NULL); ;}
     break;
 
   case 69:
 
 /* Line 1455 of yacc.c  */
-#line 448 "parser.y"
+#line 444 "parser.y"
     { (yyval.case_clausule) = new_case_block(ctx, (yyvsp[(2) - (5)].case_list), (yyvsp[(3) - (5)].case_clausule), (yyvsp[(4) - (5)].case_list)); ;}
     break;
 
   case 70:
 
 /* Line 1455 of yacc.c  */
-#line 452 "parser.y"
+#line 448 "parser.y"
     { (yyval.case_list) = NULL; ;}
     break;
 
   case 71:
 
 /* Line 1455 of yacc.c  */
-#line 453 "parser.y"
+#line 449 "parser.y"
     { (yyval.case_list) = (yyvsp[(1) - (1)].case_list); ;}
     break;
 
   case 72:
 
 /* Line 1455 of yacc.c  */
-#line 457 "parser.y"
+#line 453 "parser.y"
     { (yyval.case_list) = new_case_list(ctx, (yyvsp[(1) - (1)].case_clausule)); ;}
     break;
 
   case 73:
 
 /* Line 1455 of yacc.c  */
-#line 459 "parser.y"
+#line 455 "parser.y"
     { (yyval.case_list) = case_list_add(ctx, (yyvsp[(1) - (2)].case_list), (yyvsp[(2) - (2)].case_clausule)); ;}
     break;
 
   case 74:
 
 /* Line 1455 of yacc.c  */
-#line 464 "parser.y"
+#line 460 "parser.y"
     { (yyval.case_clausule) = new_case_clausule(ctx, (yyvsp[(2) - (4)].expr), (yyvsp[(4) - (4)].statement_list)); ;}
     break;
 
   case 75:
 
 /* Line 1455 of yacc.c  */
-#line 469 "parser.y"
+#line 465 "parser.y"
     { (yyval.case_clausule) = new_case_clausule(ctx, NULL, (yyvsp[(3) - (3)].statement_list)); ;}
     break;
 
   case 76:
 
 /* Line 1455 of yacc.c  */
-#line 474 "parser.y"
+#line 470 "parser.y"
     { (yyval.statement) = new_throw_statement(ctx, (yyvsp[(2) - (3)].expr)); ;}
     break;
 
   case 77:
 
 /* Line 1455 of yacc.c  */
-#line 478 "parser.y"
+#line 474 "parser.y"
     { (yyval.statement) = new_try_statement(ctx, (yyvsp[(2) - (3)].statement), (yyvsp[(3) - (3)].catch_block), NULL); ;}
     break;
 
   case 78:
 
 /* Line 1455 of yacc.c  */
-#line 479 "parser.y"
+#line 475 "parser.y"
     { (yyval.statement) = new_try_statement(ctx, (yyvsp[(2) - (3)].statement), NULL, (yyvsp[(3) - (3)].statement)); ;}
     break;
 
   case 79:
 
 /* Line 1455 of yacc.c  */
-#line 481 "parser.y"
+#line 477 "parser.y"
     { (yyval.statement) = new_try_statement(ctx, (yyvsp[(2) - (4)].statement), (yyvsp[(3) - (4)].catch_block), (yyvsp[(4) - (4)].statement)); ;}
     break;
 
   case 80:
 
 /* Line 1455 of yacc.c  */
-#line 486 "parser.y"
+#line 482 "parser.y"
     { (yyval.catch_block) = new_catch_block(ctx, (yyvsp[(3) - (5)].identifier), (yyvsp[(5) - (5)].statement)); ;}
     break;
 
   case 81:
 
 /* Line 1455 of yacc.c  */
-#line 490 "parser.y"
+#line 486 "parser.y"
     { (yyval.statement) = (yyvsp[(2) - (2)].statement); ;}
     break;
 
   case 82:
 
 /* Line 1455 of yacc.c  */
-#line 494 "parser.y"
+#line 490 "parser.y"
     { (yyval.expr) = NULL; ;}
     break;
 
   case 83:
 
 /* Line 1455 of yacc.c  */
-#line 495 "parser.y"
+#line 491 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 84:
 
 /* Line 1455 of yacc.c  */
-#line 498 "parser.y"
+#line 494 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 85:
 
 /* Line 1455 of yacc.c  */
-#line 499 "parser.y"
-    { set_error(ctx, IDS_SYNTAX_ERROR); YYABORT; ;}
+#line 495 "parser.y"
+    { set_error(ctx, JS_E_SYNTAX); YYABORT; ;}
     break;
 
   case 86:
 
 /* Line 1455 of yacc.c  */
-#line 503 "parser.y"
+#line 499 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 87:
 
 /* Line 1455 of yacc.c  */
-#line 505 "parser.y"
+#line 501 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_COMMA, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 88:
 
 /* Line 1455 of yacc.c  */
-#line 509 "parser.y"
+#line 505 "parser.y"
     { (yyval.expr) = NULL; ;}
     break;
 
   case 89:
 
 /* Line 1455 of yacc.c  */
-#line 510 "parser.y"
+#line 506 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 90:
 
 /* Line 1455 of yacc.c  */
-#line 515 "parser.y"
+#line 511 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 91:
 
 /* Line 1455 of yacc.c  */
-#line 517 "parser.y"
+#line 513 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_COMMA, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 92:
 
 /* Line 1455 of yacc.c  */
-#line 520 "parser.y"
+#line 516 "parser.y"
     { (yyval.ival) = (yyvsp[(1) - (1)].ival); ;}
     break;
 
   case 93:
 
 /* Line 1455 of yacc.c  */
-#line 521 "parser.y"
+#line 517 "parser.y"
     { (yyval.ival) = EXPR_ASSIGNDIV; ;}
     break;
 
   case 94:
 
 /* Line 1455 of yacc.c  */
-#line 525 "parser.y"
+#line 521 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 95:
 
 /* Line 1455 of yacc.c  */
-#line 527 "parser.y"
+#line 523 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_ASSIGN, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 96:
 
 /* Line 1455 of yacc.c  */
-#line 529 "parser.y"
+#line 525 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, (yyvsp[(2) - (3)].ival), (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 97:
 
 /* Line 1455 of yacc.c  */
-#line 534 "parser.y"
+#line 530 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 98:
 
 /* Line 1455 of yacc.c  */
-#line 536 "parser.y"
+#line 532 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_ASSIGN, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 99:
 
 /* Line 1455 of yacc.c  */
-#line 538 "parser.y"
+#line 534 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, (yyvsp[(2) - (3)].ival), (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 100:
 
 /* Line 1455 of yacc.c  */
-#line 542 "parser.y"
+#line 538 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 101:
 
 /* Line 1455 of yacc.c  */
-#line 544 "parser.y"
+#line 540 "parser.y"
     { (yyval.expr) = new_conditional_expression(ctx, (yyvsp[(1) - (5)].expr), (yyvsp[(3) - (5)].expr), (yyvsp[(5) - (5)].expr)); ;}
     break;
 
   case 102:
 
 /* Line 1455 of yacc.c  */
-#line 549 "parser.y"
+#line 545 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 103:
 
 /* Line 1455 of yacc.c  */
-#line 551 "parser.y"
+#line 547 "parser.y"
     { (yyval.expr) = new_conditional_expression(ctx, (yyvsp[(1) - (5)].expr), (yyvsp[(3) - (5)].expr), (yyvsp[(5) - (5)].expr)); ;}
     break;
 
   case 104:
 
 /* Line 1455 of yacc.c  */
-#line 555 "parser.y"
+#line 551 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 105:
 
 /* Line 1455 of yacc.c  */
-#line 557 "parser.y"
+#line 553 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 106:
 
 /* Line 1455 of yacc.c  */
-#line 562 "parser.y"
+#line 558 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 107:
 
 /* Line 1455 of yacc.c  */
-#line 564 "parser.y"
+#line 560 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 108:
 
 /* Line 1455 of yacc.c  */
-#line 568 "parser.y"
+#line 564 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 109:
 
 /* Line 1455 of yacc.c  */
-#line 570 "parser.y"
+#line 566 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 110:
 
 /* Line 1455 of yacc.c  */
-#line 575 "parser.y"
+#line 571 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 111:
 
 /* Line 1455 of yacc.c  */
-#line 577 "parser.y"
+#line 573 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 112:
 
 /* Line 1455 of yacc.c  */
-#line 581 "parser.y"
+#line 577 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 113:
 
 /* Line 1455 of yacc.c  */
-#line 583 "parser.y"
+#line 579 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_BOR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 114:
 
 /* Line 1455 of yacc.c  */
-#line 588 "parser.y"
+#line 584 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 115:
 
 /* Line 1455 of yacc.c  */
-#line 590 "parser.y"
+#line 586 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_BOR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 116:
 
 /* Line 1455 of yacc.c  */
-#line 594 "parser.y"
+#line 590 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 117:
 
 /* Line 1455 of yacc.c  */
-#line 596 "parser.y"
+#line 592 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_BXOR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 118:
 
 /* Line 1455 of yacc.c  */
-#line 601 "parser.y"
+#line 597 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 119:
 
 /* Line 1455 of yacc.c  */
-#line 603 "parser.y"
+#line 599 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_BXOR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 120:
 
 /* Line 1455 of yacc.c  */
-#line 607 "parser.y"
+#line 603 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 121:
 
 /* Line 1455 of yacc.c  */
-#line 609 "parser.y"
+#line 605 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_BAND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 122:
 
 /* Line 1455 of yacc.c  */
-#line 614 "parser.y"
+#line 610 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 123:
 
 /* Line 1455 of yacc.c  */
-#line 616 "parser.y"
+#line 612 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_BAND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 124:
 
 /* Line 1455 of yacc.c  */
-#line 620 "parser.y"
+#line 616 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 125:
 
 /* Line 1455 of yacc.c  */
-#line 622 "parser.y"
+#line 618 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, (yyvsp[(2) - (3)].ival), (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 126:
 
 /* Line 1455 of yacc.c  */
-#line 626 "parser.y"
+#line 622 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 127:
 
 /* Line 1455 of yacc.c  */
-#line 628 "parser.y"
+#line 624 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, (yyvsp[(2) - (3)].ival), (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 128:
 
 /* Line 1455 of yacc.c  */
-#line 632 "parser.y"
+#line 628 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 129:
 
 /* Line 1455 of yacc.c  */
-#line 634 "parser.y"
+#line 630 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, (yyvsp[(2) - (3)].ival), (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 130:
 
 /* Line 1455 of yacc.c  */
-#line 636 "parser.y"
+#line 632 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_INSTANCEOF, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 131:
 
 /* Line 1455 of yacc.c  */
-#line 638 "parser.y"
+#line 634 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_IN, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 132:
 
 /* Line 1455 of yacc.c  */
-#line 642 "parser.y"
+#line 638 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 133:
 
 /* Line 1455 of yacc.c  */
-#line 644 "parser.y"
+#line 640 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, (yyvsp[(2) - (3)].ival), (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 134:
 
 /* Line 1455 of yacc.c  */
-#line 646 "parser.y"
+#line 642 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_INSTANCEOF, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 135:
 
 /* Line 1455 of yacc.c  */
-#line 650 "parser.y"
+#line 646 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 136:
 
 /* Line 1455 of yacc.c  */
-#line 652 "parser.y"
+#line 648 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, (yyvsp[(2) - (3)].ival), (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 137:
 
 /* Line 1455 of yacc.c  */
-#line 657 "parser.y"
+#line 653 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 138:
 
 /* Line 1455 of yacc.c  */
-#line 659 "parser.y"
+#line 655 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_ADD, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 139:
 
 /* Line 1455 of yacc.c  */
-#line 661 "parser.y"
+#line 657 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_SUB, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 140:
 
 /* Line 1455 of yacc.c  */
-#line 665 "parser.y"
+#line 661 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 141:
 
 /* Line 1455 of yacc.c  */
-#line 667 "parser.y"
+#line 663 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_MUL, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 142:
 
 /* Line 1455 of yacc.c  */
-#line 669 "parser.y"
+#line 665 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_DIV, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 143:
 
 /* Line 1455 of yacc.c  */
-#line 671 "parser.y"
+#line 667 "parser.y"
     { (yyval.expr) = new_binary_expression(ctx, EXPR_MOD, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 144:
 
 /* Line 1455 of yacc.c  */
-#line 675 "parser.y"
+#line 671 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 145:
 
 /* Line 1455 of yacc.c  */
-#line 677 "parser.y"
+#line 673 "parser.y"
     { (yyval.expr) = new_unary_expression(ctx, EXPR_DELETE, (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 146:
 
 /* Line 1455 of yacc.c  */
-#line 678 "parser.y"
+#line 674 "parser.y"
     { (yyval.expr) = new_unary_expression(ctx, EXPR_VOID, (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 147:
 
 /* Line 1455 of yacc.c  */
-#line 680 "parser.y"
+#line 676 "parser.y"
     { (yyval.expr) = new_unary_expression(ctx, EXPR_TYPEOF, (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 148:
 
 /* Line 1455 of yacc.c  */
-#line 681 "parser.y"
+#line 677 "parser.y"
     { (yyval.expr) = new_unary_expression(ctx, EXPR_PREINC, (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 149:
 
 /* Line 1455 of yacc.c  */
-#line 682 "parser.y"
+#line 678 "parser.y"
     { (yyval.expr) = new_unary_expression(ctx, EXPR_PREDEC, (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 150:
 
 /* Line 1455 of yacc.c  */
-#line 683 "parser.y"
+#line 679 "parser.y"
     { (yyval.expr) = new_unary_expression(ctx, EXPR_PLUS, (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 151:
 
 /* Line 1455 of yacc.c  */
-#line 684 "parser.y"
+#line 680 "parser.y"
     { (yyval.expr) = new_unary_expression(ctx, EXPR_MINUS, (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 152:
 
 /* Line 1455 of yacc.c  */
-#line 685 "parser.y"
+#line 681 "parser.y"
     { (yyval.expr) = new_unary_expression(ctx, EXPR_BITNEG, (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 153:
 
 /* Line 1455 of yacc.c  */
-#line 686 "parser.y"
+#line 682 "parser.y"
     { (yyval.expr) = new_unary_expression(ctx, EXPR_LOGNEG, (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 154:
 
 /* Line 1455 of yacc.c  */
-#line 691 "parser.y"
+#line 687 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 155:
 
 /* Line 1455 of yacc.c  */
-#line 693 "parser.y"
+#line 689 "parser.y"
     { (yyval.expr) = new_unary_expression(ctx, EXPR_POSTINC, (yyvsp[(1) - (2)].expr)); ;}
     break;
 
   case 156:
 
 /* Line 1455 of yacc.c  */
-#line 695 "parser.y"
+#line 691 "parser.y"
     { (yyval.expr) = new_unary_expression(ctx, EXPR_POSTDEC, (yyvsp[(1) - (2)].expr)); ;}
     break;
 
   case 157:
 
 /* Line 1455 of yacc.c  */
-#line 700 "parser.y"
+#line 696 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 158:
 
 /* Line 1455 of yacc.c  */
-#line 701 "parser.y"
+#line 697 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 159:
 
 /* Line 1455 of yacc.c  */
-#line 705 "parser.y"
+#line 701 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 160:
 
 /* Line 1455 of yacc.c  */
-#line 706 "parser.y"
+#line 702 "parser.y"
     { (yyval.expr) = new_new_expression(ctx, (yyvsp[(2) - (2)].expr), NULL); ;}
     break;
 
   case 161:
 
 /* Line 1455 of yacc.c  */
-#line 710 "parser.y"
+#line 706 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 162:
 
 /* Line 1455 of yacc.c  */
-#line 711 "parser.y"
+#line 707 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 163:
 
 /* Line 1455 of yacc.c  */
-#line 713 "parser.y"
-    { (yyval.expr) = new_array_expression(ctx, (yyvsp[(1) - (4)].expr), (yyvsp[(3) - (4)].expr)); ;}
+#line 709 "parser.y"
+    { (yyval.expr) = new_binary_expression(ctx, EXPR_ARRAY, (yyvsp[(1) - (4)].expr), (yyvsp[(3) - (4)].expr)); ;}
     break;
 
   case 164:
 
 /* Line 1455 of yacc.c  */
-#line 715 "parser.y"
+#line 711 "parser.y"
     { (yyval.expr) = new_member_expression(ctx, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].identifier)); ;}
     break;
 
   case 165:
 
 /* Line 1455 of yacc.c  */
-#line 717 "parser.y"
+#line 713 "parser.y"
     { (yyval.expr) = new_new_expression(ctx, (yyvsp[(2) - (3)].expr), (yyvsp[(3) - (3)].argument_list)); ;}
     break;
 
   case 166:
 
 /* Line 1455 of yacc.c  */
-#line 722 "parser.y"
+#line 718 "parser.y"
     { (yyval.expr) = new_call_expression(ctx, (yyvsp[(1) - (2)].expr), (yyvsp[(2) - (2)].argument_list)); ;}
     break;
 
   case 167:
 
 /* Line 1455 of yacc.c  */
-#line 724 "parser.y"
+#line 720 "parser.y"
     { (yyval.expr) = new_call_expression(ctx, (yyvsp[(1) - (2)].expr), (yyvsp[(2) - (2)].argument_list)); ;}
     break;
 
   case 168:
 
 /* Line 1455 of yacc.c  */
-#line 726 "parser.y"
-    { (yyval.expr) = new_array_expression(ctx, (yyvsp[(1) - (4)].expr), (yyvsp[(3) - (4)].expr)); ;}
+#line 722 "parser.y"
+    { (yyval.expr) = new_binary_expression(ctx, EXPR_ARRAY, (yyvsp[(1) - (4)].expr), (yyvsp[(3) - (4)].expr)); ;}
     break;
 
   case 169:
 
 /* Line 1455 of yacc.c  */
-#line 728 "parser.y"
+#line 724 "parser.y"
     { (yyval.expr) = new_member_expression(ctx, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].identifier)); ;}
     break;
 
   case 170:
 
 /* Line 1455 of yacc.c  */
-#line 732 "parser.y"
+#line 728 "parser.y"
     { (yyval.argument_list) = NULL; ;}
     break;
 
   case 171:
 
 /* Line 1455 of yacc.c  */
-#line 733 "parser.y"
+#line 729 "parser.y"
     { (yyval.argument_list) = (yyvsp[(2) - (3)].argument_list); ;}
     break;
 
   case 172:
 
 /* Line 1455 of yacc.c  */
-#line 737 "parser.y"
+#line 733 "parser.y"
     { (yyval.argument_list) = new_argument_list(ctx, (yyvsp[(1) - (1)].expr)); ;}
     break;
 
   case 173:
 
 /* Line 1455 of yacc.c  */
-#line 739 "parser.y"
+#line 735 "parser.y"
     { (yyval.argument_list) = argument_list_add(ctx, (yyvsp[(1) - (3)].argument_list), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 174:
 
 /* Line 1455 of yacc.c  */
-#line 743 "parser.y"
-    { (yyval.expr) = new_this_expression(ctx); ;}
+#line 739 "parser.y"
+    { (yyval.expr) = new_expression(ctx, EXPR_THIS, 0); ;}
     break;
 
   case 175:
 
 /* Line 1455 of yacc.c  */
-#line 744 "parser.y"
+#line 740 "parser.y"
     { (yyval.expr) = new_identifier_expression(ctx, (yyvsp[(1) - (1)].identifier)); ;}
     break;
 
   case 176:
 
 /* Line 1455 of yacc.c  */
-#line 745 "parser.y"
+#line 741 "parser.y"
     { (yyval.expr) = new_literal_expression(ctx, (yyvsp[(1) - (1)].literal)); ;}
     break;
 
   case 177:
 
 /* Line 1455 of yacc.c  */
-#line 746 "parser.y"
+#line 742 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 178:
 
 /* Line 1455 of yacc.c  */
-#line 747 "parser.y"
+#line 743 "parser.y"
     { (yyval.expr) = (yyvsp[(1) - (1)].expr); ;}
     break;
 
   case 179:
 
 /* Line 1455 of yacc.c  */
-#line 748 "parser.y"
+#line 744 "parser.y"
     { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;}
     break;
 
   case 180:
 
 /* Line 1455 of yacc.c  */
-#line 752 "parser.y"
+#line 748 "parser.y"
     { (yyval.expr) = new_array_literal_expression(ctx, NULL, 0); ;}
     break;
 
   case 181:
 
 /* Line 1455 of yacc.c  */
-#line 753 "parser.y"
+#line 749 "parser.y"
     { (yyval.expr) = new_array_literal_expression(ctx, NULL, (yyvsp[(2) - (3)].ival)+1); ;}
     break;
 
   case 182:
 
 /* Line 1455 of yacc.c  */
-#line 754 "parser.y"
+#line 750 "parser.y"
     { (yyval.expr) = new_array_literal_expression(ctx, (yyvsp[(2) - (3)].element_list), 0); ;}
     break;
 
   case 183:
 
 /* Line 1455 of yacc.c  */
-#line 756 "parser.y"
+#line 752 "parser.y"
     { (yyval.expr) = new_array_literal_expression(ctx, (yyvsp[(2) - (5)].element_list), (yyvsp[(4) - (5)].ival)+1); ;}
     break;
 
   case 184:
 
 /* Line 1455 of yacc.c  */
-#line 761 "parser.y"
+#line 757 "parser.y"
     { (yyval.element_list) = new_element_list(ctx, (yyvsp[(1) - (2)].ival), (yyvsp[(2) - (2)].expr)); ;}
     break;
 
   case 185:
 
 /* Line 1455 of yacc.c  */
-#line 763 "parser.y"
+#line 759 "parser.y"
     { (yyval.element_list) = element_list_add(ctx, (yyvsp[(1) - (4)].element_list), (yyvsp[(3) - (4)].ival), (yyvsp[(4) - (4)].expr)); ;}
     break;
 
   case 186:
 
 /* Line 1455 of yacc.c  */
-#line 767 "parser.y"
+#line 763 "parser.y"
     { (yyval.ival) = 1; ;}
     break;
 
   case 187:
 
 /* Line 1455 of yacc.c  */
-#line 768 "parser.y"
+#line 764 "parser.y"
     { (yyval.ival) = (yyvsp[(1) - (2)].ival) + 1; ;}
     break;
 
   case 188:
 
 /* Line 1455 of yacc.c  */
-#line 772 "parser.y"
+#line 768 "parser.y"
     { (yyval.ival) = 0; ;}
     break;
 
   case 189:
 
 /* Line 1455 of yacc.c  */
-#line 773 "parser.y"
+#line 769 "parser.y"
     { (yyval.ival) = (yyvsp[(1) - (1)].ival); ;}
     break;
 
   case 190:
 
 /* Line 1455 of yacc.c  */
-#line 777 "parser.y"
+#line 773 "parser.y"
     { (yyval.expr) = new_prop_and_value_expression(ctx, NULL); ;}
     break;
 
   case 191:
 
 /* Line 1455 of yacc.c  */
-#line 779 "parser.y"
+#line 775 "parser.y"
     { (yyval.expr) = new_prop_and_value_expression(ctx, (yyvsp[(2) - (3)].property_list)); ;}
     break;
 
   case 192:
 
 /* Line 1455 of yacc.c  */
-#line 784 "parser.y"
+#line 780 "parser.y"
     { (yyval.property_list) = new_property_list(ctx, (yyvsp[(1) - (3)].literal), (yyvsp[(3) - (3)].expr)); ;}
     break;
 
   case 193:
 
 /* Line 1455 of yacc.c  */
-#line 786 "parser.y"
+#line 782 "parser.y"
     { (yyval.property_list) = property_list_add(ctx, (yyvsp[(1) - (5)].property_list), (yyvsp[(3) - (5)].literal), (yyvsp[(5) - (5)].expr)); ;}
     break;
 
   case 194:
 
 /* Line 1455 of yacc.c  */
-#line 790 "parser.y"
+#line 786 "parser.y"
     { (yyval.literal) = new_string_literal(ctx, (yyvsp[(1) - (1)].identifier)); ;}
     break;
 
   case 195:
 
 /* Line 1455 of yacc.c  */
-#line 791 "parser.y"
+#line 787 "parser.y"
     { (yyval.literal) = new_string_literal(ctx, (yyvsp[(1) - (1)].wstr)); ;}
     break;
 
   case 196:
 
 /* Line 1455 of yacc.c  */
-#line 792 "parser.y"
+#line 788 "parser.y"
     { (yyval.literal) = (yyvsp[(1) - (1)].literal); ;}
     break;
 
   case 197:
 
 /* Line 1455 of yacc.c  */
-#line 796 "parser.y"
+#line 792 "parser.y"
     { (yyval.identifier) = NULL; ;}
     break;
 
   case 198:
 
 /* Line 1455 of yacc.c  */
-#line 797 "parser.y"
+#line 793 "parser.y"
     { (yyval.identifier) = (yyvsp[(1) - (1)].identifier); ;}
     break;
 
   case 199:
 
 /* Line 1455 of yacc.c  */
-#line 801 "parser.y"
+#line 797 "parser.y"
     { (yyval.literal) = new_null_literal(ctx); ;}
     break;
 
   case 200:
 
 /* Line 1455 of yacc.c  */
-#line 802 "parser.y"
+#line 798 "parser.y"
     { (yyval.literal) = (yyvsp[(1) - (1)].literal); ;}
     break;
 
   case 201:
 
 /* Line 1455 of yacc.c  */
-#line 803 "parser.y"
+#line 799 "parser.y"
     { (yyval.literal) = (yyvsp[(1) - (1)].literal); ;}
     break;
 
   case 202:
 
 /* Line 1455 of yacc.c  */
-#line 804 "parser.y"
+#line 800 "parser.y"
     { (yyval.literal) = new_string_literal(ctx, (yyvsp[(1) - (1)].wstr)); ;}
     break;
 
   case 203:
 
 /* Line 1455 of yacc.c  */
-#line 805 "parser.y"
+#line 801 "parser.y"
     { (yyval.literal) = parse_regexp(ctx);
                                   if(!(yyval.literal)) YYABORT; ;}
     break;
@@ -3443,7 +3446,7 @@ yyreduce:
   case 204:
 
 /* Line 1455 of yacc.c  */
-#line 807 "parser.y"
+#line 803 "parser.y"
     { (yyval.literal) = parse_regexp(ctx);
                                   if(!(yyval.literal)) YYABORT; ;}
     break;
@@ -3451,49 +3454,56 @@ yyreduce:
   case 205:
 
 /* Line 1455 of yacc.c  */
-#line 812 "parser.y"
+#line 808 "parser.y"
     { (yyval.literal) = new_boolean_literal(ctx, VARIANT_TRUE); ;}
     break;
 
   case 206:
 
 /* Line 1455 of yacc.c  */
-#line 813 "parser.y"
+#line 809 "parser.y"
     { (yyval.literal) = new_boolean_literal(ctx, VARIANT_FALSE); ;}
     break;
 
-  case 208:
+  case 207:
+
+/* Line 1455 of yacc.c  */
+#line 810 "parser.y"
+    { (yyval.literal) = (yyvsp[(1) - (1)].literal); ;}
+    break;
+
+  case 209:
 
 /* Line 1455 of yacc.c  */
-#line 817 "parser.y"
+#line 814 "parser.y"
     { if(!allow_auto_semicolon(ctx)) {YYABORT;} ;}
     break;
 
-  case 210:
+  case 211:
 
 /* Line 1455 of yacc.c  */
-#line 821 "parser.y"
-    { set_error(ctx, IDS_LBRACKET); YYABORT; ;}
+#line 818 "parser.y"
+    { set_error(ctx, JS_E_MISSING_LBRACKET); YYABORT; ;}
     break;
 
-  case 212:
+  case 213:
 
 /* Line 1455 of yacc.c  */
-#line 825 "parser.y"
-    { set_error(ctx, IDS_RBRACKET); YYABORT; ;}
+#line 822 "parser.y"
+    { set_error(ctx, JS_E_MISSING_RBRACKET); YYABORT; ;}
     break;
 
-  case 214:
+  case 215:
 
 /* Line 1455 of yacc.c  */
-#line 829 "parser.y"
-    { set_error(ctx, IDS_SEMICOLON); YYABORT; ;}
+#line 826 "parser.y"
+    { set_error(ctx, JS_E_MISSING_SEMICOLON); YYABORT; ;}
     break;
 
 
 
 /* Line 1455 of yacc.c  */
-#line 3497 "parser.tab.c"
+#line 3507 "parser.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -3705,7 +3715,7 @@ yyreturn:
 
 
 /* Line 1675 of yacc.c  */
-#line 831 "parser.y"
+#line 828 "parser.y"
 
 
 static BOOL allow_auto_semicolon(parser_ctx_t *ctx)
@@ -3713,31 +3723,35 @@ static BOOL allow_auto_semicolon(parser_ctx_t *ctx)
     return ctx->nl || ctx->ptr == ctx->end || *(ctx->ptr-1) == '}';
 }
 
-static literal_t *new_string_literal(parser_ctx_t *ctx, const WCHAR *str)
+static void *new_statement(parser_ctx_t *ctx, statement_type_t type, size_t size)
 {
-    literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
+    statement_t *stat;
 
-    ret->type = LT_STRING;
-    ret->u.wstr = str;
+    stat = parser_alloc(ctx, size ? size : sizeof(*stat));
+    if(!stat)
+        return NULL;
 
-    return ret;
+    stat->type = type;
+    stat->next = NULL;
+
+    return stat;
 }
 
-static literal_t *new_null_literal(parser_ctx_t *ctx)
+static literal_t *new_string_literal(parser_ctx_t *ctx, const WCHAR *str)
 {
     literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
 
-    ret->type = LT_NULL;
+    ret->type = LT_STRING;
+    ret->u.wstr = str;
 
     return ret;
 }
 
-static literal_t *new_boolean_literal(parser_ctx_t *ctx, VARIANT_BOOL bval)
+static literal_t *new_null_literal(parser_ctx_t *ctx)
 {
     literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
 
-    ret->type = LT_BOOL;
-    ret->u.bval = bval;
+    ret->type = LT_NULL;
 
     return ret;
 }
@@ -3911,10 +3925,12 @@ static case_clausule_t *new_case_block(parser_ctx_t *ctx, case_list_t *case_list
 
 static statement_t *new_block_statement(parser_ctx_t *ctx, statement_list_t *list)
 {
-    block_statement_t *ret = parser_alloc(ctx, sizeof(block_statement_t));
+    block_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_BLOCK, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = block_statement_eval;
-    ret->stat.next = NULL;
     ret->stat_list = list ? list->head : NULL;
 
     return &ret->stat;
@@ -3923,19 +3939,11 @@ static statement_t *new_block_statement(parser_ctx_t *ctx, statement_list_t *lis
 static variable_declaration_t *new_variable_declaration(parser_ctx_t *ctx, const WCHAR *identifier, expression_t *expr)
 {
     variable_declaration_t *ret = parser_alloc(ctx, sizeof(variable_declaration_t));
-    var_list_t *var_list = parser_alloc(ctx, sizeof(var_list_t));
 
     ret->identifier = identifier;
     ret->expr = expr;
     ret->next = NULL;
-
-    var_list->identifier = identifier;
-    var_list->next = NULL;
-
-    if(ctx->func_stack->var_tail)
-        ctx->func_stack->var_tail = ctx->func_stack->var_tail->next = var_list;
-    else
-        ctx->func_stack->var_head = ctx->func_stack->var_tail = var_list;
+    ret->global_next = NULL;
 
     return ret;
 }
@@ -3958,31 +3966,25 @@ static variable_list_t *variable_list_add(parser_ctx_t *ctx, variable_list_t *li
 
 static statement_t *new_var_statement(parser_ctx_t *ctx, variable_list_t *variable_list)
 {
-    var_statement_t *ret = parser_alloc(ctx, sizeof(var_statement_t));
+    var_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_VAR, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = var_statement_eval;
-    ret->stat.next = NULL;
     ret->variable_list = variable_list->head;
 
     return &ret->stat;
 }
 
-static statement_t *new_empty_statement(parser_ctx_t *ctx)
-{
-    statement_t *ret = parser_alloc(ctx, sizeof(statement_t));
-
-    ret->eval = empty_statement_eval;
-    ret->next = NULL;
-
-    return ret;
-}
-
 static statement_t *new_expression_statement(parser_ctx_t *ctx, expression_t *expr)
 {
-    expression_statement_t *ret = parser_alloc(ctx, sizeof(expression_statement_t));
+    expression_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_EXPR, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = expression_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
 
     return &ret->stat;
@@ -3990,10 +3992,12 @@ static statement_t *new_expression_statement(parser_ctx_t *ctx, expression_t *ex
 
 static statement_t *new_if_statement(parser_ctx_t *ctx, expression_t *expr, statement_t *if_stat, statement_t *else_stat)
 {
-    if_statement_t *ret = parser_alloc(ctx, sizeof(if_statement_t));
+    if_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_IF, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = if_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
     ret->if_stat = if_stat;
     ret->else_stat = else_stat;
@@ -4003,10 +4007,12 @@ static statement_t *new_if_statement(parser_ctx_t *ctx, expression_t *expr, stat
 
 static statement_t *new_while_statement(parser_ctx_t *ctx, BOOL dowhile, expression_t *expr, statement_t *stat)
 {
-    while_statement_t *ret = parser_alloc(ctx, sizeof(while_statement_t));
+    while_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_WHILE, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = while_statement_eval;
-    ret->stat.next = NULL;
     ret->do_while = dowhile;
     ret->expr = expr;
     ret->statement = stat;
@@ -4017,10 +4023,12 @@ static statement_t *new_while_statement(parser_ctx_t *ctx, BOOL dowhile, express
 static statement_t *new_for_statement(parser_ctx_t *ctx, variable_list_t *variable_list, expression_t *begin_expr,
         expression_t *expr, expression_t *end_expr, statement_t *statement)
 {
-    for_statement_t *ret = parser_alloc(ctx, sizeof(for_statement_t));
+    for_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_FOR, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = for_statement_eval;
-    ret->stat.next = NULL;
     ret->variable_list = variable_list ? variable_list->head : NULL;
     ret->begin_expr = begin_expr;
     ret->expr = expr;
@@ -4033,10 +4041,12 @@ static statement_t *new_for_statement(parser_ctx_t *ctx, variable_list_t *variab
 static statement_t *new_forin_statement(parser_ctx_t *ctx, variable_declaration_t *variable, expression_t *expr,
         expression_t *in_expr, statement_t *statement)
 {
-    forin_statement_t *ret = parser_alloc(ctx, sizeof(forin_statement_t));
+    forin_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_FORIN, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = forin_statement_eval;
-    ret->stat.next = NULL;
     ret->variable = variable;
     ret->expr = expr;
     ret->in_expr = in_expr;
@@ -4047,10 +4057,12 @@ static statement_t *new_forin_statement(parser_ctx_t *ctx, variable_declaration_
 
 static statement_t *new_continue_statement(parser_ctx_t *ctx, const WCHAR *identifier)
 {
-    branch_statement_t *ret = parser_alloc(ctx, sizeof(branch_statement_t));
+    branch_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_CONTINUE, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = continue_statement_eval;
-    ret->stat.next = NULL;
     ret->identifier = identifier;
 
     return &ret->stat;
@@ -4058,10 +4070,12 @@ static statement_t *new_continue_statement(parser_ctx_t *ctx, const WCHAR *ident
 
 static statement_t *new_break_statement(parser_ctx_t *ctx, const WCHAR *identifier)
 {
-    branch_statement_t *ret = parser_alloc(ctx, sizeof(branch_statement_t));
+    branch_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_BREAK, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = break_statement_eval;
-    ret->stat.next = NULL;
     ret->identifier = identifier;
 
     return &ret->stat;
@@ -4069,10 +4083,12 @@ static statement_t *new_break_statement(parser_ctx_t *ctx, const WCHAR *identifi
 
 static statement_t *new_return_statement(parser_ctx_t *ctx, expression_t *expr)
 {
-    expression_statement_t *ret = parser_alloc(ctx, sizeof(expression_statement_t));
+    expression_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_RETURN, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = return_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
 
     return &ret->stat;
@@ -4080,10 +4096,12 @@ static statement_t *new_return_statement(parser_ctx_t *ctx, expression_t *expr)
 
 static statement_t *new_with_statement(parser_ctx_t *ctx, expression_t *expr, statement_t *statement)
 {
-    with_statement_t *ret = parser_alloc(ctx, sizeof(with_statement_t));
+    with_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_WITH, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = with_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
     ret->statement = statement;
 
@@ -4092,10 +4110,12 @@ static statement_t *new_with_statement(parser_ctx_t *ctx, expression_t *expr, st
 
 static statement_t *new_labelled_statement(parser_ctx_t *ctx, const WCHAR *identifier, statement_t *statement)
 {
-    labelled_statement_t *ret = parser_alloc(ctx, sizeof(labelled_statement_t));
+    labelled_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_LABEL, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = labelled_statement_eval;
-    ret->stat.next = NULL;
     ret->identifier = identifier;
     ret->statement = statement;
 
@@ -4104,10 +4124,12 @@ static statement_t *new_labelled_statement(parser_ctx_t *ctx, const WCHAR *ident
 
 static statement_t *new_switch_statement(parser_ctx_t *ctx, expression_t *expr, case_clausule_t *case_list)
 {
-    switch_statement_t *ret = parser_alloc(ctx, sizeof(switch_statement_t));
+    switch_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_SWITCH, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = switch_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
     ret->case_list = case_list;
 
@@ -4116,10 +4138,12 @@ static statement_t *new_switch_statement(parser_ctx_t *ctx, expression_t *expr,
 
 static statement_t *new_throw_statement(parser_ctx_t *ctx, expression_t *expr)
 {
-    expression_statement_t *ret = parser_alloc(ctx, sizeof(expression_statement_t));
+    expression_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_THROW, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = throw_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
 
     return &ret->stat;
@@ -4128,10 +4152,12 @@ static statement_t *new_throw_statement(parser_ctx_t *ctx, expression_t *expr)
 static statement_t *new_try_statement(parser_ctx_t *ctx, statement_t *try_statement,
        catch_block_t *catch_block, statement_t *finally_statement)
 {
-    try_statement_t *ret = parser_alloc(ctx, sizeof(try_statement_t));
+    try_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_TRY, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = try_statement_eval;
-    ret->stat.next = NULL;
     ret->try_statement = try_statement;
     ret->catch_block = catch_block;
     ret->finally_statement = finally_statement;
@@ -4168,86 +4194,32 @@ static parameter_list_t *parameter_list_add(parser_ctx_t *ctx, parameter_list_t
 static expression_t *new_function_expression(parser_ctx_t *ctx, const WCHAR *identifier,
        parameter_list_t *parameter_list, source_elements_t *source_elements, const WCHAR *src_str, DWORD src_len)
 {
-    function_expression_t *ret = parser_alloc(ctx, sizeof(function_expression_t));
+    function_expression_t *ret = new_expression(ctx, EXPR_FUNC, sizeof(*ret));
 
-    ret->expr.eval = function_expression_eval;
     ret->identifier = identifier;
     ret->parameter_list = parameter_list ? parameter_list->head : NULL;
     ret->source_elements = source_elements;
     ret->src_str = src_str;
     ret->src_len = src_len;
+    ret->next = NULL;
 
-    if(ret->identifier) {
-        function_declaration_t *decl = parser_alloc(ctx, sizeof(function_declaration_t));
+    return &ret->expr;
+}
 
-        decl->expr = ret;
-        decl->next = NULL;
+static void *new_expression(parser_ctx_t *ctx, expression_type_t type, size_t size)
+{
+    expression_t *ret = parser_alloc(ctx, size ? size : sizeof(*ret));
 
-        if(ctx->func_stack->func_tail)
-            ctx->func_stack->func_tail = ctx->func_stack->func_tail->next = decl;
-        else
-            ctx->func_stack->func_head = ctx->func_stack->func_tail = decl;
-    }
+    ret->type = type;
 
-    return &ret->expr;
+    return ret;
 }
 
-static const expression_eval_t expression_eval_table[] = {
-   comma_expression_eval,
-   logical_or_expression_eval,
-   logical_and_expression_eval,
-   binary_or_expression_eval,
-   binary_xor_expression_eval,
-   binary_and_expression_eval,
-   instanceof_expression_eval,
-   in_expression_eval,
-   add_expression_eval,
-   sub_expression_eval,
-   mul_expression_eval,
-   div_expression_eval,
-   mod_expression_eval,
-   delete_expression_eval,
-   void_expression_eval,
-   typeof_expression_eval,
-   minus_expression_eval,
-   plus_expression_eval,
-   post_increment_expression_eval,
-   post_decrement_expression_eval,
-   pre_increment_expression_eval,
-   pre_decrement_expression_eval,
-   equal_expression_eval,
-   equal2_expression_eval,
-   not_equal_expression_eval,
-   not_equal2_expression_eval,
-   less_expression_eval,
-   lesseq_expression_eval,
-   greater_expression_eval,
-   greatereq_expression_eval,
-   binary_negation_expression_eval,
-   logical_negation_expression_eval,
-   left_shift_expression_eval,
-   right_shift_expression_eval,
-   right2_shift_expression_eval,
-   assign_expression_eval,
-   assign_lshift_expression_eval,
-   assign_rshift_expression_eval,
-   assign_rrshift_expression_eval,
-   assign_add_expression_eval,
-   assign_sub_expression_eval,
-   assign_mul_expression_eval,
-   assign_div_expression_eval,
-   assign_mod_expression_eval,
-   assign_and_expression_eval,
-   assign_or_expression_eval,
-   assign_xor_expression_eval,
-};
-
 static expression_t *new_binary_expression(parser_ctx_t *ctx, expression_type_t type,
        expression_t *expression1, expression_t *expression2)
 {
-    binary_expression_t *ret = parser_alloc(ctx, sizeof(binary_expression_t));
+    binary_expression_t *ret = new_expression(ctx, type, sizeof(*ret));
 
-    ret->expr.eval = expression_eval_table[type];
     ret->expression1 = expression1;
     ret->expression2 = expression2;
 
@@ -4256,9 +4228,8 @@ static expression_t *new_binary_expression(parser_ctx_t *ctx, expression_type_t
 
 static expression_t *new_unary_expression(parser_ctx_t *ctx, expression_type_t type, expression_t *expression)
 {
-    unary_expression_t *ret = parser_alloc(ctx, sizeof(unary_expression_t));
+    unary_expression_t *ret = new_expression(ctx, type, sizeof(*ret));
 
-    ret->expr.eval = expression_eval_table[type];
     ret->expression = expression;
 
     return &ret->expr;
@@ -4267,9 +4238,8 @@ static expression_t *new_unary_expression(parser_ctx_t *ctx, expression_type_t t
 static expression_t *new_conditional_expression(parser_ctx_t *ctx, expression_t *expression,
        expression_t *true_expression, expression_t *false_expression)
 {
-    conditional_expression_t *ret = parser_alloc(ctx, sizeof(conditional_expression_t));
+    conditional_expression_t *ret = new_expression(ctx, EXPR_COND, sizeof(*ret));
 
-    ret->expr.eval = conditional_expression_eval;
     ret->expression = expression;
     ret->true_expression = true_expression;
     ret->false_expression = false_expression;
@@ -4277,22 +4247,10 @@ static expression_t *new_conditional_expression(parser_ctx_t *ctx, expression_t
     return &ret->expr;
 }
 
-static expression_t *new_array_expression(parser_ctx_t *ctx, expression_t *member_expr, expression_t *expression)
-{
-    array_expression_t *ret = parser_alloc(ctx, sizeof(array_expression_t));
-
-    ret->expr.eval = array_expression_eval;
-    ret->member_expr = member_expr;
-    ret->expression = expression;
-
-    return &ret->expr;
-}
-
 static expression_t *new_member_expression(parser_ctx_t *ctx, expression_t *expression, const WCHAR *identifier)
 {
-    member_expression_t *ret = parser_alloc(ctx, sizeof(member_expression_t));
+    member_expression_t *ret = new_expression(ctx, EXPR_MEMBER, sizeof(*ret));
 
-    ret->expr.eval = member_expression_eval;
     ret->expression = expression;
     ret->identifier = identifier;
 
@@ -4301,9 +4259,8 @@ static expression_t *new_member_expression(parser_ctx_t *ctx, expression_t *expr
 
 static expression_t *new_new_expression(parser_ctx_t *ctx, expression_t *expression, argument_list_t *argument_list)
 {
-    call_expression_t *ret = parser_alloc(ctx, sizeof(call_expression_t));
+    call_expression_t *ret = new_expression(ctx, EXPR_NEW, sizeof(*ret));
 
-    ret->expr.eval = new_expression_eval;
     ret->expression = expression;
     ret->argument_list = argument_list ? argument_list->head : NULL;
 
@@ -4312,24 +4269,14 @@ static expression_t *new_new_expression(parser_ctx_t *ctx, expression_t *express
 
 static expression_t *new_call_expression(parser_ctx_t *ctx, expression_t *expression, argument_list_t *argument_list)
 {
-    call_expression_t *ret = parser_alloc(ctx, sizeof(call_expression_t));
+    call_expression_t *ret = new_expression(ctx, EXPR_CALL, sizeof(*ret));
 
-    ret->expr.eval = call_expression_eval;
     ret->expression = expression;
     ret->argument_list = argument_list ? argument_list->head : NULL;
 
     return &ret->expr;
 }
 
-static expression_t *new_this_expression(parser_ctx_t *ctx)
-{
-    expression_t *ret = parser_alloc(ctx, sizeof(expression_t));
-
-    ret->eval = this_expression_eval;
-
-    return ret;
-}
-
 static int parser_error(const char *str)
 {
     return 0;
@@ -4337,23 +4284,22 @@ static int parser_error(const char *str)
 
 static void set_error(parser_ctx_t *ctx, UINT error)
 {
-    ctx->hres = JSCRIPT_ERROR|error;
+    ctx->hres = error;
 }
 
 static BOOL explicit_error(parser_ctx_t *ctx, void *obj, WCHAR next)
 {
     if(obj || *(ctx->ptr-1)==next) return TRUE;
 
-    set_error(ctx, IDS_SYNTAX_ERROR);
+    set_error(ctx, JS_E_SYNTAX);
     return FALSE;
 }
 
 
 static expression_t *new_identifier_expression(parser_ctx_t *ctx, const WCHAR *identifier)
 {
-    identifier_expression_t *ret = parser_alloc(ctx, sizeof(identifier_expression_t));
+    identifier_expression_t *ret = new_expression(ctx, EXPR_IDENT, sizeof(*ret));
 
-    ret->expr.eval = identifier_expression_eval;
     ret->identifier = identifier;
 
     return &ret->expr;
@@ -4361,9 +4307,8 @@ static expression_t *new_identifier_expression(parser_ctx_t *ctx, const WCHAR *i
 
 static expression_t *new_array_literal_expression(parser_ctx_t *ctx, element_list_t *element_list, int length)
 {
-    array_literal_expression_t *ret = parser_alloc(ctx, sizeof(array_literal_expression_t));
+    array_literal_expression_t *ret = new_expression(ctx, EXPR_ARRAYLIT, sizeof(*ret));
 
-    ret->expr.eval = array_literal_expression_eval;
     ret->element_list = element_list ? element_list->head : NULL;
     ret->length = length;
 
@@ -4372,9 +4317,8 @@ static expression_t *new_array_literal_expression(parser_ctx_t *ctx, element_lis
 
 static expression_t *new_prop_and_value_expression(parser_ctx_t *ctx, property_list_t *property_list)
 {
-    property_value_expression_t *ret = parser_alloc(ctx, sizeof(property_value_expression_t));
+    property_value_expression_t *ret = new_expression(ctx, EXPR_PROPVAL, sizeof(*ret));
 
-    ret->expr.eval = property_value_expression_eval;
     ret->property_list = property_list ? property_list->head : NULL;
 
     return &ret->expr;
@@ -4382,9 +4326,8 @@ static expression_t *new_prop_and_value_expression(parser_ctx_t *ctx, property_l
 
 static expression_t *new_literal_expression(parser_ctx_t *ctx, literal_t *literal)
 {
-    literal_expression_t *ret = parser_alloc(ctx, sizeof(literal_expression_t));
+    literal_expression_t *ret = new_expression(ctx, EXPR_LITERAL, sizeof(*ret));
 
-    ret->expr.eval = literal_expression_eval;
     ret->literal = literal;
 
     return &ret->expr;
@@ -4425,32 +4368,8 @@ static statement_list_t *statement_list_add(statement_list_t *list, statement_t
     return list;
 }
 
-static void push_func(parser_ctx_t *ctx)
-{
-    func_stack_t *new_func = parser_alloc_tmp(ctx, sizeof(func_stack_t));
-
-    new_func->func_head = new_func->func_tail = NULL;
-    new_func->var_head = new_func->var_tail = NULL;
-
-    new_func->next = ctx->func_stack;
-    ctx->func_stack = new_func;
-}
-
-static source_elements_t *function_body_parsed(parser_ctx_t *ctx, source_elements_t *source)
-{
-    source->functions = ctx->func_stack->func_head;
-    source->variables = ctx->func_stack->var_head;
-    pop_func(ctx);
-
-    return source;
-}
-
 static void program_parsed(parser_ctx_t *ctx, source_elements_t *source)
 {
-    source->functions = ctx->func_stack->func_head;
-    source->variables = ctx->func_stack->var_head;
-    pop_func(ctx);
-
     ctx->source = source;
     if(!ctx->lexer_error)
         ctx->hres = S_OK;
@@ -4458,20 +4377,16 @@ static void program_parsed(parser_ctx_t *ctx, source_elements_t *source)
 
 void parser_release(parser_ctx_t *ctx)
 {
-    if(--ctx->ref)
-        return;
-
     script_release(ctx->script);
-    heap_free(ctx->begin);
-    jsheap_free(&ctx->heap);
+    heap_pool_free(&ctx->heap);
     heap_free(ctx);
 }
 
-HRESULT script_parse(script_ctx_t *ctx, const WCHAR *code, const WCHAR *delimiter,
+HRESULT script_parse(script_ctx_t *ctx, const WCHAR *code, const WCHAR *delimiter, BOOL from_eval,
         parser_ctx_t **ret)
 {
     parser_ctx_t *parser_ctx;
-    jsheap_t *mark;
+    heap_pool_t *mark;
     HRESULT hres;
 
     const WCHAR html_tagW[] = {'<','/','s','c','r','i','p','t','>',0};
@@ -4480,31 +4395,24 @@ HRESULT script_parse(script_ctx_t *ctx, const WCHAR *code, const WCHAR *delimite
     if(!parser_ctx)
         return E_OUTOFMEMORY;
 
-    parser_ctx->ref = 1;
-    parser_ctx->hres = JSCRIPT_ERROR|IDS_SYNTAX_ERROR;
+    parser_ctx->hres = JS_E_SYNTAX;
     parser_ctx->is_html = delimiter && !strcmpiW(delimiter, html_tagW);
 
-    parser_ctx->begin = heap_strdupW(code);
-    if(!parser_ctx->begin) {
-        heap_free(parser_ctx);
-        return E_OUTOFMEMORY;
-    }
-
-    parser_ctx->ptr = parser_ctx->begin;
+    parser_ctx->begin = parser_ctx->ptr = code;
     parser_ctx->end = parser_ctx->begin + strlenW(parser_ctx->begin);
 
     script_addref(ctx);
     parser_ctx->script = ctx;
 
-    mark = jsheap_mark(&ctx->tmp_heap);
-    jsheap_init(&parser_ctx->heap);
-
-    push_func(parser_ctx);
+    mark = heap_pool_mark(&ctx->tmp_heap);
+    heap_pool_init(&parser_ctx->heap);
 
     parser_parse(parser_ctx);
-    jsheap_clear(mark);
-    if(FAILED(parser_ctx->hres)) {
-        hres = parser_ctx->hres;
+    heap_pool_clear(mark);
+    hres = parser_ctx->hres;
+    if(FAILED(hres)) {
+        WARN("parser failed around %s\n",
+            debugstr_w(parser_ctx->begin+20 > parser_ctx->ptr ? parser_ctx->begin : parser_ctx->ptr-20));
         parser_release(parser_ctx);
         return hres;
     }
index cdc4c1c..07151ac 100644 (file)
      tShiftOper = 295,
      tRelOper = 296,
      tNumericLiteral = 297,
-     tStringLiteral = 298,
-     LOWER_THAN_ELSE = 299
+     tBooleanLiteral = 298,
+     tStringLiteral = 299,
+     tEOF = 300,
+     LOWER_THAN_ELSE = 301
    };
 #endif
 
@@ -91,7 +93,7 @@ typedef union YYSTYPE
 {
 
 /* Line 1676 of yacc.c  */
-#line 150 "parser.y"
+#line 145 "parser.y"
 
     int                     ival;
     const WCHAR             *srcptr;
@@ -115,7 +117,7 @@ typedef union YYSTYPE
 
 
 /* Line 1676 of yacc.c  */
-#line 119 "parser.tab.h"
+#line 121 "parser.tab.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
index f062cd0..f5a2e72 100644 (file)
 #include "jscript.h"
 #include "engine.h"
 
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(jscript);
+
 #define YYLEX_PARAM ctx
 #define YYPARSE_PARAM ctx
 
@@ -29,7 +33,6 @@ static void set_error(parser_ctx_t*,UINT);
 static BOOL explicit_error(parser_ctx_t*,void*,WCHAR);
 static BOOL allow_auto_semicolon(parser_ctx_t*);
 static void program_parsed(parser_ctx_t*,source_elements_t*);
-static source_elements_t *function_body_parsed(parser_ctx_t*,source_elements_t*);
 
 typedef struct _statement_list_t {
     statement_t *head;
@@ -38,7 +41,6 @@ typedef struct _statement_list_t {
 
 static literal_t *new_string_literal(parser_ctx_t*,const WCHAR*);
 static literal_t *new_null_literal(parser_ctx_t*);
-static literal_t *new_boolean_literal(parser_ctx_t*,VARIANT_BOOL);
 
 typedef struct _property_list_t {
     prop_val_t *head;
@@ -84,9 +86,9 @@ static variable_declaration_t *new_variable_declaration(parser_ctx_t*,const WCHA
 static variable_list_t *new_variable_list(parser_ctx_t*,variable_declaration_t*);
 static variable_list_t *variable_list_add(parser_ctx_t*,variable_list_t*,variable_declaration_t*);
 
+static void *new_statement(parser_ctx_t*,statement_type_t,size_t);
 static statement_t *new_block_statement(parser_ctx_t*,statement_list_t*);
 static statement_t *new_var_statement(parser_ctx_t*,variable_list_t*);
-static statement_t *new_empty_statement(parser_ctx_t*);
 static statement_t *new_expression_statement(parser_ctx_t*,expression_t*);
 static statement_t *new_if_statement(parser_ctx_t*,expression_t*,statement_t*,statement_t*);
 static statement_t *new_while_statement(parser_ctx_t*,BOOL,expression_t*,statement_t*);
@@ -118,22 +120,15 @@ typedef struct _parameter_list_t {
 static parameter_list_t *new_parameter_list(parser_ctx_t*,const WCHAR*);
 static parameter_list_t *parameter_list_add(parser_ctx_t*,parameter_list_t*,const WCHAR*);
 
-static void push_func(parser_ctx_t*);
-static inline void pop_func(parser_ctx_t *ctx)
-{
-    ctx->func_stack = ctx->func_stack->next;
-}
-
+static void *new_expression(parser_ctx_t *ctx,expression_type_t,size_t);
 static expression_t *new_function_expression(parser_ctx_t*,const WCHAR*,parameter_list_t*,
         source_elements_t*,const WCHAR*,DWORD);
 static expression_t *new_binary_expression(parser_ctx_t*,expression_type_t,expression_t*,expression_t*);
 static expression_t *new_unary_expression(parser_ctx_t*,expression_type_t,expression_t*);
 static expression_t *new_conditional_expression(parser_ctx_t*,expression_t*,expression_t*,expression_t*);
-static expression_t *new_array_expression(parser_ctx_t*,expression_t*,expression_t*);
 static expression_t *new_member_expression(parser_ctx_t*,expression_t*,const WCHAR*);
 static expression_t *new_new_expression(parser_ctx_t*,expression_t*,argument_list_t*);
 static expression_t *new_call_expression(parser_ctx_t*,expression_t*,argument_list_t*);
-static expression_t *new_this_expression(parser_ctx_t*);
 static expression_t *new_identifier_expression(parser_ctx_t*,const WCHAR*);
 static expression_t *new_literal_expression(parser_ctx_t*,literal_t*);
 static expression_t *new_array_literal_expression(parser_ctx_t*,element_list_t*,int);
@@ -178,8 +173,9 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state
 /* tokens */
 %token <identifier> tIdentifier
 %token <ival> tAssignOper tEqOper tShiftOper tRelOper
-%token <literal> tNumericLiteral
+%token <literal> tNumericLiteral tBooleanLiteral
 %token <wstr> tStringLiteral
+%token tEOF
 
 %type <source_elements> SourceElements
 %type <source_elements> FunctionBody
@@ -253,7 +249,7 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state
 
 /* ECMA-262 3rd Edition    14 */
 Program
-       : SourceElements HtmlComment
+       : SourceElements HtmlComment tEOF
                                 { program_parsed(ctx, $1); }
 
 HtmlComment
@@ -272,11 +268,11 @@ FunctionExpression
                                 { $$ = new_function_expression(ctx, $2, $4, $7, $1, $8-$1+1); }
 
 KFunction
-        : kFUNCTION             { push_func(ctx); $$ = $1; }
+        : kFUNCTION             { $$ = $1; }
 
 /* ECMA-262 3rd Edition    13 */
 FunctionBody
-        : SourceElements        { $$ = function_body_parsed(ctx, $1); }
+        : SourceElements        { $$ = $1; }
 
 /* ECMA-262 3rd Edition    13 */
 FormalParameterList
@@ -294,7 +290,7 @@ Statement
         : Block                 { $$ = $1; }
         | VariableStatement     { $$ = $1; }
         | EmptyStatement        { $$ = $1; }
-        | FunctionExpression    { $$ = new_empty_statement(ctx); } /* FIXME: return NULL */
+        | FunctionExpression    { $$ = new_expression_statement(ctx, $1); }
         | ExpressionStatement   { $$ = $1; }
         | IfStatement           { $$ = $1; }
         | IterationStatement    { $$ = $1; }
@@ -373,7 +369,7 @@ InitialiserNoIn
 
 /* ECMA-262 3rd Edition    12.3 */
 EmptyStatement
-        : ';'                   { $$ = new_empty_statement(ctx); }
+        : ';'                   { $$ = new_statement(ctx, STAT_EMPTY, 0); }
 
 /* ECMA-262 3rd Edition    12.4 */
 ExpressionStatement
@@ -496,7 +492,7 @@ Expression_opt
 
 Expression_err
         : Expression            { $$ = $1; }
-        | error                 { set_error(ctx, IDS_SYNTAX_ERROR); YYABORT; }
+        | error                 { set_error(ctx, JS_E_SYNTAX); YYABORT; }
 
 /* ECMA-262 3rd Edition    11.14 */
 Expression
@@ -710,7 +706,7 @@ MemberExpression
         : PrimaryExpression     { $$ = $1; }
         | FunctionExpression    { $$ = $1; }
         | MemberExpression '[' Expression ']'
-                                { $$ = new_array_expression(ctx, $1, $3); }
+                                { $$ = new_binary_expression(ctx, EXPR_ARRAY, $1, $3); }
         | MemberExpression '.' tIdentifier
                                 { $$ = new_member_expression(ctx, $1, $3); }
         | kNEW MemberExpression Arguments
@@ -723,7 +719,7 @@ CallExpression
         | CallExpression Arguments
                                 { $$ = new_call_expression(ctx, $1, $2); }
         | CallExpression '[' Expression ']'
-                                { $$ = new_array_expression(ctx, $1, $3); }
+                                { $$ = new_binary_expression(ctx, EXPR_ARRAY, $1, $3); }
         | CallExpression '.' tIdentifier
                                 { $$ = new_member_expression(ctx, $1, $3); }
 
@@ -740,7 +736,7 @@ ArgumentList
 
 /* ECMA-262 3rd Edition    11.1 */
 PrimaryExpression
-        : kTHIS                 { $$ = new_this_expression(ctx); }
+        : kTHIS                 { $$ = new_expression(ctx, EXPR_THIS, 0); }
         | tIdentifier           { $$ = new_identifier_expression(ctx, $1); }
         | Literal               { $$ = new_literal_expression(ctx, $1); }
         | ArrayLiteral          { $$ = $1; }
@@ -811,6 +807,7 @@ Literal
 BooleanLiteral
         : kTRUE                 { $$ = new_boolean_literal(ctx, VARIANT_TRUE); }
         | kFALSE                { $$ = new_boolean_literal(ctx, VARIANT_FALSE); }
+        | tBooleanLiteral       { $$ = $1; }
 
 semicolon_opt
         : ';'
@@ -818,15 +815,15 @@ semicolon_opt
 
 left_bracket
         : '('
-        | error                 { set_error(ctx, IDS_LBRACKET); YYABORT; }
+        | error                 { set_error(ctx, JS_E_MISSING_LBRACKET); YYABORT; }
 
 right_bracket
         : ')'
-        | error                 { set_error(ctx, IDS_RBRACKET); YYABORT; }
+        | error                 { set_error(ctx, JS_E_MISSING_RBRACKET); YYABORT; }
 
 semicolon
         : ';'
-        | error                 { set_error(ctx, IDS_SEMICOLON); YYABORT; }
+        | error                 { set_error(ctx, JS_E_MISSING_SEMICOLON); YYABORT; }
 
 %%
 
@@ -835,31 +832,35 @@ static BOOL allow_auto_semicolon(parser_ctx_t *ctx)
     return ctx->nl || ctx->ptr == ctx->end || *(ctx->ptr-1) == '}';
 }
 
-static literal_t *new_string_literal(parser_ctx_t *ctx, const WCHAR *str)
+static void *new_statement(parser_ctx_t *ctx, statement_type_t type, size_t size)
 {
-    literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
+    statement_t *stat;
 
-    ret->type = LT_STRING;
-    ret->u.wstr = str;
+    stat = parser_alloc(ctx, size ? size : sizeof(*stat));
+    if(!stat)
+        return NULL;
 
-    return ret;
+    stat->type = type;
+    stat->next = NULL;
+
+    return stat;
 }
 
-static literal_t *new_null_literal(parser_ctx_t *ctx)
+static literal_t *new_string_literal(parser_ctx_t *ctx, const WCHAR *str)
 {
     literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
 
-    ret->type = LT_NULL;
+    ret->type = LT_STRING;
+    ret->u.wstr = str;
 
     return ret;
 }
 
-static literal_t *new_boolean_literal(parser_ctx_t *ctx, VARIANT_BOOL bval)
+static literal_t *new_null_literal(parser_ctx_t *ctx)
 {
     literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
 
-    ret->type = LT_BOOL;
-    ret->u.bval = bval;
+    ret->type = LT_NULL;
 
     return ret;
 }
@@ -1033,10 +1034,12 @@ static case_clausule_t *new_case_block(parser_ctx_t *ctx, case_list_t *case_list
 
 static statement_t *new_block_statement(parser_ctx_t *ctx, statement_list_t *list)
 {
-    block_statement_t *ret = parser_alloc(ctx, sizeof(block_statement_t));
+    block_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_BLOCK, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = block_statement_eval;
-    ret->stat.next = NULL;
     ret->stat_list = list ? list->head : NULL;
 
     return &ret->stat;
@@ -1045,19 +1048,11 @@ static statement_t *new_block_statement(parser_ctx_t *ctx, statement_list_t *lis
 static variable_declaration_t *new_variable_declaration(parser_ctx_t *ctx, const WCHAR *identifier, expression_t *expr)
 {
     variable_declaration_t *ret = parser_alloc(ctx, sizeof(variable_declaration_t));
-    var_list_t *var_list = parser_alloc(ctx, sizeof(var_list_t));
 
     ret->identifier = identifier;
     ret->expr = expr;
     ret->next = NULL;
-
-    var_list->identifier = identifier;
-    var_list->next = NULL;
-
-    if(ctx->func_stack->var_tail)
-        ctx->func_stack->var_tail = ctx->func_stack->var_tail->next = var_list;
-    else
-        ctx->func_stack->var_head = ctx->func_stack->var_tail = var_list;
+    ret->global_next = NULL;
 
     return ret;
 }
@@ -1080,31 +1075,25 @@ static variable_list_t *variable_list_add(parser_ctx_t *ctx, variable_list_t *li
 
 static statement_t *new_var_statement(parser_ctx_t *ctx, variable_list_t *variable_list)
 {
-    var_statement_t *ret = parser_alloc(ctx, sizeof(var_statement_t));
+    var_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_VAR, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = var_statement_eval;
-    ret->stat.next = NULL;
     ret->variable_list = variable_list->head;
 
     return &ret->stat;
 }
 
-static statement_t *new_empty_statement(parser_ctx_t *ctx)
-{
-    statement_t *ret = parser_alloc(ctx, sizeof(statement_t));
-
-    ret->eval = empty_statement_eval;
-    ret->next = NULL;
-
-    return ret;
-}
-
 static statement_t *new_expression_statement(parser_ctx_t *ctx, expression_t *expr)
 {
-    expression_statement_t *ret = parser_alloc(ctx, sizeof(expression_statement_t));
+    expression_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_EXPR, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = expression_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
 
     return &ret->stat;
@@ -1112,10 +1101,12 @@ static statement_t *new_expression_statement(parser_ctx_t *ctx, expression_t *ex
 
 static statement_t *new_if_statement(parser_ctx_t *ctx, expression_t *expr, statement_t *if_stat, statement_t *else_stat)
 {
-    if_statement_t *ret = parser_alloc(ctx, sizeof(if_statement_t));
+    if_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_IF, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = if_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
     ret->if_stat = if_stat;
     ret->else_stat = else_stat;
@@ -1125,10 +1116,12 @@ static statement_t *new_if_statement(parser_ctx_t *ctx, expression_t *expr, stat
 
 static statement_t *new_while_statement(parser_ctx_t *ctx, BOOL dowhile, expression_t *expr, statement_t *stat)
 {
-    while_statement_t *ret = parser_alloc(ctx, sizeof(while_statement_t));
+    while_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_WHILE, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = while_statement_eval;
-    ret->stat.next = NULL;
     ret->do_while = dowhile;
     ret->expr = expr;
     ret->statement = stat;
@@ -1139,10 +1132,12 @@ static statement_t *new_while_statement(parser_ctx_t *ctx, BOOL dowhile, express
 static statement_t *new_for_statement(parser_ctx_t *ctx, variable_list_t *variable_list, expression_t *begin_expr,
         expression_t *expr, expression_t *end_expr, statement_t *statement)
 {
-    for_statement_t *ret = parser_alloc(ctx, sizeof(for_statement_t));
+    for_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_FOR, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = for_statement_eval;
-    ret->stat.next = NULL;
     ret->variable_list = variable_list ? variable_list->head : NULL;
     ret->begin_expr = begin_expr;
     ret->expr = expr;
@@ -1155,10 +1150,12 @@ static statement_t *new_for_statement(parser_ctx_t *ctx, variable_list_t *variab
 static statement_t *new_forin_statement(parser_ctx_t *ctx, variable_declaration_t *variable, expression_t *expr,
         expression_t *in_expr, statement_t *statement)
 {
-    forin_statement_t *ret = parser_alloc(ctx, sizeof(forin_statement_t));
+    forin_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_FORIN, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = forin_statement_eval;
-    ret->stat.next = NULL;
     ret->variable = variable;
     ret->expr = expr;
     ret->in_expr = in_expr;
@@ -1169,10 +1166,12 @@ static statement_t *new_forin_statement(parser_ctx_t *ctx, variable_declaration_
 
 static statement_t *new_continue_statement(parser_ctx_t *ctx, const WCHAR *identifier)
 {
-    branch_statement_t *ret = parser_alloc(ctx, sizeof(branch_statement_t));
+    branch_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_CONTINUE, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = continue_statement_eval;
-    ret->stat.next = NULL;
     ret->identifier = identifier;
 
     return &ret->stat;
@@ -1180,10 +1179,12 @@ static statement_t *new_continue_statement(parser_ctx_t *ctx, const WCHAR *ident
 
 static statement_t *new_break_statement(parser_ctx_t *ctx, const WCHAR *identifier)
 {
-    branch_statement_t *ret = parser_alloc(ctx, sizeof(branch_statement_t));
+    branch_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_BREAK, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = break_statement_eval;
-    ret->stat.next = NULL;
     ret->identifier = identifier;
 
     return &ret->stat;
@@ -1191,10 +1192,12 @@ static statement_t *new_break_statement(parser_ctx_t *ctx, const WCHAR *identifi
 
 static statement_t *new_return_statement(parser_ctx_t *ctx, expression_t *expr)
 {
-    expression_statement_t *ret = parser_alloc(ctx, sizeof(expression_statement_t));
+    expression_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_RETURN, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = return_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
 
     return &ret->stat;
@@ -1202,10 +1205,12 @@ static statement_t *new_return_statement(parser_ctx_t *ctx, expression_t *expr)
 
 static statement_t *new_with_statement(parser_ctx_t *ctx, expression_t *expr, statement_t *statement)
 {
-    with_statement_t *ret = parser_alloc(ctx, sizeof(with_statement_t));
+    with_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_WITH, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = with_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
     ret->statement = statement;
 
@@ -1214,10 +1219,12 @@ static statement_t *new_with_statement(parser_ctx_t *ctx, expression_t *expr, st
 
 static statement_t *new_labelled_statement(parser_ctx_t *ctx, const WCHAR *identifier, statement_t *statement)
 {
-    labelled_statement_t *ret = parser_alloc(ctx, sizeof(labelled_statement_t));
+    labelled_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_LABEL, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = labelled_statement_eval;
-    ret->stat.next = NULL;
     ret->identifier = identifier;
     ret->statement = statement;
 
@@ -1226,10 +1233,12 @@ static statement_t *new_labelled_statement(parser_ctx_t *ctx, const WCHAR *ident
 
 static statement_t *new_switch_statement(parser_ctx_t *ctx, expression_t *expr, case_clausule_t *case_list)
 {
-    switch_statement_t *ret = parser_alloc(ctx, sizeof(switch_statement_t));
+    switch_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_SWITCH, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = switch_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
     ret->case_list = case_list;
 
@@ -1238,10 +1247,12 @@ static statement_t *new_switch_statement(parser_ctx_t *ctx, expression_t *expr,
 
 static statement_t *new_throw_statement(parser_ctx_t *ctx, expression_t *expr)
 {
-    expression_statement_t *ret = parser_alloc(ctx, sizeof(expression_statement_t));
+    expression_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_THROW, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = throw_statement_eval;
-    ret->stat.next = NULL;
     ret->expr = expr;
 
     return &ret->stat;
@@ -1250,10 +1261,12 @@ static statement_t *new_throw_statement(parser_ctx_t *ctx, expression_t *expr)
 static statement_t *new_try_statement(parser_ctx_t *ctx, statement_t *try_statement,
        catch_block_t *catch_block, statement_t *finally_statement)
 {
-    try_statement_t *ret = parser_alloc(ctx, sizeof(try_statement_t));
+    try_statement_t *ret;
+
+    ret = new_statement(ctx, STAT_TRY, sizeof(*ret));
+    if(!ret)
+        return NULL;
 
-    ret->stat.eval = try_statement_eval;
-    ret->stat.next = NULL;
     ret->try_statement = try_statement;
     ret->catch_block = catch_block;
     ret->finally_statement = finally_statement;
@@ -1290,86 +1303,32 @@ static parameter_list_t *parameter_list_add(parser_ctx_t *ctx, parameter_list_t
 static expression_t *new_function_expression(parser_ctx_t *ctx, const WCHAR *identifier,
        parameter_list_t *parameter_list, source_elements_t *source_elements, const WCHAR *src_str, DWORD src_len)
 {
-    function_expression_t *ret = parser_alloc(ctx, sizeof(function_expression_t));
+    function_expression_t *ret = new_expression(ctx, EXPR_FUNC, sizeof(*ret));
 
-    ret->expr.eval = function_expression_eval;
     ret->identifier = identifier;
     ret->parameter_list = parameter_list ? parameter_list->head : NULL;
     ret->source_elements = source_elements;
     ret->src_str = src_str;
     ret->src_len = src_len;
+    ret->next = NULL;
 
-    if(ret->identifier) {
-        function_declaration_t *decl = parser_alloc(ctx, sizeof(function_declaration_t));
+    return &ret->expr;
+}
 
-        decl->expr = ret;
-        decl->next = NULL;
+static void *new_expression(parser_ctx_t *ctx, expression_type_t type, size_t size)
+{
+    expression_t *ret = parser_alloc(ctx, size ? size : sizeof(*ret));
 
-        if(ctx->func_stack->func_tail)
-            ctx->func_stack->func_tail = ctx->func_stack->func_tail->next = decl;
-        else
-            ctx->func_stack->func_head = ctx->func_stack->func_tail = decl;
-    }
+    ret->type = type;
 
-    return &ret->expr;
+    return ret;
 }
 
-static const expression_eval_t expression_eval_table[] = {
-   comma_expression_eval,
-   logical_or_expression_eval,
-   logical_and_expression_eval,
-   binary_or_expression_eval,
-   binary_xor_expression_eval,
-   binary_and_expression_eval,
-   instanceof_expression_eval,
-   in_expression_eval,
-   add_expression_eval,
-   sub_expression_eval,
-   mul_expression_eval,
-   div_expression_eval,
-   mod_expression_eval,
-   delete_expression_eval,
-   void_expression_eval,
-   typeof_expression_eval,
-   minus_expression_eval,
-   plus_expression_eval,
-   post_increment_expression_eval,
-   post_decrement_expression_eval,
-   pre_increment_expression_eval,
-   pre_decrement_expression_eval,
-   equal_expression_eval,
-   equal2_expression_eval,
-   not_equal_expression_eval,
-   not_equal2_expression_eval,
-   less_expression_eval,
-   lesseq_expression_eval,
-   greater_expression_eval,
-   greatereq_expression_eval,
-   binary_negation_expression_eval,
-   logical_negation_expression_eval,
-   left_shift_expression_eval,
-   right_shift_expression_eval,
-   right2_shift_expression_eval,
-   assign_expression_eval,
-   assign_lshift_expression_eval,
-   assign_rshift_expression_eval,
-   assign_rrshift_expression_eval,
-   assign_add_expression_eval,
-   assign_sub_expression_eval,
-   assign_mul_expression_eval,
-   assign_div_expression_eval,
-   assign_mod_expression_eval,
-   assign_and_expression_eval,
-   assign_or_expression_eval,
-   assign_xor_expression_eval,
-};
-
 static expression_t *new_binary_expression(parser_ctx_t *ctx, expression_type_t type,
        expression_t *expression1, expression_t *expression2)
 {
-    binary_expression_t *ret = parser_alloc(ctx, sizeof(binary_expression_t));
+    binary_expression_t *ret = new_expression(ctx, type, sizeof(*ret));
 
-    ret->expr.eval = expression_eval_table[type];
     ret->expression1 = expression1;
     ret->expression2 = expression2;
 
@@ -1378,9 +1337,8 @@ static expression_t *new_binary_expression(parser_ctx_t *ctx, expression_type_t
 
 static expression_t *new_unary_expression(parser_ctx_t *ctx, expression_type_t type, expression_t *expression)
 {
-    unary_expression_t *ret = parser_alloc(ctx, sizeof(unary_expression_t));
+    unary_expression_t *ret = new_expression(ctx, type, sizeof(*ret));
 
-    ret->expr.eval = expression_eval_table[type];
     ret->expression = expression;
 
     return &ret->expr;
@@ -1389,9 +1347,8 @@ static expression_t *new_unary_expression(parser_ctx_t *ctx, expression_type_t t
 static expression_t *new_conditional_expression(parser_ctx_t *ctx, expression_t *expression,
        expression_t *true_expression, expression_t *false_expression)
 {
-    conditional_expression_t *ret = parser_alloc(ctx, sizeof(conditional_expression_t));
+    conditional_expression_t *ret = new_expression(ctx, EXPR_COND, sizeof(*ret));
 
-    ret->expr.eval = conditional_expression_eval;
     ret->expression = expression;
     ret->true_expression = true_expression;
     ret->false_expression = false_expression;
@@ -1399,22 +1356,10 @@ static expression_t *new_conditional_expression(parser_ctx_t *ctx, expression_t
     return &ret->expr;
 }
 
-static expression_t *new_array_expression(parser_ctx_t *ctx, expression_t *member_expr, expression_t *expression)
-{
-    array_expression_t *ret = parser_alloc(ctx, sizeof(array_expression_t));
-
-    ret->expr.eval = array_expression_eval;
-    ret->member_expr = member_expr;
-    ret->expression = expression;
-
-    return &ret->expr;
-}
-
 static expression_t *new_member_expression(parser_ctx_t *ctx, expression_t *expression, const WCHAR *identifier)
 {
-    member_expression_t *ret = parser_alloc(ctx, sizeof(member_expression_t));
+    member_expression_t *ret = new_expression(ctx, EXPR_MEMBER, sizeof(*ret));
 
-    ret->expr.eval = member_expression_eval;
     ret->expression = expression;
     ret->identifier = identifier;
 
@@ -1423,9 +1368,8 @@ static expression_t *new_member_expression(parser_ctx_t *ctx, expression_t *expr
 
 static expression_t *new_new_expression(parser_ctx_t *ctx, expression_t *expression, argument_list_t *argument_list)
 {
-    call_expression_t *ret = parser_alloc(ctx, sizeof(call_expression_t));
+    call_expression_t *ret = new_expression(ctx, EXPR_NEW, sizeof(*ret));
 
-    ret->expr.eval = new_expression_eval;
     ret->expression = expression;
     ret->argument_list = argument_list ? argument_list->head : NULL;
 
@@ -1434,24 +1378,14 @@ static expression_t *new_new_expression(parser_ctx_t *ctx, expression_t *express
 
 static expression_t *new_call_expression(parser_ctx_t *ctx, expression_t *expression, argument_list_t *argument_list)
 {
-    call_expression_t *ret = parser_alloc(ctx, sizeof(call_expression_t));
+    call_expression_t *ret = new_expression(ctx, EXPR_CALL, sizeof(*ret));
 
-    ret->expr.eval = call_expression_eval;
     ret->expression = expression;
     ret->argument_list = argument_list ? argument_list->head : NULL;
 
     return &ret->expr;
 }
 
-static expression_t *new_this_expression(parser_ctx_t *ctx)
-{
-    expression_t *ret = parser_alloc(ctx, sizeof(expression_t));
-
-    ret->eval = this_expression_eval;
-
-    return ret;
-}
-
 static int parser_error(const char *str)
 {
     return 0;
@@ -1459,23 +1393,22 @@ static int parser_error(const char *str)
 
 static void set_error(parser_ctx_t *ctx, UINT error)
 {
-    ctx->hres = JSCRIPT_ERROR|error;
+    ctx->hres = error;
 }
 
 static BOOL explicit_error(parser_ctx_t *ctx, void *obj, WCHAR next)
 {
     if(obj || *(ctx->ptr-1)==next) return TRUE;
 
-    set_error(ctx, IDS_SYNTAX_ERROR);
+    set_error(ctx, JS_E_SYNTAX);
     return FALSE;
 }
 
 
 static expression_t *new_identifier_expression(parser_ctx_t *ctx, const WCHAR *identifier)
 {
-    identifier_expression_t *ret = parser_alloc(ctx, sizeof(identifier_expression_t));
+    identifier_expression_t *ret = new_expression(ctx, EXPR_IDENT, sizeof(*ret));
 
-    ret->expr.eval = identifier_expression_eval;
     ret->identifier = identifier;
 
     return &ret->expr;
@@ -1483,9 +1416,8 @@ static expression_t *new_identifier_expression(parser_ctx_t *ctx, const WCHAR *i
 
 static expression_t *new_array_literal_expression(parser_ctx_t *ctx, element_list_t *element_list, int length)
 {
-    array_literal_expression_t *ret = parser_alloc(ctx, sizeof(array_literal_expression_t));
+    array_literal_expression_t *ret = new_expression(ctx, EXPR_ARRAYLIT, sizeof(*ret));
 
-    ret->expr.eval = array_literal_expression_eval;
     ret->element_list = element_list ? element_list->head : NULL;
     ret->length = length;
 
@@ -1494,9 +1426,8 @@ static expression_t *new_array_literal_expression(parser_ctx_t *ctx, element_lis
 
 static expression_t *new_prop_and_value_expression(parser_ctx_t *ctx, property_list_t *property_list)
 {
-    property_value_expression_t *ret = parser_alloc(ctx, sizeof(property_value_expression_t));
+    property_value_expression_t *ret = new_expression(ctx, EXPR_PROPVAL, sizeof(*ret));
 
-    ret->expr.eval = property_value_expression_eval;
     ret->property_list = property_list ? property_list->head : NULL;
 
     return &ret->expr;
@@ -1504,9 +1435,8 @@ static expression_t *new_prop_and_value_expression(parser_ctx_t *ctx, property_l
 
 static expression_t *new_literal_expression(parser_ctx_t *ctx, literal_t *literal)
 {
-    literal_expression_t *ret = parser_alloc(ctx, sizeof(literal_expression_t));
+    literal_expression_t *ret = new_expression(ctx, EXPR_LITERAL, sizeof(*ret));
 
-    ret->expr.eval = literal_expression_eval;
     ret->literal = literal;
 
     return &ret->expr;
@@ -1547,32 +1477,8 @@ static statement_list_t *statement_list_add(statement_list_t *list, statement_t
     return list;
 }
 
-static void push_func(parser_ctx_t *ctx)
-{
-    func_stack_t *new_func = parser_alloc_tmp(ctx, sizeof(func_stack_t));
-
-    new_func->func_head = new_func->func_tail = NULL;
-    new_func->var_head = new_func->var_tail = NULL;
-
-    new_func->next = ctx->func_stack;
-    ctx->func_stack = new_func;
-}
-
-static source_elements_t *function_body_parsed(parser_ctx_t *ctx, source_elements_t *source)
-{
-    source->functions = ctx->func_stack->func_head;
-    source->variables = ctx->func_stack->var_head;
-    pop_func(ctx);
-
-    return source;
-}
-
 static void program_parsed(parser_ctx_t *ctx, source_elements_t *source)
 {
-    source->functions = ctx->func_stack->func_head;
-    source->variables = ctx->func_stack->var_head;
-    pop_func(ctx);
-
     ctx->source = source;
     if(!ctx->lexer_error)
         ctx->hres = S_OK;
@@ -1580,20 +1486,16 @@ static void program_parsed(parser_ctx_t *ctx, source_elements_t *source)
 
 void parser_release(parser_ctx_t *ctx)
 {
-    if(--ctx->ref)
-        return;
-
     script_release(ctx->script);
-    heap_free(ctx->begin);
-    jsheap_free(&ctx->heap);
+    heap_pool_free(&ctx->heap);
     heap_free(ctx);
 }
 
-HRESULT script_parse(script_ctx_t *ctx, const WCHAR *code, const WCHAR *delimiter,
+HRESULT script_parse(script_ctx_t *ctx, const WCHAR *code, const WCHAR *delimiter, BOOL from_eval,
         parser_ctx_t **ret)
 {
     parser_ctx_t *parser_ctx;
-    jsheap_t *mark;
+    heap_pool_t *mark;
     HRESULT hres;
 
     const WCHAR html_tagW[] = {'<','/','s','c','r','i','p','t','>',0};
@@ -1602,31 +1504,24 @@ HRESULT script_parse(script_ctx_t *ctx, const WCHAR *code, const WCHAR *delimite
     if(!parser_ctx)
         return E_OUTOFMEMORY;
 
-    parser_ctx->ref = 1;
-    parser_ctx->hres = JSCRIPT_ERROR|IDS_SYNTAX_ERROR;
+    parser_ctx->hres = JS_E_SYNTAX;
     parser_ctx->is_html = delimiter && !strcmpiW(delimiter, html_tagW);
 
-    parser_ctx->begin = heap_strdupW(code);
-    if(!parser_ctx->begin) {
-        heap_free(parser_ctx);
-        return E_OUTOFMEMORY;
-    }
-
-    parser_ctx->ptr = parser_ctx->begin;
+    parser_ctx->begin = parser_ctx->ptr = code;
     parser_ctx->end = parser_ctx->begin + strlenW(parser_ctx->begin);
 
     script_addref(ctx);
     parser_ctx->script = ctx;
 
-    mark = jsheap_mark(&ctx->tmp_heap);
-    jsheap_init(&parser_ctx->heap);
-
-    push_func(parser_ctx);
+    mark = heap_pool_mark(&ctx->tmp_heap);
+    heap_pool_init(&parser_ctx->heap);
 
     parser_parse(parser_ctx);
-    jsheap_clear(mark);
-    if(FAILED(parser_ctx->hres)) {
-        hres = parser_ctx->hres;
+    heap_pool_clear(mark);
+    hres = parser_ctx->hres;
+    if(FAILED(hres)) {
+        WARN("parser failed around %s\n",
+            debugstr_w(parser_ctx->begin+20 > parser_ctx->ptr ? parser_ctx->begin : parser_ctx->ptr-20));
         parser_release(parser_ctx);
         return hres;
     }
index 4d0544c..6b0fc4b 100644 (file)
  */
 
 #include <assert.h>
-#include <math.h>
 
 #include "jscript.h"
+#include "regexp.h"
 
 #include <wine/debug.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 
-#define JSREG_FOLD      0x01    /* fold uppercase to lowercase */
-#define JSREG_GLOB      0x02    /* global exec, creates array of matches */
-#define JSREG_MULTILINE 0x04    /* treat ^ and $ as begin and end of line */
-#define JSREG_STICKY    0x08    /* only match starting at lastIndex */
+/* FIXME: Better error handling */
+#define ReportRegExpError(a,b,c)
+#define ReportRegExpErrorHelper(a,b,c,d)
+#define JS_ReportErrorNumber(a,b,c,d)
+#define JS_ReportErrorFlagsAndNumber(a,b,c,d,e,f)
+#define js_ReportOutOfScriptQuota(a)
+#define JS_ReportOutOfMemory(a)
+#define JS_COUNT_OPERATION(a,b)
+
 
 typedef BYTE JSPackedBool;
-typedef BYTE jsbytecode;
 
 /*
  * This struct holds a bitmap representation of a class from a regexp.
- * There's a list of these referenced by the classList field in the JSRegExp
+ * There's a list of these referenced by the classList field in the regexp_t
  * struct below. The initial state has startIndex set to the offset in the
  * original regexp source of the beginning of the class contents. The first
  * use of the class converts the source representation into a bitmap.
@@ -69,50 +73,6 @@ typedef struct RECharSet {
     } u;
 } RECharSet;
 
-typedef struct {
-    WORD         flags;         /* flags, see jsapi.h's JSREG_* defines */
-    size_t       parenCount;    /* number of parenthesized submatches */
-    size_t       classCount;    /* count [...] bitmaps */
-    RECharSet    *classList;    /* list of [...] bitmaps */
-    BSTR         source;        /* locked source string, sans // */
-    jsbytecode   program[1];    /* regular expression bytecode */
-} JSRegExp;
-
-typedef struct {
-    DispatchEx dispex;
-
-    JSRegExp *jsregexp;
-    BSTR str;
-    INT last_index;
-    VARIANT last_index_var;
-} RegExpInstance;
-
-static const WCHAR sourceW[] = {'s','o','u','r','c','e',0};
-static const WCHAR globalW[] = {'g','l','o','b','a','l',0};
-static const WCHAR ignoreCaseW[] = {'i','g','n','o','r','e','C','a','s','e',0};
-static const WCHAR multilineW[] = {'m','u','l','t','i','l','i','n','e',0};
-static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
-static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
-static const WCHAR execW[] = {'e','x','e','c',0};
-static const WCHAR testW[] = {'t','e','s','t',0};
-
-static const WCHAR leftContextW[] =
-    {'l','e','f','t','C','o','n','t','e','x','t',0};
-static const WCHAR rightContextW[] =
-    {'r','i','g','h','t','C','o','n','t','e','x','t',0};
-
-static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
-static const WCHAR emptyW[] = {0};
-
-/* FIXME: Better error handling */
-#define ReportRegExpError(a,b,c)
-#define ReportRegExpErrorHelper(a,b,c,d)
-#define JS_ReportErrorNumber(a,b,c,d)
-#define JS_ReportErrorFlagsAndNumber(a,b,c,d,e,f)
-#define js_ReportOutOfScriptQuota(a)
-#define JS_ReportOutOfMemory(a)
-#define JS_COUNT_OPERATION(a,b)
-
 #define JSMSG_MIN_TOO_BIG 47
 #define JSMSG_MAX_TOO_BIG 48
 #define JSMSG_OUT_OF_ORDER 49
@@ -239,17 +199,6 @@ static const char *reop_names[] = {
     NULL
 };
 
-typedef struct RECapture {
-    ptrdiff_t index;           /* start of contents, -1 for empty  */
-    size_t length;             /* length of capture */
-} RECapture;
-
-typedef struct REMatchState {
-    const WCHAR *cp;
-    RECapture parens[1];      /* first of 're->parenCount' captures,
-                                 allocated at end of this struct */
-} REMatchState;
-
 typedef struct REProgState {
     jsbytecode *continue_pc;        /* current continuation data */
     jsbytecode continue_op;
@@ -283,8 +232,8 @@ typedef struct REBackTrackData {
 #define INITIAL_BACKTRACK   8000
 
 typedef struct REGlobalData {
-    script_ctx_t *cx;
-    JSRegExp *regexp;               /* the RE in execution */
+    void *cx;
+    regexp_t *regexp;               /* the RE in execution */
     BOOL ok;                        /* runtime error (out_of_memory only?) */
     size_t start;                   /* offset to start at */
     ptrdiff_t skipped;              /* chars skipped anchoring this r.e. */
@@ -302,7 +251,7 @@ typedef struct REGlobalData {
     size_t backTrackCount;          /* how many times we've backtracked */
     size_t backTrackLimit;          /* upper limit on backtrack states */
 
-    jsheap_t *pool;                 /* It's faster to use one malloc'd pool
+    heap_pool_t *pool;              /* It's faster to use one malloc'd pool
                                        than to malloc/free the three items
                                        that are allocated from this pool */
 } REGlobalData;
@@ -343,7 +292,7 @@ struct RENode {
 #define CLASS_CACHE_SIZE    4
 
 typedef struct CompilerState {
-    script_ctx_t    *context;
+    void            *context;
     const WCHAR     *cpbegin;
     const WCHAR     *cpend;
     const WCHAR     *cp;
@@ -359,6 +308,9 @@ typedef struct CompilerState {
         size_t index;
     } classCache[CLASS_CACHE_SIZE];
     WORD          flags;
+
+    heap_pool_t *pool;              /* It's faster to use one malloc'd pool
+                                       than to malloc/free */
 } CompilerState;
 
 typedef struct EmitStateStackEntry {
@@ -458,7 +410,7 @@ NewRENode(CompilerState *state, REOp op)
 {
     RENode *ren;
 
-    ren = jsheap_alloc(&state->context->tmp_heap, sizeof(*ren));
+    ren = heap_pool_alloc(state->pool, sizeof(*ren));
     if (!ren) {
         /* js_ReportOutOfScriptQuota(cx); */
         return NULL;
@@ -520,7 +472,7 @@ SetForwardJumpOffset(jsbytecode *jump, jsbytecode *target)
  * of recursion.
  */
 static jsbytecode *
-EmitREBytecode(CompilerState *state, JSRegExp *re, size_t treeDepth,
+EmitREBytecode(CompilerState *state, regexp_t *re, size_t treeDepth,
                jsbytecode *pc, RENode *t)
 {
     EmitStateStackEntry *emitStateSP, *emitStateStack;
@@ -710,14 +662,14 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, size_t treeDepth,
                 }
             }
             if (t->kid && t->u.flat.length > 1) {
-                pc[-1] = (state->flags & JSREG_FOLD) ? REOP_FLATi : REOP_FLAT;
+                pc[-1] = (state->flags & REG_FOLD) ? REOP_FLATi : REOP_FLAT;
                 pc = WriteCompactIndex(pc, (WCHAR*)t->kid - state->cpbegin);
                 pc = WriteCompactIndex(pc, t->u.flat.length);
             } else if (t->u.flat.chr < 256) {
-                pc[-1] = (state->flags & JSREG_FOLD) ? REOP_FLAT1i : REOP_FLAT1;
+                pc[-1] = (state->flags & REG_FOLD) ? REOP_FLAT1i : REOP_FLAT1;
                 *pc++ = (jsbytecode) t->u.flat.chr;
             } else {
-                pc[-1] = (state->flags & JSREG_FOLD)
+                pc[-1] = (state->flags & REG_FOLD)
                          ? REOP_UCFLAT1i
                          : REOP_UCFLAT1;
                 SET_ARG(pc, t->u.flat.chr);
@@ -876,7 +828,7 @@ ProcessOp(CompilerState *state, REOpData *opData, RENode **operandStack,
          */
         if (((RENode *) result->kid)->op == REOP_FLAT &&
             ((RENode *) result->u.kid2)->op == REOP_FLAT &&
-            (state->flags & JSREG_FOLD) == 0) {
+            (state->flags & REG_FOLD) == 0) {
             result->op = REOP_ALTPREREQ;
             result->u.altprereq.ch1 = ((RENode *) result->kid)->u.flat.chr;
             result->u.altprereq.ch2 = ((RENode *) result->u.kid2)->u.flat.chr;
@@ -888,7 +840,7 @@ ProcessOp(CompilerState *state, REOpData *opData, RENode **operandStack,
         if (((RENode *) result->kid)->op == REOP_CLASS &&
             ((RENode *) result->kid)->u.ucclass.index < 256 &&
             ((RENode *) result->u.kid2)->op == REOP_FLAT &&
-            (state->flags & JSREG_FOLD) == 0) {
+            (state->flags & REG_FOLD) == 0) {
             result->op = REOP_ALTPREREQ2;
             result->u.altprereq.ch1 = ((RENode *) result->u.kid2)->u.flat.chr;
             result->u.altprereq.ch2 = ((RENode *) result->kid)->u.ucclass.index;
@@ -900,7 +852,7 @@ ProcessOp(CompilerState *state, REOpData *opData, RENode **operandStack,
         if (((RENode *) result->kid)->op == REOP_FLAT &&
             ((RENode *) result->u.kid2)->op == REOP_CLASS &&
             ((RENode *) result->u.kid2)->u.ucclass.index < 256 &&
-            (state->flags & JSREG_FOLD) == 0) {
+            (state->flags & REG_FOLD) == 0) {
             result->op = REOP_ALTPREREQ2;
             result->u.altprereq.ch1 = ((RENode *) result->kid)->u.flat.chr;
             result->u.altprereq.ch2 =
@@ -1180,11 +1132,11 @@ lexHex:
                     continue;
                 }
             }
-            if (state->flags & JSREG_FOLD)
+            if (state->flags & REG_FOLD)
                 rangeStart = localMax;   /* one run of the uc/dc loop below */
         }
 
-        if (state->flags & JSREG_FOLD) {
+        if (state->flags & REG_FOLD) {
             WCHAR maxch = localMax;
 
             for (i = rangeStart; i <= localMax; i++) {
@@ -1968,7 +1920,7 @@ out:
  */
 static REBackTrackData *
 PushBackTrackState(REGlobalData *gData, REOp op,
-                   jsbytecode *target, REMatchState *x, const WCHAR *cp,
+                   jsbytecode *target, match_state_t *x, const WCHAR *cp,
                    size_t parenIndex, size_t parenCount)
 {
     size_t i;
@@ -1991,7 +1943,7 @@ PushBackTrackState(REGlobalData *gData, REOp op,
 
         JS_COUNT_OPERATION(gData->cx, JSOW_ALLOCATION);
         btincr = ((btincr+btsize-1)/btsize)*btsize;
-        gData->backTrackStack = jsheap_grow(gData->pool, gData->backTrackStack, btsize, btincr);
+        gData->backTrackStack = heap_pool_grow(gData->pool, gData->backTrackStack, btsize, btincr);
         if (!gData->backTrackStack) {
             js_ReportOutOfScriptQuota(gData->cx);
             gData->ok = FALSE;
@@ -2027,8 +1979,8 @@ PushBackTrackState(REGlobalData *gData, REOp op,
     return result;
 }
 
-static inline REMatchState *
-FlatNIMatcher(REGlobalData *gData, REMatchState *x, WCHAR *matchChars,
+static inline match_state_t *
+FlatNIMatcher(REGlobalData *gData, match_state_t *x, const WCHAR *matchChars,
               size_t length)
 {
     size_t i;
@@ -2066,8 +2018,8 @@ FlatNIMatcher(REGlobalData *gData, REMatchState *x, WCHAR *matchChars,
  *     9. Let y be the State (f, cap).
  *     10. Call c(y) and return its result.
  */
-static REMatchState *
-BackrefMatcher(REGlobalData *gData, REMatchState *x, size_t parenIndex)
+static match_state_t *
+BackrefMatcher(REGlobalData *gData, match_state_t *x, size_t parenIndex)
 {
     size_t len, i;
     const WCHAR *parenContent;
@@ -2081,7 +2033,7 @@ BackrefMatcher(REGlobalData *gData, REMatchState *x, size_t parenIndex)
         return NULL;
 
     parenContent = &gData->cpbegin[cap->index];
-    if (gData->regexp->flags & JSREG_FOLD) {
+    if (gData->regexp->flags & REG_FOLD) {
         for (i = 0; i < len; i++) {
             if (toupperW(parenContent[i]) != toupperW(x->cp[i]))
                 return NULL;
@@ -2147,10 +2099,9 @@ ProcessCharSet(REGlobalData *gData, RECharSet *charSet)
      * source string.
      */
     assert(1 <= charSet->u.src.startIndex);
-    assert(charSet->u.src.startIndex
-              < SysStringLen(gData->regexp->source));
-    assert(charSet->u.src.length <= SysStringLen(gData->regexp->source)
-                                       - 1 - charSet->u.src.startIndex);
+    assert(charSet->u.src.startIndex < gData->regexp->source_len);
+    assert(charSet->u.src.length <= gData->regexp->source_len
+            - 1 - charSet->u.src.startIndex);
 
     charSet->converted = TRUE;
     src = gData->regexp->source + charSet->u.src.startIndex;
@@ -2306,9 +2257,7 @@ ProcessCharSet(REGlobalData *gData, RECharSet *charSet)
 
         }
         if (inRange) {
-            if (gData->regexp->flags & JSREG_FOLD) {
-                int i;
-
+            if (gData->regexp->flags & REG_FOLD) {
                 assert(rangeStart <= thisCh);
                 for (i = rangeStart; i <= thisCh; i++) {
                     WCHAR uch, dch;
@@ -2326,7 +2275,7 @@ ProcessCharSet(REGlobalData *gData, RECharSet *charSet)
             }
             inRange = FALSE;
         } else {
-            if (gData->regexp->flags & JSREG_FOLD) {
+            if (gData->regexp->flags & REG_FOLD) {
                 AddCharacterToCharSet(charSet, toupperW(thisCh));
                 AddCharacterToCharSet(charSet, tolowerW(thisCh));
             } else {
@@ -2350,7 +2299,7 @@ ReallocStateStack(REGlobalData *gData)
     size_t limit = gData->stateStackLimit;
     size_t sz = sizeof(REProgState) * limit;
 
-    gData->stateStack = jsheap_grow(gData->pool, gData->stateStack, sz, sz);
+    gData->stateStack = heap_pool_grow(gData->pool, gData->stateStack, sz, sz);
     if (!gData->stateStack) {
         js_ReportOutOfScriptQuota(gData->cx);
         gData->ok = FALSE;
@@ -2375,16 +2324,16 @@ ReallocStateStack(REGlobalData *gData)
  * true, then update the current state's cp. Always update startpc to the next
  * op.
  */
-static inline REMatchState *
-SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
+static inline match_state_t *
+SimpleMatch(REGlobalData *gData, match_state_t *x, REOp op,
             jsbytecode **startpc, BOOL updatecp)
 {
-    REMatchState *result = NULL;
+    match_state_t *result = NULL;
     WCHAR matchCh;
     size_t parenIndex;
     size_t offset, length, index;
     jsbytecode *pc = *startpc;  /* pc has already been incremented past op */
-    WCHAR *source;
+    const WCHAR *source;
     const WCHAR *startcp = x->cp;
     WCHAR ch;
     RECharSet *charSet;
@@ -2400,7 +2349,7 @@ SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
       case REOP_BOL:
         if (x->cp != gData->cpbegin) {
             if (/*!gData->cx->regExpStatics.multiline &&  FIXME !!! */
-                !(gData->regexp->flags & JSREG_MULTILINE)) {
+                !(gData->regexp->flags & REG_MULTILINE)) {
                 break;
             }
             if (!RE_IS_LINE_TERM(x->cp[-1]))
@@ -2411,7 +2360,7 @@ SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
       case REOP_EOL:
         if (x->cp != gData->cpend) {
             if (/*!gData->cx->regExpStatics.multiline &&*/
-                !(gData->regexp->flags & JSREG_MULTILINE)) {
+                !(gData->regexp->flags & REG_MULTILINE)) {
                 break;
             }
             if (!RE_IS_LINE_TERM(*x->cp))
@@ -2480,10 +2429,10 @@ SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
         break;
       case REOP_FLAT:
         pc = ReadCompactIndex(pc, &offset);
-        assert(offset < SysStringLen(gData->regexp->source));
+        assert(offset < gData->regexp->source_len);
         pc = ReadCompactIndex(pc, &length);
         assert(1 <= length);
-        assert(length <= SysStringLen(gData->regexp->source) - offset);
+        assert(length <= gData->regexp->source_len - offset);
         if (length <= (size_t)(gData->cpend - x->cp)) {
             source = gData->regexp->source + offset;
             TRACE("%s\n", debugstr_wn(source, length));
@@ -2505,10 +2454,10 @@ SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
         break;
       case REOP_FLATi:
         pc = ReadCompactIndex(pc, &offset);
-        assert(offset < SysStringLen(gData->regexp->source));
+        assert(offset < gData->regexp->source_len);
         pc = ReadCompactIndex(pc, &length);
         assert(1 <= length);
-        assert(length <= SysStringLen(gData->regexp->source) - offset);
+        assert(length <= gData->regexp->source_len - offset);
         source = gData->regexp->source;
         result = FlatNIMatcher(gData, x, source + offset, length);
         break;
@@ -2583,10 +2532,10 @@ SimpleMatch(REGlobalData *gData, REMatchState *x, REOp op,
     return NULL;
 }
 
-static inline REMatchState *
-ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
+static inline match_state_t *
+ExecuteREBytecode(REGlobalData *gData, match_state_t *x)
 {
-    REMatchState *result = NULL;
+    match_state_t *result = NULL;
     REBackTrackData *backTrackData;
     jsbytecode *nextpc, *testpc;
     REOp nextop;
@@ -2607,7 +2556,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
      * If the first node is a simple match, step the index into the string
      * until that match is made, or fail if it can't be found at all.
      */
-    if (REOP_IS_SIMPLE(op) && !(gData->regexp->flags & JSREG_STICKY)) {
+    if (REOP_IS_SIMPLE(op) && !(gData->regexp->flags & REG_STICKY)) {
         anchor = FALSE;
         while (x->cp <= gData->cpend) {
             nextpc = pc;    /* reset back to start each time */
@@ -2678,7 +2627,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
                     result = NULL;
                     break;
                 }
-                /* else false thru... */
+                /* else fall through... */
 
               case REOP_ALT:
               doAlt:
@@ -2994,7 +2943,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x)
                 TRACE("{%d,%d}\n", curState->u.quantifier.min, curState->u.quantifier.max);
 #define PREPARE_REPEAT()                                                      \
     do {                                                                      \
-        curState->index = x->cp - gData->cpbegin;                             \
+        curState->index = x->cp - gData->cpbegin;                          \
         curState->continue_op = REOP_MINIMALREPEAT;                           \
         curState->continue_pc = pc;                                           \
         pc += ARG_LEN;                                                        \
@@ -3121,9 +3070,9 @@ good:
     return x;
 }
 
-static REMatchState *MatchRegExp(REGlobalData *gData, REMatchState *x)
+static match_state_t *MatchRegExp(REGlobalData *gData, match_state_t *x)
 {
-    REMatchState *result;
+    match_state_t *result;
     const WCHAR *cp = x->cp;
     const WCHAR *cp2;
     UINT j;
@@ -3138,7 +3087,7 @@ static REMatchState *MatchRegExp(REGlobalData *gData, REMatchState *x)
         for (j = 0; j < gData->regexp->parenCount; j++)
             x->parens[j].index = -1;
         result = ExecuteREBytecode(gData, x);
-        if (!gData->ok || result || (gData->regexp->flags & JSREG_STICKY))
+        if (!gData->ok || result || (gData->regexp->flags & REG_STICKY))
             return result;
         gData->backTrackSP = gData->backTrackStack;
         gData->cursz = 0;
@@ -3148,15 +3097,12 @@ static REMatchState *MatchRegExp(REGlobalData *gData, REMatchState *x)
     return NULL;
 }
 
-#define MIN_BACKTRACK_LIMIT 400000
-
-static REMatchState *InitMatch(script_ctx_t *cx, REGlobalData *gData, JSRegExp *re, size_t length)
+static HRESULT InitMatch(regexp_t *re, void *cx, heap_pool_t *pool, REGlobalData *gData)
 {
-    REMatchState *result;
     UINT i;
 
     gData->backTrackStackSize = INITIAL_BACKTRACK;
-    gData->backTrackStack = jsheap_alloc(gData->pool, INITIAL_BACKTRACK);
+    gData->backTrackStack = heap_pool_alloc(gData->pool, INITIAL_BACKTRACK);
     if (!gData->backTrackStack)
         goto bad;
 
@@ -3166,36 +3112,73 @@ static REMatchState *InitMatch(script_ctx_t *cx, REGlobalData *gData, JSRegExp *
     gData->backTrackLimit = 0;
 
     gData->stateStackLimit = INITIAL_STATESTACK;
-    gData->stateStack = jsheap_alloc(gData->pool, sizeof(REProgState) * INITIAL_STATESTACK);
+    gData->stateStack = heap_pool_alloc(gData->pool, sizeof(REProgState) * INITIAL_STATESTACK);
     if (!gData->stateStack)
         goto bad;
 
     gData->stateStackTop = 0;
     gData->cx = cx;
+    gData->pool = pool;
     gData->regexp = re;
     gData->ok = TRUE;
 
-    result = jsheap_alloc(gData->pool, offsetof(REMatchState, parens) + re->parenCount * sizeof(RECapture));
-    if (!result)
-        goto bad;
-
     for (i = 0; i < re->classCount; i++) {
         if (!re->classList[i].converted &&
-            !ProcessCharSet(gData, &re->classList[i])) {
-            return NULL;
+                !ProcessCharSet(gData, &re->classList[i])) {
+            return E_FAIL;
         }
     }
 
-    return result;
+    return S_OK;
 
 bad:
     js_ReportOutOfScriptQuota(cx);
     gData->ok = FALSE;
-    return NULL;
+    return E_OUTOFMEMORY;
 }
 
-static void
-js_DestroyRegExp(JSRegExp *re)
+HRESULT regexp_execute(regexp_t *regexp, void *cx, heap_pool_t *pool,
+        const WCHAR *str, DWORD str_len, match_state_t *result)
+{
+    match_state_t *res;
+    REGlobalData gData;
+    heap_pool_t *mark = heap_pool_mark(pool);
+    const WCHAR *str_beg = result->cp;
+    HRESULT hres;
+
+    assert(result->cp != NULL);
+
+    gData.cpbegin = str;
+    gData.cpend = str+str_len;
+    gData.start = result->cp-str;
+    gData.skipped = 0;
+    gData.pool = pool;
+
+    hres = InitMatch(regexp, cx, pool, &gData);
+    if(FAILED(hres)) {
+        WARN("InitMatch failed\n");
+        heap_pool_clear(mark);
+        return hres;
+    }
+
+    res = MatchRegExp(&gData, result);
+    heap_pool_clear(mark);
+    if(!gData.ok) {
+        WARN("MatchRegExp failed\n");
+        return E_FAIL;
+    }
+
+    if(!res) {
+        result->match_len = 0;
+        return S_FALSE;
+    }
+
+    result->match_len = (result->cp-str_beg) - gData.skipped;
+    result->paren_count = regexp->parenCount;
+    return S_OK;
+}
+
+void regexp_destroy(regexp_t *re)
 {
     if (re->classList) {
         UINT i;
@@ -3209,11 +3192,11 @@ js_DestroyRegExp(JSRegExp *re)
     heap_free(re);
 }
 
-static JSRegExp *
-js_NewRegExp(script_ctx_t *cx, BSTR str, UINT flags, BOOL flat)
+regexp_t* regexp_new(void *cx, heap_pool_t *pool, const WCHAR *str,
+        DWORD str_len, WORD flags, BOOL flat)
 {
-    JSRegExp *re;
-    jsheap_t *mark;
+    regexp_t *re;
+    heap_pool_t *mark;
     CompilerState state;
     size_t resize;
     jsbytecode *endPC;
@@ -3221,10 +3204,11 @@ js_NewRegExp(script_ctx_t *cx, BSTR str, UINT flags, BOOL flat)
     size_t len;
 
     re = NULL;
-    mark = jsheap_mark(&cx->tmp_heap);
-    len = SysStringLen(str);
+    mark = heap_pool_mark(pool);
+    len = str_len;
 
     state.context = cx;
+    state.pool = pool;
     state.cp = str;
     if (!state.cp)
         goto out;
@@ -3253,7 +3237,7 @@ js_NewRegExp(script_ctx_t *cx, BSTR str, UINT flags, BOOL flat)
         if (!ParseRegExp(&state))
             goto out;
     }
-    resize = offsetof(JSRegExp, program) + state.progLength + 1;
+    resize = offsetof(regexp_t, program) + state.progLength + 1;
     re = heap_alloc(resize);
     if (!re)
         goto out;
@@ -3263,7 +3247,7 @@ js_NewRegExp(script_ctx_t *cx, BSTR str, UINT flags, BOOL flat)
     if (re->classCount) {
         re->classList = heap_alloc(re->classCount * sizeof(RECharSet));
         if (!re->classList) {
-            js_DestroyRegExp(re);
+            regexp_destroy(re);
             re = NULL;
             goto out;
         }
@@ -3274,7 +3258,7 @@ js_NewRegExp(script_ctx_t *cx, BSTR str, UINT flags, BOOL flat)
     }
     endPC = EmitREBytecode(&state, re, state.treeDepth, re->program, state.result);
     if (!endPC) {
-        js_DestroyRegExp(re);
+        regexp_destroy(re);
         re = NULL;
         goto out;
     }
@@ -3285,9 +3269,9 @@ js_NewRegExp(script_ctx_t *cx, BSTR str, UINT flags, BOOL flat)
      * besides re exist here.
      */
     if ((size_t)(endPC - re->program) != state.progLength + 1) {
-        JSRegExp *tmp;
+        regexp_t *tmp;
         assert((size_t)(endPC - re->program) < state.progLength + 1);
-        resize = offsetof(JSRegExp, program) + (endPC - re->program);
+        resize = offsetof(regexp_t, program) + (endPC - re->program);
         tmp = heap_realloc(re, resize);
         if (tmp)
             re = tmp;
@@ -3296,875 +3280,9 @@ js_NewRegExp(script_ctx_t *cx, BSTR str, UINT flags, BOOL flat)
     re->flags = flags;
     re->parenCount = state.parenCount;
     re->source = str;
+    re->source_len = str_len;
 
 out:
-    jsheap_clear(mark);
+    heap_pool_clear(mark);
     return re;
 }
-
-static inline RegExpInstance *regexp_from_vdisp(vdisp_t *vdisp)
-{
-    return (RegExpInstance*)vdisp->u.jsdisp;
-}
-
-static void set_last_index(RegExpInstance *This, DWORD last_index)
-{
-    This->last_index = last_index;
-    VariantClear(&This->last_index_var);
-    num_set_val(&This->last_index_var, last_index);
-}
-
-static HRESULT do_regexp_match_next(script_ctx_t *ctx, RegExpInstance *regexp, DWORD rem_flags,
-        const WCHAR *str, DWORD len, const WCHAR **cp, match_result_t **parens, DWORD *parens_size,
-        DWORD *parens_cnt, match_result_t *ret)
-{
-    REMatchState *x, *result;
-    REGlobalData gData;
-    DWORD matchlen;
-
-    gData.cpbegin = *cp;
-    gData.cpend = str + len;
-    gData.start = *cp-str;
-    gData.skipped = 0;
-    gData.pool = &ctx->tmp_heap;
-
-    x = InitMatch(NULL, &gData, regexp->jsregexp, gData.cpend - gData.cpbegin);
-    if(!x) {
-        WARN("InitMatch failed\n");
-        return E_FAIL;
-    }
-
-    x->cp = *cp;
-    result = MatchRegExp(&gData, x);
-    if(!gData.ok) {
-        WARN("MatchRegExp failed\n");
-        return E_FAIL;
-    }
-
-    if(!result) {
-        if(rem_flags & REM_RESET_INDEX)
-            set_last_index(regexp, 0);
-        return S_FALSE;
-    }
-
-    if(parens) {
-        if(regexp->jsregexp->parenCount > *parens_size) {
-            match_result_t *new_parens;
-
-            if(*parens)
-                new_parens = heap_realloc(*parens, sizeof(match_result_t)*regexp->jsregexp->parenCount);
-            else
-                new_parens = heap_alloc(sizeof(match_result_t)*regexp->jsregexp->parenCount);
-            if(!new_parens)
-                return E_OUTOFMEMORY;
-
-            *parens = new_parens;
-        }
-    }
-
-    /* FIXME: We often already have a copy of input string that we could use to store last match */
-    if(!(rem_flags & REM_NO_CTX_UPDATE) &&
-       (!ctx->last_match || len != SysStringLen(ctx->last_match) || strncmpW(ctx->last_match, str, len))) {
-        BSTR last_match;
-
-        last_match = SysAllocStringLen(str, len);
-        if(!last_match)
-            return E_OUTOFMEMORY;
-        SysFreeString(ctx->last_match);
-        ctx->last_match = last_match;
-    }
-
-    if(parens) {
-        DWORD i;
-
-        *parens_cnt = regexp->jsregexp->parenCount;
-
-        for(i=0; i < regexp->jsregexp->parenCount; i++) {
-            if(result->parens[i].index == -1) {
-                (*parens)[i].str = NULL;
-                (*parens)[i].len = 0;
-            }else {
-                (*parens)[i].str = *cp + result->parens[i].index;
-                (*parens)[i].len = result->parens[i].length;
-            }
-        }
-    }
-
-    matchlen = (result->cp-*cp) - gData.skipped;
-    *cp = result->cp;
-    ret->str = result->cp-matchlen;
-    ret->len = matchlen;
-    set_last_index(regexp, result->cp-str);
-
-    if(!(rem_flags & REM_NO_CTX_UPDATE)) {
-        ctx->last_match_index = ret->str-str;
-        ctx->last_match_length = matchlen;
-    }
-
-    return S_OK;
-}
-
-HRESULT regexp_match_next(script_ctx_t *ctx, DispatchEx *dispex, DWORD rem_flags, const WCHAR *str,
-        DWORD len, const WCHAR **cp, match_result_t **parens, DWORD *parens_size, DWORD *parens_cnt,
-        match_result_t *ret)
-{
-    RegExpInstance *regexp = (RegExpInstance*)dispex;
-    jsheap_t *mark;
-    HRESULT hres;
-
-    if((rem_flags & REM_CHECK_GLOBAL) && !(regexp->jsregexp->flags & JSREG_GLOB))
-        return S_FALSE;
-
-    mark = jsheap_mark(&ctx->tmp_heap);
-
-    hres = do_regexp_match_next(ctx, regexp, rem_flags, str, len, cp, parens, parens_size, parens_cnt, ret);
-
-    jsheap_clear(mark);
-    return hres;
-}
-
-HRESULT regexp_match(script_ctx_t *ctx, DispatchEx *dispex, const WCHAR *str, DWORD len, BOOL gflag,
-        match_result_t **match_result, DWORD *result_cnt)
-{
-    RegExpInstance *This = (RegExpInstance*)dispex;
-    match_result_t *ret = NULL, cres;
-    const WCHAR *cp = str;
-    DWORD i=0, ret_size = 0;
-    jsheap_t *mark;
-    HRESULT hres;
-
-    mark = jsheap_mark(&ctx->tmp_heap);
-
-    while(1) {
-        hres = do_regexp_match_next(ctx, This, 0, str, len, &cp, NULL, NULL, NULL, &cres);
-        if(hres == S_FALSE) {
-            hres = S_OK;
-            break;
-        }
-
-        if(FAILED(hres))
-            break;
-
-        if(ret_size == i) {
-            if(ret)
-                ret = heap_realloc(ret, (ret_size <<= 1) * sizeof(match_result_t));
-            else
-                ret = heap_alloc((ret_size=4) * sizeof(match_result_t));
-            if(!ret) {
-                hres = E_OUTOFMEMORY;
-                break;
-            }
-        }
-
-        ret[i++] = cres;
-
-        if(!gflag && !(This->jsregexp->flags & JSREG_GLOB)) {
-            hres = S_OK;
-            break;
-        }
-    }
-
-    jsheap_clear(mark);
-    if(FAILED(hres)) {
-        heap_free(ret);
-        return hres;
-    }
-
-    *match_result = ret;
-    *result_cnt = i;
-    return S_OK;
-}
-
-static HRESULT RegExp_source(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-
-    switch(flags) {
-    case DISPATCH_PROPERTYGET: {
-        RegExpInstance *This = regexp_from_vdisp(jsthis);
-
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = SysAllocString(This->str);
-        if(!V_BSTR(retv))
-            return E_OUTOFMEMORY;
-        break;
-    }
-    default:
-        FIXME("Unimplemnted flags %x\n", flags);
-        return E_NOTIMPL;
-    }
-
-    return S_OK;
-}
-
-static HRESULT RegExp_global(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    FIXME("\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT RegExp_ignoreCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    FIXME("\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT RegExp_multiline(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    FIXME("\n");
-    return E_NOTIMPL;
-}
-
-static INT index_from_var(script_ctx_t *ctx, VARIANT *v)
-{
-    jsexcept_t ei;
-    VARIANT num;
-    HRESULT hres;
-
-    memset(&ei, 0, sizeof(ei));
-    hres = to_number(ctx, v, &ei, &num);
-    if(FAILED(hres)) { /* FIXME: Move ignoring exceptions to to_promitive */
-        VariantClear(&ei.var);
-        return 0;
-    }
-
-    if(V_VT(&num) == VT_R8) {
-        DOUBLE d = floor(V_R8(&num));
-        return (DOUBLE)(INT)d == d ? d : 0;
-    }
-
-    return V_I4(&num);
-}
-
-static HRESULT RegExp_lastIndex(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-
-    switch(flags) {
-    case DISPATCH_PROPERTYGET: {
-        RegExpInstance *regexp = regexp_from_vdisp(jsthis);
-
-        V_VT(retv) = VT_EMPTY;
-        return VariantCopy(retv, &regexp->last_index_var);
-    }
-    case DISPATCH_PROPERTYPUT: {
-        RegExpInstance *regexp = regexp_from_vdisp(jsthis);
-        VARIANT *arg;
-        HRESULT hres;
-
-        arg = get_arg(dp,0);
-        hres = VariantCopy(&regexp->last_index_var, arg);
-        if(FAILED(hres))
-            return hres;
-
-        regexp->last_index = index_from_var(ctx, arg);
-        break;
-    }
-    default:
-        FIXME("unimplemented flags: %x\n", flags);
-        return E_NOTIMPL;
-    }
-
-    return S_OK;
-}
-
-static HRESULT RegExp_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    FIXME("\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT create_match_array(script_ctx_t *ctx, BSTR input, const match_result_t *result,
-        const match_result_t *parens, DWORD parens_cnt, jsexcept_t *ei, IDispatch **ret)
-{
-    DispatchEx *array;
-    VARIANT var;
-    int i;
-    HRESULT hres = S_OK;
-
-    static const WCHAR indexW[] = {'i','n','d','e','x',0};
-    static const WCHAR inputW[] = {'i','n','p','u','t',0};
-    static const WCHAR zeroW[] = {'0',0};
-
-    hres = create_array(ctx, parens_cnt+1, &array);
-    if(FAILED(hres))
-        return hres;
-
-    for(i=0; i < parens_cnt; i++) {
-        V_VT(&var) = VT_BSTR;
-        V_BSTR(&var) = SysAllocStringLen(parens[i].str, parens[i].len);
-        if(!V_BSTR(&var)) {
-            hres = E_OUTOFMEMORY;
-            break;
-        }
-
-        hres = jsdisp_propput_idx(array, i+1, &var, ei, NULL/*FIXME*/);
-        SysFreeString(V_BSTR(&var));
-        if(FAILED(hres))
-            break;
-    }
-
-    while(SUCCEEDED(hres)) {
-        V_VT(&var) = VT_I4;
-        V_I4(&var) = result->str-input;
-        hres = jsdisp_propput_name(array, indexW, &var, ei, NULL/*FIXME*/);
-        if(FAILED(hres))
-            break;
-
-        V_VT(&var) = VT_BSTR;
-        V_BSTR(&var) = input;
-        hres = jsdisp_propput_name(array, inputW, &var, ei, NULL/*FIXME*/);
-        if(FAILED(hres))
-            break;
-
-        V_BSTR(&var) = SysAllocStringLen(result->str, result->len);
-        if(!V_BSTR(&var)) {
-            hres = E_OUTOFMEMORY;
-            break;
-        }
-        hres = jsdisp_propput_name(array, zeroW, &var, ei, NULL/*FIXME*/);
-        SysFreeString(V_BSTR(&var));
-        break;
-    }
-
-    if(FAILED(hres)) {
-        jsdisp_release(array);
-        return hres;
-    }
-
-    *ret = (IDispatch*)_IDispatchEx_(array);
-    return S_OK;
-}
-
-static HRESULT run_exec(script_ctx_t *ctx, vdisp_t *jsthis, VARIANT *arg, jsexcept_t *ei, BSTR *input,
-        match_result_t *match, match_result_t **parens, DWORD *parens_cnt, VARIANT_BOOL *ret)
-{
-    RegExpInstance *regexp;
-    DWORD parens_size = 0, last_index = 0, length;
-    const WCHAR *cp;
-    BSTR string;
-    HRESULT hres;
-
-    if(!is_vclass(jsthis, JSCLASS_REGEXP)) {
-        FIXME("Not a RegExp\n");
-        return E_NOTIMPL;
-    }
-
-    regexp = regexp_from_vdisp(jsthis);
-
-    if(arg) {
-        hres = to_string(ctx, arg, ei, &string);
-        if(FAILED(hres))
-            return hres;
-        length = SysStringLen(string);
-    }else {
-        string = NULL;
-        length = 0;
-    }
-
-    if(regexp->jsregexp->flags & JSREG_GLOB) {
-        if(regexp->last_index < 0) {
-            SysFreeString(string);
-            set_last_index(regexp, 0);
-            *ret = VARIANT_FALSE;
-            if(input) {
-                *input = NULL;
-            }
-            return S_OK;
-        }
-
-        last_index = regexp->last_index;
-    }
-
-    cp = string + last_index;
-    hres = regexp_match_next(ctx, &regexp->dispex, REM_RESET_INDEX, string, length, &cp, parens,
-            parens ? &parens_size : NULL, parens_cnt, match);
-    if(FAILED(hres)) {
-        SysFreeString(string);
-        return hres;
-    }
-
-    *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
-    if(input) {
-        *input = string;
-    }else {
-        SysFreeString(string);
-    }
-    return S_OK;
-}
-
-static HRESULT RegExp_exec(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    match_result_t *parens = NULL, match;
-    DWORD parens_cnt = 0;
-    VARIANT_BOOL b;
-    BSTR string;
-    HRESULT hres;
-
-    TRACE("\n");
-
-    hres = run_exec(ctx, jsthis, arg_cnt(dp) ? get_arg(dp,0) : NULL, ei, &string, &match, &parens, &parens_cnt, &b);
-    if(FAILED(hres))
-        return hres;
-
-    if(retv) {
-        if(b) {
-            IDispatch *ret;
-
-            hres = create_match_array(ctx, string, &match, parens, parens_cnt, ei, &ret);
-            if(SUCCEEDED(hres)) {
-                V_VT(retv) = VT_DISPATCH;
-                V_DISPATCH(retv) = ret;
-            }
-        }else {
-            V_VT(retv) = VT_NULL;
-        }
-    }
-
-    heap_free(parens);
-    SysFreeString(string);
-    return hres;
-}
-
-static HRESULT RegExp_test(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    match_result_t match;
-    VARIANT undef_var;
-    VARIANT_BOOL b;
-    DWORD argc;
-    HRESULT hres;
-
-    TRACE("\n");
-
-    argc = arg_cnt(dp);
-    if(!argc) {
-        V_VT(&undef_var) = VT_BSTR;
-        V_BSTR(&undef_var) = SysAllocString(undefinedW);
-        if(!V_BSTR(&undef_var))
-            return E_OUTOFMEMORY;
-    }
-
-    hres = run_exec(ctx, jsthis, argc ? get_arg(dp,0) : &undef_var, ei, NULL, &match, NULL, NULL, &b);
-    if(!argc)
-        SysFreeString(V_BSTR(&undef_var));
-    if(FAILED(hres))
-        return hres;
-
-    if(retv) {
-        V_VT(retv) = VT_BOOL;
-        V_BOOL(retv) = b;
-    }
-    return S_OK;
-}
-
-static HRESULT RegExp_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-
-    switch(flags) {
-    case INVOKE_FUNC:
-        return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
-    default:
-        FIXME("unimplemented flags %x\n", flags);
-        return E_NOTIMPL;
-    }
-
-    return S_OK;
-}
-
-static void RegExp_destructor(DispatchEx *dispex)
-{
-    RegExpInstance *This = (RegExpInstance*)dispex;
-
-    if(This->jsregexp)
-        js_DestroyRegExp(This->jsregexp);
-    VariantClear(&This->last_index_var);
-    SysFreeString(This->str);
-    heap_free(This);
-}
-
-static const builtin_prop_t RegExp_props[] = {
-    {execW,                  RegExp_exec,                  PROPF_METHOD|1},
-    {globalW,                RegExp_global,                0},
-    {ignoreCaseW,            RegExp_ignoreCase,            0},
-    {lastIndexW,             RegExp_lastIndex,             0},
-    {multilineW,             RegExp_multiline,             0},
-    {sourceW,                RegExp_source,                0},
-    {testW,                  RegExp_test,                  PROPF_METHOD|1},
-    {toStringW,              RegExp_toString,              PROPF_METHOD}
-};
-
-static const builtin_info_t RegExp_info = {
-    JSCLASS_REGEXP,
-    {NULL, RegExp_value, 0},
-    sizeof(RegExp_props)/sizeof(*RegExp_props),
-    RegExp_props,
-    RegExp_destructor,
-    NULL
-};
-
-static HRESULT alloc_regexp(script_ctx_t *ctx, DispatchEx *object_prototype, RegExpInstance **ret)
-{
-    RegExpInstance *regexp;
-    HRESULT hres;
-
-    regexp = heap_alloc_zero(sizeof(RegExpInstance));
-    if(!regexp)
-        return E_OUTOFMEMORY;
-
-    if(object_prototype)
-        hres = init_dispex(&regexp->dispex, ctx, &RegExp_info, object_prototype);
-    else
-        hres = init_dispex_from_constr(&regexp->dispex, ctx, &RegExp_info, ctx->regexp_constr);
-
-    if(FAILED(hres)) {
-        heap_free(regexp);
-        return hres;
-    }
-
-    *ret = regexp;
-    return S_OK;
-}
-
-HRESULT create_regexp(script_ctx_t *ctx, const WCHAR *exp, int len, DWORD flags, DispatchEx **ret)
-{
-    RegExpInstance *regexp;
-    HRESULT hres;
-
-    TRACE("%s %x\n", debugstr_w(exp), flags);
-
-    hres = alloc_regexp(ctx, NULL, &regexp);
-    if(FAILED(hres))
-        return hres;
-
-    if(len == -1)
-        regexp->str = SysAllocString(exp);
-    else
-        regexp->str = SysAllocStringLen(exp, len);
-    if(!regexp->str) {
-        jsdisp_release(&regexp->dispex);
-        return E_OUTOFMEMORY;
-    }
-
-    regexp->jsregexp = js_NewRegExp(ctx, regexp->str, flags, FALSE);
-    if(!regexp->jsregexp) {
-        WARN("js_NewRegExp failed\n");
-        jsdisp_release(&regexp->dispex);
-        return E_FAIL;
-    }
-
-    V_VT(&regexp->last_index_var) = VT_I4;
-    V_I4(&regexp->last_index_var) = 0;
-
-    *ret = &regexp->dispex;
-    return S_OK;
-}
-
-HRESULT create_regexp_var(script_ctx_t *ctx, VARIANT *src_arg, VARIANT *flags_arg, DispatchEx **ret)
-{
-    const WCHAR *opt = emptyW, *src;
-    DWORD flags;
-    HRESULT hres;
-
-    if(V_VT(src_arg) == VT_DISPATCH) {
-        DispatchEx *obj;
-
-        obj = iface_to_jsdisp((IUnknown*)V_DISPATCH(src_arg));
-        if(obj) {
-            if(is_class(obj, JSCLASS_REGEXP)) {
-                RegExpInstance *regexp = (RegExpInstance*)obj;
-
-                hres = create_regexp(ctx, regexp->str, -1, regexp->jsregexp->flags, ret);
-                jsdisp_release(obj);
-                return hres;
-            }
-
-            jsdisp_release(obj);
-        }
-    }
-
-    if(V_VT(src_arg) != VT_BSTR) {
-        FIXME("flags_arg = %s\n", debugstr_variant(flags_arg));
-        return E_NOTIMPL;
-    }
-
-    src = V_BSTR(src_arg);
-
-    if(flags_arg) {
-        if(V_VT(flags_arg) != VT_BSTR) {
-            FIXME("unimplemented for vt %d\n", V_VT(flags_arg));
-            return E_NOTIMPL;
-        }
-
-        opt = V_BSTR(flags_arg);
-    }
-
-    hres = parse_regexp_flags(opt, strlenW(opt), &flags);
-    if(FAILED(hres))
-        return hres;
-
-    return create_regexp(ctx, src, -1, flags, ret);
-}
-
-HRESULT regexp_string_match(script_ctx_t *ctx, DispatchEx *re, BSTR str,
-        VARIANT *retv, jsexcept_t *ei)
-{
-    RegExpInstance *regexp = (RegExpInstance*)re;
-    match_result_t *match_result;
-    DWORD match_cnt, i, length;
-    DispatchEx *array;
-    VARIANT var;
-    HRESULT hres;
-
-    length = SysStringLen(str);
-
-    if(!(regexp->jsregexp->flags & JSREG_GLOB)) {
-        match_result_t match, *parens = NULL;
-        DWORD parens_cnt, parens_size = 0;
-        const WCHAR *cp = str;
-
-        hres = regexp_match_next(ctx, &regexp->dispex, 0, str, length, &cp, &parens, &parens_size, &parens_cnt, &match);
-        if(FAILED(hres))
-            return hres;
-
-        if(retv) {
-            if(hres == S_OK) {
-                IDispatch *ret;
-
-                hres = create_match_array(ctx, str, &match, parens, parens_cnt, ei, &ret);
-                if(SUCCEEDED(hres)) {
-                    V_VT(retv) = VT_DISPATCH;
-                    V_DISPATCH(retv) = ret;
-                }
-            }else {
-                V_VT(retv) = VT_NULL;
-            }
-        }
-
-        heap_free(parens);
-        return S_OK;
-    }
-
-    hres = regexp_match(ctx, &regexp->dispex, str, length, FALSE, &match_result, &match_cnt);
-    if(FAILED(hres))
-        return hres;
-
-    if(!match_cnt) {
-        TRACE("no match\n");
-
-        if(retv)
-            V_VT(retv) = VT_NULL;
-        return S_OK;
-    }
-
-    hres = create_array(ctx, match_cnt, &array);
-    if(FAILED(hres))
-        return hres;
-
-    V_VT(&var) = VT_BSTR;
-
-    for(i=0; i < match_cnt; i++) {
-        V_BSTR(&var) = SysAllocStringLen(match_result[i].str, match_result[i].len);
-        if(!V_BSTR(&var)) {
-            hres = E_OUTOFMEMORY;
-            break;
-        }
-
-        hres = jsdisp_propput_idx(array, i, &var, ei, NULL/*FIXME*/);
-        SysFreeString(V_BSTR(&var));
-        if(FAILED(hres))
-            break;
-    }
-
-    heap_free(match_result);
-
-    if(SUCCEEDED(hres) && retv) {
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(array);
-    }else {
-        jsdisp_release(array);
-    }
-    return hres;
-}
-
-static HRESULT RegExpConstr_leftContext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-
-    switch(flags) {
-    case DISPATCH_PROPERTYGET: {
-        BSTR ret;
-
-        ret = SysAllocStringLen(ctx->last_match, ctx->last_match_index);
-        if(!ret)
-            return E_OUTOFMEMORY;
-
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
-    }
-    case DISPATCH_PROPERTYPUT:
-        return S_OK;
-    default:
-        FIXME("unsupported flags\n");
-        return E_NOTIMPL;
-    }
-
-    return S_OK;
-}
-
-static HRESULT RegExpConstr_rightContext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-
-    switch(flags) {
-    case DISPATCH_PROPERTYGET: {
-        BSTR ret;
-
-        ret = SysAllocString(ctx->last_match+ctx->last_match_index+ctx->last_match_length);
-        if(!ret)
-            return E_OUTOFMEMORY;
-
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
-    }
-    case DISPATCH_PROPERTYPUT:
-        return S_OK;
-    default:
-        FIXME("unsupported flags\n");
-        return E_NOTIMPL;
-    }
-
-    return S_OK;
-}
-
-static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
-{
-    TRACE("\n");
-
-    switch(flags) {
-    case DISPATCH_METHOD:
-        if(arg_cnt(dp)) {
-            VARIANT *arg = get_arg(dp,0);
-            if(V_VT(arg) == VT_DISPATCH) {
-                DispatchEx *jsdisp = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg));
-                if(jsdisp) {
-                    if(is_class(jsdisp, JSCLASS_REGEXP)) {
-                        if(arg_cnt(dp) > 1 && V_VT(get_arg(dp,1)) != VT_EMPTY) {
-                            jsdisp_release(jsdisp);
-                            return throw_regexp_error(ctx, ei, IDS_REGEXP_SYNTAX_ERROR, NULL);
-                        }
-
-                        if(retv) {
-                            V_VT(retv) = VT_DISPATCH;
-                            V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(jsdisp);
-                        }else {
-                            jsdisp_release(jsdisp);
-                        }
-                        return S_OK;
-                    }
-                    jsdisp_release(jsdisp);
-                }
-            }
-        }
-        /* fall through */
-    case DISPATCH_CONSTRUCT: {
-        DispatchEx *ret;
-        HRESULT hres;
-
-        if(!arg_cnt(dp)) {
-            FIXME("no args\n");
-            return E_NOTIMPL;
-        }
-
-        hres = create_regexp_var(ctx, get_arg(dp,0), arg_cnt(dp) > 1 ? get_arg(dp,1) : NULL, &ret);
-        if(FAILED(hres))
-            return hres;
-
-        if(retv) {
-            V_VT(retv) = VT_DISPATCH;
-            V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(ret);
-        }else {
-            jsdisp_release(ret);
-        }
-        return S_OK;
-    }
-    default:
-        FIXME("unimplemented flags: %x\n", flags);
-        return E_NOTIMPL;
-    }
-
-    return S_OK;
-}
-
-static const builtin_prop_t RegExpConstr_props[] = {
-    {leftContextW,    RegExpConstr_leftContext,    0},
-    {rightContextW,   RegExpConstr_rightContext,   0}
-};
-
-static const builtin_info_t RegExpConstr_info = {
-    JSCLASS_FUNCTION,
-    {NULL, Function_value, 0},
-    sizeof(RegExpConstr_props)/sizeof(*RegExpConstr_props),
-    RegExpConstr_props,
-    NULL,
-    NULL
-};
-
-HRESULT create_regexp_constr(script_ctx_t *ctx, DispatchEx *object_prototype, DispatchEx **ret)
-{
-    RegExpInstance *regexp;
-    HRESULT hres;
-
-    static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
-
-    hres = alloc_regexp(ctx, object_prototype, &regexp);
-    if(FAILED(hres))
-        return hres;
-
-    hres = create_builtin_function(ctx, RegExpConstr_value, RegExpW, &RegExpConstr_info,
-            PROPF_CONSTR|2, &regexp->dispex, ret);
-
-    jsdisp_release(&regexp->dispex);
-    return hres;
-}
-
-HRESULT parse_regexp_flags(const WCHAR *str, DWORD str_len, DWORD *ret)
-{
-    const WCHAR *p;
-    DWORD flags = 0;
-
-    for (p = str; p < str+str_len; p++) {
-        switch (*p) {
-        case 'g':
-            flags |= JSREG_GLOB;
-            break;
-        case 'i':
-            flags |= JSREG_FOLD;
-            break;
-        case 'm':
-            flags |= JSREG_MULTILINE;
-            break;
-        case 'y':
-            flags |= JSREG_STICKY;
-            break;
-        default:
-            WARN("wrong flag %c\n", *p);
-            return E_FAIL;
-        }
-    }
-
-    *ret = flags;
-    return S_OK;
-}
diff --git a/reactos/dll/win32/jscript/regexp.h b/reactos/dll/win32/jscript/regexp.h
new file mode 100644 (file)
index 0000000..de86aa2
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2008 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
+ */
+
+/*
+ * Code in this file is based on files:
+ * js/src/jsregexp.h
+ * js/src/jsregexp.c
+ * from Mozilla project, released under LGPL 2.1 or later.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ */
+
+#define REG_FOLD      0x01      /* fold uppercase to lowercase */
+#define REG_GLOB      0x02      /* global exec, creates array of matches */
+#define REG_MULTILINE 0x04      /* treat ^ and $ as begin and end of line */
+#define REG_STICKY    0x08      /* only match starting at lastIndex */
+
+typedef struct RECapture {
+    ptrdiff_t index;            /* start of contents, -1 for empty  */
+    size_t length;              /* length of capture */
+} RECapture;
+
+typedef struct match_state_t {
+    const WCHAR *cp;
+    DWORD match_len;
+
+    DWORD paren_count;
+    RECapture parens[1];
+} match_state_t;
+
+typedef BYTE jsbytecode;
+
+typedef struct regexp_t {
+    WORD                flags;         /* flags, see jsapi.h's REG_* defines */
+    size_t              parenCount;    /* number of parenthesized submatches */
+    size_t              classCount;    /* count [...] bitmaps */
+    struct RECharSet    *classList;    /* list of [...] bitmaps */
+    const WCHAR         *source;       /* locked source string, sans // */
+    DWORD               source_len;
+    jsbytecode          program[1];    /* regular expression bytecode */
+} regexp_t;
+
+regexp_t* regexp_new(void*, heap_pool_t*, const WCHAR*, DWORD, WORD, BOOL) DECLSPEC_HIDDEN;
+void regexp_destroy(regexp_t*) DECLSPEC_HIDDEN;
+HRESULT regexp_execute(regexp_t*, void*, heap_pool_t*, const WCHAR*,
+        DWORD, match_state_t*) DECLSPEC_HIDDEN;
+
+static inline match_state_t* alloc_match_state(regexp_t *regexp,
+        heap_pool_t *pool, const WCHAR *pos)
+{
+    size_t size = offsetof(match_state_t, parens) + regexp->parenCount*sizeof(RECapture);
+    match_state_t *ret;
+
+    ret = pool ? heap_pool_alloc(pool, size) : heap_alloc(size);
+    if(!ret)
+        return NULL;
+
+    ret->cp = pos;
+    return ret;
+}
index b88621f..fc4c829 100644 (file)
 
 #include <windef.h>
 
+#define JSCRIPT_MAJOR_VERSION 5
+#define JSCRIPT_MINOR_VERSION 8
+#define JSCRIPT_BUILD_VERSION 16475
+
 #define IDS_TO_PRIMITIVE                    0x0001
 #define IDS_INVALID_CALL_ARG                0x0005
+#define IDS_SUBSCRIPT_OUT_OF_RANGE          0x0009
+#define IDS_OBJECT_REQUIRED                 0x01A8
 #define IDS_CREATE_OBJ_ERROR                0x01AD
 #define IDS_NO_PROPERTY                     0x01B6
+#define IDS_UNSUPPORTED_ACTION              0x01BD
 #define IDS_ARG_NOT_OPT                     0x01c1
 #define IDS_SYNTAX_ERROR                    0x03EA
 #define IDS_SEMICOLON                       0x03EC
 #define IDS_LBRACKET                        0x03ED
 #define IDS_RBRACKET                        0x03EE
+#define IDS_INVALID_CHAR                    0x03F6
 #define IDS_UNTERMINATED_STR                0x03F7
+#define IDS_MISPLACED_RETURN                0x03FA
+#define IDS_INVALID_BREAK                   0x03FB
+#define IDS_INVALID_CONTINUE                0x03FC
+#define IDS_LABEL_REDEFINED                 0x0401
+#define IDS_LABEL_NOT_FOUND                 0x0402
+#define IDS_DISABLED_CC                     0x0406
 #define IDS_NOT_FUNC                        0x138A
 #define IDS_NOT_DATE                        0x138E
 #define IDS_NOT_NUM                         0x1389
 #define IDS_ILLEGAL_ASSIGN                  0x1390
 #define IDS_UNDEFINED                       0x1391
 #define IDS_NOT_BOOL                        0x1392
+#define IDS_INVALID_DELETE                  0x1394
+#define IDS_NOT_VBARRAY                     0x1395
 #define IDS_JSCRIPT_EXPECTED                0x1396
 #define IDS_REGEXP_SYNTAX_ERROR             0x1399
 #define IDS_URI_INVALID_CHAR                0x13A0
+#define IDS_URI_INVALID_CODING              0x13A1
+#define IDS_FRACTION_DIGITS_OUT_OF_RANGE    0x13A2
+#define IDS_PRECISION_OUT_OF_RANGE          0x13A3
 #define IDS_INVALID_LENGTH                  0x13A5
 #define IDS_ARRAY_EXPECTED                  0x13A7
index 502cd94..067fdeb 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-/* @makedep: jscript.inf */
-REGINST REGINST jscript.inf
+/* @makedep: jscript.rgs */
+2 WINE_REGISTRY jscript.rgs
+
+3 WINE_REGISTRY jscript_classes.rgs
 
 /* @makedep: jsglobal.tlb */
 1 TYPELIB jsglobal.tlb
 
+#define WINE_FILEDESCRIPTION_STR "Wine JScript"
+#define WINE_FILENAME_STR "jscript.dll"
+#define WINE_FILEVERSION 5,7,7601,16982
+#define WINE_FILEVERSION_STR "5.8.7601.16982"
+#define WINE_PRODUCTVERSION 5,8,7601,16982
+#define WINE_PRODUCTVERSION_STR "5.8.7601.16982"
+
+#include "wine/wine_common_ver.rc"
+
 #ifdef LANGUAGE_EN_US
     #include "jscript_En.rc"
 #endif
index ff999d9..80392a9 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "config.h"
+#include "wine/port.h"
+
 #include "jscript.h"
+#include "regexp.h"
 
 #include <wine/debug.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
 
-typedef struct {
-    DispatchEx dispex;
+#define UINT32_MAX 0xffffffff
 
-    WCHAR *str;
-    DWORD length;
+typedef struct {
+    jsdisp_t dispex;
+    jsstr_t *str;
 } StringInstance;
 
 static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
@@ -74,33 +78,20 @@ static inline StringInstance *string_this(vdisp_t *jsthis)
     return is_vclass(jsthis, JSCLASS_STRING) ? string_from_vdisp(jsthis) : NULL;
 }
 
-static HRESULT get_string_val(script_ctx_t *ctx, vdisp_t *jsthis, jsexcept_t *ei,
-        const WCHAR **str, DWORD *len, BSTR *val_str)
+static HRESULT get_string_val(script_ctx_t *ctx, vdisp_t *jsthis, jsstr_t **val)
 {
     StringInstance *string;
-    VARIANT this_var;
-    HRESULT hres;
 
     if((string = string_this(jsthis))) {
-        *str = string->str;
-        *len = string->length;
-        *val_str = NULL;
+        *val = jsstr_addref(string->str);
         return S_OK;
     }
 
-    V_VT(&this_var) = VT_DISPATCH;
-    V_DISPATCH(&this_var) = jsthis->u.disp;
-    hres = to_string(ctx, &this_var, ei, val_str);
-    if(FAILED(hres))
-        return hres;
-
-    *str = *val_str;
-    *len = SysStringLen(*val_str);
-    return S_OK;
+    return to_string(ctx, jsval_disp(jsthis->u.disp), val);
 }
 
-static HRESULT String_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("%p\n", jsthis);
 
@@ -108,8 +99,7 @@ static HRESULT String_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DIS
     case DISPATCH_PROPERTYGET: {
         StringInstance *string = string_from_vdisp(jsthis);
 
-        V_VT(retv) = VT_I4;
-        V_I4(retv) = string->length;
+        *r = jsval_number(jsstr_length(string->str));
         break;
     }
     default:
@@ -120,7 +110,7 @@ static HRESULT String_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DIS
     return S_OK;
 }
 
-static HRESULT stringobj_to_string(vdisp_t *jsthis, VARIANT *retv)
+static HRESULT stringobj_to_string(vdisp_t *jsthis, jsval_t *r)
 {
     StringInstance *string;
 
@@ -129,458 +119,426 @@ static HRESULT stringobj_to_string(vdisp_t *jsthis, VARIANT *retv)
         return E_FAIL;
     }
 
-    if(retv) {
-        BSTR str = SysAllocString(string->str);
-        if(!str)
-            return E_OUTOFMEMORY;
-
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = str;
-    }
+    if(r)
+        *r = jsval_string(jsstr_addref(string->str));
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.5.4.2 */
-static HRESULT String_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return stringobj_to_string(jsthis, retv);
+    return stringobj_to_string(jsthis, r);
 }
 
 /* ECMA-262 3rd Edition    15.5.4.2 */
-static HRESULT String_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     TRACE("\n");
 
-    return stringobj_to_string(jsthis, retv);
+    return stringobj_to_string(jsthis, r);
 }
 
-static HRESULT do_attributeless_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp, const WCHAR *tagname)
+static HRESULT do_attributeless_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r, const WCHAR *tagname)
 {
-    const WCHAR *str;
-    DWORD length;
-    BSTR val_str = NULL;
+    unsigned tagname_len;
+    jsstr_t *str, *ret;
+    WCHAR *ptr;
     HRESULT hres;
 
-    static const WCHAR tagfmt[] = {'<','%','s','>','%','s','<','/','%','s','>',0};
-
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(retv) {
-        BSTR ret = SysAllocStringLen(NULL, length + 2*strlenW(tagname) + 5);
-        if(!ret) {
-            SysFreeString(val_str);
-            return E_OUTOFMEMORY;
-        }
+    if(!r) {
+        jsstr_release(str);
+        return S_OK;
+    }
 
-        sprintfW(ret, tagfmt, tagname, str, tagname);
+    tagname_len = strlenW(tagname);
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
+    ret = jsstr_alloc_buf(jsstr_length(str) + 2*tagname_len + 5);
+    if(!ret) {
+        jsstr_release(str);
+        return E_OUTOFMEMORY;
     }
 
-    SysFreeString(val_str);
+    ptr = ret->str;
+    *ptr++ = '<';
+    memcpy(ptr, tagname, tagname_len*sizeof(WCHAR));
+    ptr += tagname_len;
+    *ptr++ = '>';
+
+    ptr += jsstr_flush(str, ptr);
+    jsstr_release(str);
+
+    *ptr++ = '<';
+    *ptr++ = '/';
+    memcpy(ptr, tagname, tagname_len*sizeof(WCHAR));
+    ptr += tagname_len;
+    *ptr = '>';
+
+    *r = jsval_string(ret);
     return S_OK;
 }
 
-static HRESULT do_attribute_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp,
-        const WCHAR *tagname, const WCHAR *attr)
+static HRESULT do_attribute_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, unsigned argc, jsval_t *argv, jsval_t *r,
+        const WCHAR *tagname, const WCHAR *attrname)
 {
-    static const WCHAR tagfmtW[]
-        = {'<','%','s',' ','%','s','=','\"','%','s','\"','>','%','s','<','/','%','s','>',0};
-    static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
-
-    StringInstance *string;
-    const WCHAR *str;
-    DWORD length;
-    BSTR attr_value, val_str = NULL;
+    jsstr_t *str, *attr_value = NULL;
     HRESULT hres;
 
-    if(!(string = string_this(jsthis))) {
-        VARIANT this;
-
-        V_VT(&this) = VT_DISPATCH;
-        V_DISPATCH(&this) = jsthis->u.disp;
-
-        hres = to_string(ctx, &this, ei, &val_str);
-        if(FAILED(hres))
-            return hres;
-
-        str = val_str;
-        length = SysStringLen(val_str);
-    }
-    else {
-        str = string->str;
-        length = string->length;
-    }
+    hres = get_string_val(ctx, jsthis, &str);
+    if(FAILED(hres))
+        return hres;
 
-    if(arg_cnt(dp)) {
-        hres = to_string(ctx, get_arg(dp, 0), ei, &attr_value);
+    if(argc) {
+        hres = to_string(ctx, argv[0], &attr_value);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
-    }
-    else {
-        attr_value = SysAllocString(undefinedW);
-        if(!attr_value) {
-            SysFreeString(val_str);
-            return E_OUTOFMEMORY;
-        }
-    }
-
-    if(retv) {
-        BSTR ret = SysAllocStringLen(NULL, length + 2*strlenW(tagname)
-                + strlenW(attr) + SysStringLen(attr_value) + 9);
-        if(!ret) {
-            SysFreeString(attr_value);
-            SysFreeString(val_str);
-            return E_OUTOFMEMORY;
+    }else {
+        attr_value = jsstr_undefined();
+    }
+
+    if(r) {
+        unsigned attrname_len = strlenW(attrname);
+        unsigned tagname_len = strlenW(tagname);
+        jsstr_t *ret;
+
+        ret = jsstr_alloc_buf(2*tagname_len + attrname_len + jsstr_length(attr_value) + jsstr_length(str) + 9);
+        if(ret) {
+            WCHAR *ptr = ret->str;
+
+            *ptr++ = '<';
+            memcpy(ptr, tagname, tagname_len*sizeof(WCHAR));
+            ptr += tagname_len;
+            *ptr++ = ' ';
+            memcpy(ptr, attrname, attrname_len*sizeof(WCHAR));
+            ptr += attrname_len;
+            *ptr++ = '=';
+            *ptr++ = '"';
+            ptr += jsstr_flush(attr_value, ptr);
+            *ptr++ = '"';
+            *ptr++ = '>';
+            ptr += jsstr_flush(str, ptr);
+
+            *ptr++ = '<';
+            *ptr++ = '/';
+            memcpy(ptr, tagname, tagname_len*sizeof(WCHAR));
+            ptr += tagname_len;
+            *ptr = '>';
+
+            *r = jsval_string(ret);
+        }else {
+            hres = E_OUTOFMEMORY;
         }
-
-        sprintfW(ret, tagfmtW, tagname, attr, attr_value, str, tagname);
-
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
     }
 
-    SysFreeString(attr_value);
-    SysFreeString(val_str);
-    return S_OK;
+    jsstr_release(attr_value);
+    jsstr_release(str);
+    return hres;
 }
 
-static HRESULT String_anchor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_anchor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR fontW[] = {'A',0};
     static const WCHAR colorW[] = {'N','A','M','E',0};
 
-    return do_attribute_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, fontW, colorW);
+    return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
 }
 
-static HRESULT String_big(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_big(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR bigtagW[] = {'B','I','G',0};
-    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, bigtagW);
+    return do_attributeless_tag_format(ctx, jsthis, r, bigtagW);
 }
 
-static HRESULT String_blink(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_blink(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR blinktagW[] = {'B','L','I','N','K',0};
-    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, blinktagW);
+    return do_attributeless_tag_format(ctx, jsthis, r, blinktagW);
 }
 
-static HRESULT String_bold(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_bold(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR boldtagW[] = {'B',0};
-    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, boldtagW);
+    return do_attributeless_tag_format(ctx, jsthis, r, boldtagW);
 }
 
 /* ECMA-262 3rd Edition    15.5.4.5 */
-static HRESULT String_charAt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_charAt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    const WCHAR *str;
-    DWORD length;
-    BSTR ret, val_str;
+    jsstr_t *str, *ret;
     INT pos = 0;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(arg_cnt(dp)) {
-        VARIANT num;
+    if(argc) {
+        double d;
 
-        hres = to_integer(ctx, get_arg(dp, 0), ei, &num);
+        hres = to_integer(ctx, argv[0], &d);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
-
-        if(V_VT(&num) == VT_I4) {
-            pos = V_I4(&num);
-        }else {
-            WARN("pos = %lf\n", V_R8(&num));
-            pos = -1;
-        }
+        pos = is_int32(d) ? d : -1;
     }
 
-    if(!retv) {
-        SysFreeString(val_str);
+    if(!r) {
+        jsstr_release(str);
         return S_OK;
     }
 
-    if(0 <= pos && pos < length)
-        ret = SysAllocStringLen(str+pos, 1);
-    else
-        ret = SysAllocStringLen(NULL, 0);
-    SysFreeString(val_str);
-    if(!ret) {
-        return E_OUTOFMEMORY;
+    if(0 <= pos && pos < jsstr_length(str)) {
+        ret = jsstr_substr(str, pos, 1);
+        if(!ret)
+            return E_OUTOFMEMORY;
+    }else {
+        ret = jsstr_empty();
     }
 
-    V_VT(retv) = VT_BSTR;
-    V_BSTR(retv) = ret;
+    *r = jsval_string(ret);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.5.4.5 */
-static HRESULT String_charCodeAt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_charCodeAt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    const WCHAR *str;
-    BSTR val_str;
-    DWORD length, idx = 0;
+    jsstr_t *str;
+    DWORD idx = 0;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(arg_cnt(dp) > 0) {
-        VARIANT v;
+    if(argc > 0) {
+        double d;
 
-        hres = to_integer(ctx, get_arg(dp, 0), ei, &v);
+        hres = to_integer(ctx, argv[0], &d);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
 
-        if(V_VT(&v) != VT_I4 || V_I4(&v) < 0 || V_I4(&v) >= length) {
-            if(retv) num_set_nan(&v);
-            SysFreeString(val_str);
+        if(!is_int32(d) || d < 0 || d >= jsstr_length(str)) {
+            jsstr_release(str);
+            if(r)
+                *r = jsval_number(NAN);
             return S_OK;
         }
 
-        idx = V_I4(&v);
+        idx = d;
     }
 
-    if(retv) {
-        V_VT(retv) = VT_I4;
-        V_I4(retv) = str[idx];
-    }
+    if(r)
+        *r = jsval_number(str->str[idx]);
 
-    SysFreeString(val_str);
+    jsstr_release(str);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.5.4.6 */
-static HRESULT String_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    BSTR *strs = NULL, ret = NULL;
-    DWORD len = 0, i, l, str_cnt;
-    VARIANT var;
+    unsigned len = 0, i, str_cnt;
+    jsstr_t **strs, *ret = NULL;
     WCHAR *ptr;
     HRESULT hres;
 
     TRACE("\n");
 
-    str_cnt = arg_cnt(dp)+1;
-    strs = heap_alloc_zero(str_cnt * sizeof(BSTR));
+    str_cnt = argc+1;
+    strs = heap_alloc_zero(str_cnt * sizeof(*strs));
     if(!strs)
         return E_OUTOFMEMORY;
 
-    V_VT(&var) = VT_DISPATCH;
-    V_DISPATCH(&var) = jsthis->u.disp;
-
-    hres = to_string(ctx, &var, ei, strs);
+    hres = to_string(ctx, jsval_disp(jsthis->u.disp), strs);
     if(SUCCEEDED(hres)) {
-        for(i=0; i < arg_cnt(dp); i++) {
-            hres = to_string(ctx, get_arg(dp, i), ei, strs+i+1);
+        for(i=0; i < argc; i++) {
+            hres = to_string(ctx, argv[i], strs+i+1);
             if(FAILED(hres))
                 break;
         }
     }
 
     if(SUCCEEDED(hres)) {
-        for(i=0; i < str_cnt; i++)
-            len += SysStringLen(strs[i]);
-
-        ptr = ret = SysAllocStringLen(NULL, len);
-
         for(i=0; i < str_cnt; i++) {
-            l = SysStringLen(strs[i]);
-            memcpy(ptr, strs[i], l*sizeof(WCHAR));
-            ptr += l;
+            len += jsstr_length(strs[i]);
+            if(len > JSSTR_MAX_LENGTH) {
+                hres = E_OUTOFMEMORY;
+                break;
+            }
+        }
+
+        ret = jsstr_alloc_buf(len);
+        if(ret) {
+            ptr = ret->str;
+            for(i=0; i < str_cnt; i++)
+                ptr += jsstr_flush(strs[i], ptr);
+        }else {
+            hres = E_OUTOFMEMORY;
         }
     }
 
     for(i=0; i < str_cnt; i++)
-        SysFreeString(strs[i]);
+        jsstr_release(strs[i]);
     heap_free(strs);
 
     if(FAILED(hres))
         return hres;
 
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
-    }else {
-        SysFreeString(ret);
-    }
+    if(r)
+        *r = jsval_string(ret);
+    else
+        jsstr_release(ret);
     return S_OK;
 }
 
-static HRESULT String_fixed(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_fixed(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR fixedtagW[] = {'T','T',0};
-    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, fixedtagW);
+    return do_attributeless_tag_format(ctx, jsthis, r, fixedtagW);
 }
 
-static HRESULT String_fontcolor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_fontcolor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR fontW[] = {'F','O','N','T',0};
     static const WCHAR colorW[] = {'C','O','L','O','R',0};
 
-    return do_attribute_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, fontW, colorW);
+    return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
 }
 
-static HRESULT String_fontsize(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_fontsize(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR fontW[] = {'F','O','N','T',0};
     static const WCHAR colorW[] = {'S','I','Z','E',0};
 
-    return do_attribute_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, fontW, colorW);
+    return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
 }
 
-static HRESULT String_indexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_indexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DWORD length, pos = 0;
-    const WCHAR *str;
-    BSTR search_str, val_str;
+    jsstr_t *search_str, *str;
+    int length, pos = 0;
     INT ret = -1;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(!arg_cnt(dp)) {
-        if(retv) {
-            V_VT(retv) = VT_I4;
-            V_I4(retv) = -1;
-        }
-        SysFreeString(val_str);
+    length = jsstr_length(str);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(-1);
+        jsstr_release(str);
         return S_OK;
     }
 
-    hres = to_string(ctx, get_arg(dp,0), ei, &search_str);
+    hres = to_string(ctx, argv[0], &search_str);
     if(FAILED(hres)) {
-        SysFreeString(val_str);
+        jsstr_release(str);
         return hres;
     }
 
-    if(arg_cnt(dp) >= 2) {
-        VARIANT ival;
+    if(argc >= 2) {
+        double d;
 
-        hres = to_integer(ctx, get_arg(dp,1), ei, &ival);
-        if(SUCCEEDED(hres)) {
-            if(V_VT(&ival) == VT_I4)
-                pos = V_VT(&ival) > 0 ? V_I4(&ival) : 0;
-            else
-                pos = V_R8(&ival) > 0.0 ? length : 0;
-            if(pos > length)
-                pos = length;
-        }
+        hres = to_integer(ctx, argv[1], &d);
+        if(SUCCEEDED(hres) && d > 0.0)
+            pos = is_int32(d) ? min(length, d) : length;
     }
 
     if(SUCCEEDED(hres)) {
         const WCHAR *ptr;
 
-        ptr = strstrW(str+pos, search_str);
+        ptr = strstrW(str->str+pos, search_str->str);
         if(ptr)
-            ret = ptr - str;
+            ret = ptr - str->str;
         else
             ret = -1;
     }
 
-    SysFreeString(search_str);
-    SysFreeString(val_str);
+    jsstr_release(search_str);
+    jsstr_release(str);
     if(FAILED(hres))
         return hres;
 
-    if(retv) {
-        V_VT(retv) = VT_I4;
-        V_I4(retv) = ret;
-    }
+    if(r)
+        *r = jsval_number(ret);
     return S_OK;
 }
 
-static HRESULT String_italics(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_italics(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR italicstagW[] = {'I',0};
-    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, italicstagW);
+    return do_attributeless_tag_format(ctx, jsthis, r, italicstagW);
 }
 
 /* ECMA-262 3rd Edition    15.5.4.8 */
-static HRESULT String_lastIndexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_lastIndexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    BSTR search_str, val_str;
-    DWORD length, pos, search_len;
-    const WCHAR *str;
+    unsigned pos = 0, search_len, length;
+    jsstr_t *search_str, *str;
     INT ret = -1;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(!arg_cnt(dp)) {
-        if(retv) {
-            V_VT(retv) = VT_I4;
-            V_I4(retv) = -1;
-        }
-        SysFreeString(val_str);
+    if(!argc) {
+        if(r)
+            *r = jsval_number(-1);
+        jsstr_release(str);
         return S_OK;
     }
 
-    hres = to_string(ctx, get_arg(dp,0), ei, &search_str);
+    hres = to_string(ctx, argv[0], &search_str);
     if(FAILED(hres)) {
-        SysFreeString(val_str);
+        jsstr_release(str);
         return hres;
     }
 
-    search_len = SysStringLen(search_str);
+    search_len = jsstr_length(search_str);
+    length = jsstr_length(str);
 
-    if(arg_cnt(dp) >= 2) {
-        VARIANT ival;
+    if(argc >= 2) {
+        double d;
 
-        hres = to_integer(ctx, get_arg(dp,1), ei, &ival);
-        if(SUCCEEDED(hres)) {
-            if(V_VT(&ival) == VT_I4)
-                pos = V_VT(&ival) > 0 ? V_I4(&ival) : 0;
-            else
-                pos = V_R8(&ival) > 0.0 ? length : 0;
-            if(pos > length)
-                pos = length;
-        }
+        hres = to_integer(ctx, argv[1], &d);
+        if(SUCCEEDED(hres) && d > 0)
+            pos = is_int32(d) ? min(length, d) : length;
     }else {
         pos = length;
     }
@@ -588,91 +546,76 @@ static HRESULT String_lastIndexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
     if(SUCCEEDED(hres) && length >= search_len) {
         const WCHAR *ptr;
 
-        for(ptr = str+min(pos, length-search_len); ptr >= str; ptr--) {
-            if(!memcmp(ptr, search_str, search_len*sizeof(WCHAR))) {
-                ret = ptr-str;
+        for(ptr = str->str+min(pos, length-search_len); ptr >= str->str; ptr--) {
+            if(!memcmp(ptr, search_str->str, search_len*sizeof(WCHAR))) {
+                ret = ptr-str->str;
                 break;
             }
         }
     }
 
-    SysFreeString(search_str);
-    SysFreeString(val_str);
+    jsstr_release(search_str);
+    jsstr_release(str);
     if(FAILED(hres))
         return hres;
 
-    if(retv) {
-        V_VT(retv) = VT_I4;
-        V_I4(retv) = ret;
-    }
+    if(r)
+        *r = jsval_number(ret);
     return S_OK;
 }
 
-static HRESULT String_link(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_link(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR fontW[] = {'A',0};
     static const WCHAR colorW[] = {'H','R','E','F',0};
 
-    return do_attribute_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, fontW, colorW);
+    return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
 }
 
 /* ECMA-262 3rd Edition    15.5.4.10 */
-static HRESULT String_match(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_match(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    const WCHAR *str;
-    DispatchEx *regexp;
-    VARIANT *arg_var;
-    DWORD length;
-    BSTR val_str = NULL;
-    HRESULT hres = S_OK;
+    jsdisp_t *regexp = NULL;
+    jsstr_t *str;
+    HRESULT hres;
 
     TRACE("\n");
 
-    if(!arg_cnt(dp)) {
-        if(retv) {
-            V_VT(retv) = VT_NULL;
-        }
-
+    if(!argc) {
+        if(r)
+            *r = jsval_null();
         return S_OK;
     }
 
-    arg_var = get_arg(dp, 0);
-    switch(V_VT(arg_var)) {
-    case VT_DISPATCH:
-        regexp = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg_var));
-        if(regexp) {
-            if(is_class(regexp, JSCLASS_REGEXP))
-                break;
+    if(is_object_instance(argv[0])) {
+        regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
+        if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
             jsdisp_release(regexp);
+            regexp = NULL;
         }
-    default: {
-        BSTR match_str;
+    }
 
-        hres = to_string(ctx, arg_var, ei, &match_str);
+    if(!regexp) {
+        jsstr_t *match_str;
+
+        hres = to_string(ctx, argv[0], &match_str);
         if(FAILED(hres))
             return hres;
 
-        hres = create_regexp(ctx, match_str, SysStringLen(match_str), 0, &regexp);
-        SysFreeString(match_str);
+        hres = create_regexp(ctx, match_str, 0, &regexp);
+        jsstr_release(match_str);
         if(FAILED(hres))
             return hres;
     }
-    }
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
-    if(SUCCEEDED(hres)) {
-        if(!val_str)
-            val_str = SysAllocStringLen(str, length);
-        if(val_str)
-            hres = regexp_string_match(ctx, regexp, val_str, retv, ei);
-        else
-            hres = E_OUTOFMEMORY;
-    }
+    hres = get_string_val(ctx, jsthis, &str);
+    if(SUCCEEDED(hres))
+        hres = regexp_string_match(ctx, regexp, str, r);
 
     jsdisp_release(regexp);
-    SysFreeString(val_str);
+    jsstr_release(str);
     return hres;
 }
 
@@ -710,157 +653,125 @@ static HRESULT strbuf_append(strbuf_t *buf, const WCHAR *str, DWORD len)
     return S_OK;
 }
 
-static HRESULT rep_call(script_ctx_t *ctx, DispatchEx *func, const WCHAR *str, match_result_t *match,
-        match_result_t *parens, DWORD parens_cnt, BSTR *ret, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT rep_call(script_ctx_t *ctx, jsdisp_t *func,
+        jsstr_t *str, match_state_t *match, jsstr_t **ret)
 {
-    DISPPARAMS dp = {NULL, NULL, 0, 0};
-    VARIANTARG *args, *arg;
-    VARIANT var;
+    jsval_t *argv;
+    unsigned argc;
+    jsval_t val;
+    jsstr_t *tmp_str;
     DWORD i;
     HRESULT hres = S_OK;
 
-    dp.cArgs = parens_cnt+3;
-    dp.rgvarg = args = heap_alloc_zero(sizeof(VARIANT)*dp.cArgs);
-    if(!args)
+    argc = match->paren_count+3;
+    argv = heap_alloc_zero(sizeof(*argv)*argc);
+    if(!argv)
         return E_OUTOFMEMORY;
 
-    arg = get_arg(&dp,0);
-    V_VT(arg) = VT_BSTR;
-    V_BSTR(arg) = SysAllocStringLen(match->str, match->len);
-    if(!V_BSTR(arg))
+    tmp_str = jsstr_alloc_len(match->cp-match->match_len, match->match_len);
+    if(!tmp_str)
         hres = E_OUTOFMEMORY;
+    argv[0] = jsval_string(tmp_str);
 
     if(SUCCEEDED(hres)) {
-        for(i=0; i < parens_cnt; i++) {
-            arg = get_arg(&dp,i+1);
-            V_VT(arg) = VT_BSTR;
-            V_BSTR(arg) = SysAllocStringLen(parens[i].str, parens[i].len);
-            if(!V_BSTR(arg)) {
+        for(i=0; i < match->paren_count; i++) {
+            if(match->parens[i].index != -1)
+                tmp_str = jsstr_substr(str, match->parens[i].index, match->parens[i].length);
+            else
+                tmp_str = jsstr_empty();
+            if(!tmp_str) {
                hres = E_OUTOFMEMORY;
                break;
             }
+            argv[i+1] = jsval_string(tmp_str);
         }
     }
 
     if(SUCCEEDED(hres)) {
-        arg = get_arg(&dp,parens_cnt+1);
-        V_VT(arg) = VT_I4;
-        V_I4(arg) = match->str - str;
-
-        arg = get_arg(&dp,parens_cnt+2);
-        V_VT(arg) = VT_BSTR;
-        V_BSTR(arg) = SysAllocString(str);
-        if(!V_BSTR(arg))
-            hres = E_OUTOFMEMORY;
+        argv[match->paren_count+1] = jsval_number(match->cp-str->str - match->match_len);
+        argv[match->paren_count+2] = jsval_string(str);
     }
 
     if(SUCCEEDED(hres))
-        hres = jsdisp_call_value(func, DISPATCH_METHOD, &dp, &var, ei, caller);
+        hres = jsdisp_call_value(func, NULL, DISPATCH_METHOD, argc, argv, &val);
 
-    for(i=0; i < parens_cnt+3; i++) {
-        if(i != parens_cnt+1)
-            SysFreeString(V_BSTR(get_arg(&dp,i)));
-    }
-    heap_free(args);
+    for(i=0; i <= match->paren_count; i++)
+        jsstr_release(get_string(argv[i]));
+    heap_free(argv);
 
     if(FAILED(hres))
         return hres;
 
-    hres = to_string(ctx, &var, ei, ret);
-    VariantClear(&var);
+    hres = to_string(ctx, val, ret);
+    jsval_release(val);
     return hres;
 }
 
 /* ECMA-262 3rd Edition    15.5.4.11 */
-static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
+static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    const WCHAR *str;
-    DWORD parens_cnt = 0, parens_size=0, rep_len=0, length;
-    BSTR rep_str = NULL, match_str = NULL, ret_str, val_str;
-    DispatchEx *rep_func = NULL, *regexp = NULL;
-    match_result_t *parens = NULL, match = {NULL,0}, **parens_ptr = &parens;
+    DWORD rep_len=0;
+    jsstr_t *rep_str = NULL, *match_str = NULL, *str;
+    jsdisp_t *rep_func = NULL, *regexp = NULL;
+    match_state_t *match = NULL, last_match = {0};
     strbuf_t ret = {NULL,0,0};
-    DWORD re_flags = REM_NO_CTX_UPDATE;
-    VARIANT *arg_var;
+    DWORD re_flags = REM_NO_CTX_UPDATE|REM_ALLOC_RESULT;
     HRESULT hres = S_OK;
 
     TRACE("\n");
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(!arg_cnt(dp)) {
-        if(retv) {
-            if(!val_str) {
-                val_str = SysAllocStringLen(str, length);
-                if(!val_str)
-                    return E_OUTOFMEMORY;
-            }
-
-            V_VT(retv) = VT_BSTR;
-            V_BSTR(retv) = val_str;
-        }
+    if(!argc) {
+        if(r)
+            *r = jsval_string(str);
+        else
+            jsstr_release(str);
         return S_OK;
     }
 
-    arg_var = get_arg(dp, 0);
-    switch(V_VT(arg_var)) {
-    case VT_DISPATCH:
-        regexp = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg_var));
-        if(regexp) {
-            if(is_class(regexp, JSCLASS_REGEXP)) {
-                break;
-            }else {
-                jsdisp_release(regexp);
-                regexp = NULL;
-            }
+    if(is_object_instance(argv[0])) {
+        regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
+        if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
+            jsdisp_release(regexp);
+            regexp = NULL;
         }
+    }
 
-    default:
-        hres = to_string(ctx, arg_var, ei, &match_str);
+    if(!regexp) {
+        hres = to_string(ctx, argv[0], &match_str);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
     }
 
-    if(arg_cnt(dp) >= 2) {
-        arg_var = get_arg(dp,1);
-        switch(V_VT(arg_var)) {
-        case VT_DISPATCH:
-            rep_func = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg_var));
-            if(rep_func) {
-                if(is_class(rep_func, JSCLASS_FUNCTION)) {
-                    break;
-                }else {
-                    jsdisp_release(rep_func);
-                    rep_func = NULL;
-                }
+    if(argc >= 2) {
+        if(is_object_instance(argv[1])) {
+            rep_func = iface_to_jsdisp((IUnknown*)get_object(argv[1]));
+            if(rep_func && !is_class(rep_func, JSCLASS_FUNCTION)) {
+                jsdisp_release(rep_func);
+                rep_func = NULL;
             }
+        }
 
-        default:
-            hres = to_string(ctx, arg_var, ei, &rep_str);
-            if(FAILED(hres))
-                break;
-
-            rep_len = SysStringLen(rep_str);
-            if(!strchrW(rep_str, '$'))
-                parens_ptr = NULL;
+        if(!rep_func) {
+            hres = to_string(ctx, argv[1], &rep_str);
+            if(SUCCEEDED(hres))
+                rep_len = jsstr_length(rep_str);
         }
     }
 
     if(SUCCEEDED(hres)) {
-        const WCHAR *cp, *ecp;
-
-        cp = ecp = str;
+        const WCHAR *ecp = str->str;
 
         while(1) {
             if(regexp) {
-                hres = regexp_match_next(ctx, regexp, re_flags, str, length, &cp, parens_ptr,
-                        &parens_size, &parens_cnt, &match);
-                re_flags |= REM_CHECK_GLOBAL;
+                hres = regexp_match_next(ctx, regexp, re_flags, str, &match);
+                re_flags = (re_flags | REM_CHECK_GLOBAL) & (~REM_ALLOC_RESULT);
 
                 if(hres == S_FALSE) {
                     hres = S_OK;
@@ -868,32 +779,41 @@ static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DI
                 }
                 if(FAILED(hres))
                     break;
+
+                last_match.cp = match->cp;
+                last_match.match_len = match->match_len;
             }else {
-                match.str = strstrW(cp, match_str);
-                if(!match.str)
+                if(re_flags & REM_ALLOC_RESULT) {
+                    re_flags &= ~REM_ALLOC_RESULT;
+                    match = &last_match;
+                    match->cp = str->str;
+                }
+
+                match->cp = strstrW(match->cp, match_str->str);
+                if(!match->cp)
                     break;
-                match.len = SysStringLen(match_str);
-                cp = match.str+match.len;
+                match->match_len = jsstr_length(match_str);
+                match->cp += match->match_len;
             }
 
-            hres = strbuf_append(&ret, ecp, match.str-ecp);
-            ecp = match.str+match.len;
+            hres = strbuf_append(&ret, ecp, match->cp-ecp-match->match_len);
+            ecp = match->cp;
             if(FAILED(hres))
                 break;
 
             if(rep_func) {
-                BSTR cstr;
+                jsstr_t *cstr;
 
-                hres = rep_call(ctx, rep_func, str, &match, parens, parens_cnt, &cstr, ei, caller);
+                hres = rep_call(ctx, rep_func, str, match, &cstr);
                 if(FAILED(hres))
                     break;
 
-                hres = strbuf_append(&ret, cstr, SysStringLen(cstr));
-                SysFreeString(cstr);
+                hres = strbuf_append(&ret, cstr->str, jsstr_length(cstr));
+                jsstr_release(cstr);
                 if(FAILED(hres))
                     break;
             }else if(rep_str && regexp) {
-                const WCHAR *ptr = rep_str, *ptr2;
+                const WCHAR *ptr = rep_str->str, *ptr2;
 
                 while((ptr2 = strchrW(ptr, '$'))) {
                     hres = strbuf_append(&ret, ptr, ptr2-ptr);
@@ -906,15 +826,15 @@ static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DI
                         ptr = ptr2+2;
                         break;
                     case '&':
-                        hres = strbuf_append(&ret, match.str, match.len);
+                        hres = strbuf_append(&ret, match->cp-match->match_len, match->match_len);
                         ptr = ptr2+2;
                         break;
                     case '`':
-                        hres = strbuf_append(&ret, str, match.str-str);
+                        hres = strbuf_append(&ret, str->str, match->cp-str->str-match->match_len);
                         ptr = ptr2+2;
                         break;
                     case '\'':
-                        hres = strbuf_append(&ret, ecp, (str+length)-ecp);
+                        hres = strbuf_append(&ret, ecp, (str->str+jsstr_length(str))-ecp);
                         ptr = ptr2+2;
                         break;
                     default: {
@@ -927,10 +847,10 @@ static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DI
                         }
 
                         idx = ptr2[1] - '0';
-                        if(isdigitW(ptr2[2]) && idx*10 + (ptr2[2]-'0') <= parens_cnt) {
+                        if(isdigitW(ptr2[2]) && idx*10 + (ptr2[2]-'0') <= match->paren_count) {
                             idx = idx*10 + (ptr[2]-'0');
                             ptr = ptr2+3;
-                        }else if(idx && idx <= parens_cnt) {
+                        }else if(idx && idx <= match->paren_count) {
                             ptr = ptr2+2;
                         }else {
                             hres = strbuf_append(&ret, ptr2, 1);
@@ -938,7 +858,9 @@ static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DI
                             break;
                         }
 
-                        hres = strbuf_append(&ret, parens[idx-1].str, parens[idx-1].len);
+                        if(match->parens[idx-1].index != -1)
+                            hres = strbuf_append(&ret, str->str+match->parens[idx-1].index,
+                                    match->parens[idx-1].length);
                     }
                     }
 
@@ -947,11 +869,11 @@ static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DI
                 }
 
                 if(SUCCEEDED(hres))
-                    hres = strbuf_append(&ret, ptr, (rep_str+rep_len)-ptr);
+                    hres = strbuf_append(&ret, ptr, (rep_str->str+rep_len)-ptr);
                 if(FAILED(hres))
                     break;
             }else if(rep_str) {
-                hres = strbuf_append(&ret, rep_str, rep_len);
+                hres = strbuf_append(&ret, rep_str->str, rep_len);
                 if(FAILED(hres))
                     break;
             }else {
@@ -961,133 +883,126 @@ static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DI
                 if(FAILED(hres))
                     break;
             }
+
+            if(!regexp)
+                break;
+            else if(!match->match_len)
+                match->cp++;
         }
 
         if(SUCCEEDED(hres))
-            hres = strbuf_append(&ret, ecp, (str+length)-ecp);
+            hres = strbuf_append(&ret, ecp, str->str+jsstr_length(str)-ecp);
     }
 
     if(rep_func)
         jsdisp_release(rep_func);
-    SysFreeString(rep_str);
-    SysFreeString(match_str);
-    heap_free(parens);
-
-    if(SUCCEEDED(hres) && match.str && regexp) {
-        if(!val_str)
-            val_str = SysAllocStringLen(str, length);
-        if(val_str) {
-            SysFreeString(ctx->last_match);
-            ctx->last_match = val_str;
-            val_str = NULL;
-            ctx->last_match_index = match.str-str;
-            ctx->last_match_length = match.len;
-        }else {
-            hres = E_OUTOFMEMORY;
-        }
+    if(rep_str)
+        jsstr_release(rep_str);
+    if(match_str)
+        jsstr_release(match_str);
+    if(regexp)
+        heap_free(match);
+
+    if(SUCCEEDED(hres) && last_match.cp && regexp) {
+        jsstr_release(ctx->last_match);
+        ctx->last_match = jsstr_addref(str);
+        ctx->last_match_index = last_match.cp-str->str-last_match.match_len;
+        ctx->last_match_length = last_match.match_len;
     }
 
     if(regexp)
         jsdisp_release(regexp);
-    SysFreeString(val_str);
+    jsstr_release(str);
+
+    if(SUCCEEDED(hres) && r) {
+        jsstr_t *ret_str;
 
-    if(SUCCEEDED(hres) && retv) {
-        ret_str = SysAllocStringLen(ret.buf, ret.len);
+        ret_str = jsstr_alloc_len(ret.buf, ret.len);
         if(!ret_str)
             return E_OUTOFMEMORY;
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret_str;
-        TRACE("= %s\n", debugstr_w(ret_str));
+        TRACE("= %s\n", debugstr_jsstr(ret_str));
+        *r = jsval_string(ret_str);
     }
 
     heap_free(ret.buf);
     return hres;
 }
 
-static HRESULT String_search(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_search(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    DispatchEx *regexp = NULL;
-    const WCHAR *str, *cp;
-    match_result_t match;
-    VARIANT *arg;
-    DWORD length;
-    BSTR val_str;
+    jsdisp_t *regexp = NULL;
+    jsstr_t *str;
+    match_state_t match, *match_ptr = &match;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(!arg_cnt(dp)) {
-        if(retv)
-            V_VT(retv) = VT_NULL;
-        SysFreeString(val_str);
+    if(!argc) {
+        if(r)
+            *r = jsval_null();
+        jsstr_release(str);
         return S_OK;
     }
 
-    arg = get_arg(dp,0);
-    if(V_VT(arg) == VT_DISPATCH) {
-        regexp = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg));
-        if(regexp) {
-            if(!is_class(regexp, JSCLASS_REGEXP)) {
-                jsdisp_release(regexp);
-                regexp = NULL;
-            }
+    if(is_object_instance(argv[0])) {
+        regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
+        if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
+            jsdisp_release(regexp);
+            regexp = NULL;
         }
     }
 
     if(!regexp) {
-        hres = create_regexp_var(ctx, arg, NULL, &regexp);
+        hres = create_regexp_var(ctx, argv[0], NULL, &regexp);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
     }
 
-    cp = str;
-    hres = regexp_match_next(ctx, regexp, REM_RESET_INDEX, str, length, &cp, NULL, NULL, NULL, &match);
-    SysFreeString(val_str);
+    match.cp = str->str;
+    hres = regexp_match_next(ctx, regexp, REM_RESET_INDEX|REM_NO_PARENS, str, &match_ptr);
+    jsstr_release(str);
     jsdisp_release(regexp);
     if(FAILED(hres))
         return hres;
 
-    if(retv) {
-        V_VT(retv) = VT_I4;
-        V_I4(retv) = hres == S_OK ? match.str-str : -1;
-    }
+    if(r)
+        *r = jsval_number(hres == S_OK ? match.cp-match.match_len-str->str : -1);
     return S_OK;
 }
 
 /* ECMA-262 3rd Edition    15.5.4.13 */
-static HRESULT String_slice(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_slice(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    const WCHAR *str;
-    BSTR val_str;
-    DWORD length;
-    INT start=0, end;
-    VARIANT v;
+    int start=0, end, length;
+    jsstr_t *str;
+    double d;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(arg_cnt(dp)) {
-        hres = to_integer(ctx, get_arg(dp,0), ei, &v);
+    length = jsstr_length(str);
+    if(argc) {
+        hres = to_integer(ctx, argv[0], &d);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
 
-        if(V_VT(&v) == VT_I4) {
-            start = V_I4(&v);
+        if(is_int32(d)) {
+            start = d;
             if(start < 0) {
                 start = length + start;
                 if(start < 0)
@@ -1095,22 +1010,20 @@ static HRESULT String_slice(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
             }else if(start > length) {
                 start = length;
             }
-        }else {
-            start = V_R8(&v) < 0.0 ? 0 : length;
+        }else if(d > 0) {
+            start = length;
         }
-    }else {
-        start = 0;
     }
 
-    if(arg_cnt(dp) >= 2) {
-        hres = to_integer(ctx, get_arg(dp,1), ei, &v);
+    if(argc >= 2) {
+        hres = to_integer(ctx, argv[1], &d);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
 
-        if(V_VT(&v) == VT_I4) {
-            end = V_I4(&v);
+        if(is_int32(d)) {
+            end = d;
             if(end < 0) {
                 end = length + end;
                 if(end < 0)
@@ -1119,7 +1032,7 @@ static HRESULT String_slice(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
                 end = length;
             }
         }else {
-            end = V_R8(&v) < 0.0 ? 0 : length;
+            end = d < 0.0 ? 0 : length;
         }
     }else {
         end = length;
@@ -1128,81 +1041,79 @@ static HRESULT String_slice(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
     if(end < start)
         end = start;
 
-    if(retv) {
-        BSTR retstr = SysAllocStringLen(str+start, end-start);
+    if(r) {
+        jsstr_t *retstr = jsstr_substr(str, start, end-start);
         if(!retstr) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return E_OUTOFMEMORY;
         }
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = retstr;
+        *r = jsval_string(retstr);
     }
 
-    SysFreeString(val_str);
+    jsstr_release(str);
     return S_OK;
 }
 
-static HRESULT String_small(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_small(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR smalltagW[] = {'S','M','A','L','L',0};
-    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, smalltagW);
+    return do_attributeless_tag_format(ctx, jsthis, r, smalltagW);
 }
 
-static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    match_result_t *match_result = NULL;
-    DWORD length, match_cnt, i, match_len = 0;
-    const WCHAR *str, *ptr, *ptr2;
-    BOOL use_regexp = FALSE;
-    VARIANT *arg, var;
-    DispatchEx *array;
-    BSTR val_str, match_str = NULL;
+    match_state_t match_result, *match_ptr = &match_result;
+    DWORD length, i, match_len = 0;
+    const WCHAR *ptr, *ptr2;
+    unsigned limit = UINT32_MAX;
+    jsdisp_t *array, *regexp = NULL;
+    jsstr_t *str, *match_str = NULL, *tmp_str;
     HRESULT hres;
 
     TRACE("\n");
 
-    if(arg_cnt(dp) != 1) {
-        FIXME("unsupported args\n");
+    if(argc != 1 && argc != 2) {
+        FIXME("unsupported argc %u\n", argc);
         return E_NOTIMPL;
     }
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    arg = get_arg(dp, 0);
-    switch(V_VT(arg)) {
-    case VT_DISPATCH: {
-        DispatchEx *regexp;
+    length = jsstr_length(str);
+
+    if(argc > 1 && !is_undefined(argv[1])) {
+        hres = to_uint32(ctx, argv[1], &limit);
+        if(FAILED(hres)) {
+            jsstr_release(str);
+            return hres;
+        }
+    }
 
-        regexp = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg));
+    if(is_object_instance(argv[0])) {
+        regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
         if(regexp) {
-            if(is_class(regexp, JSCLASS_REGEXP)) {
-                use_regexp = TRUE;
-                hres = regexp_match(ctx, regexp, str, length, TRUE, &match_result, &match_cnt);
+            if(!is_class(regexp, JSCLASS_REGEXP)) {
                 jsdisp_release(regexp);
-                if(FAILED(hres)) {
-                    SysFreeString(val_str);
-                    return hres;
-                }
-                break;
+                regexp = NULL;
             }
-            jsdisp_release(regexp);
         }
     }
-    default:
-        hres = to_string(ctx, arg, ei, &match_str);
+
+    if(!regexp) {
+        hres = to_string(ctx, argv[0], &match_str);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
 
-        match_len = SysStringLen(match_str);
+        match_len = jsstr_length(match_str);
         if(!match_len) {
-            SysFreeString(match_str);
+            jsstr_release(match_str);
             match_str = NULL;
         }
     }
@@ -1210,14 +1121,16 @@ static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
     hres = create_array(ctx, 0, &array);
 
     if(SUCCEEDED(hres)) {
-        ptr = str;
-        for(i=0;; i++) {
-            if(use_regexp) {
-                if(i == match_cnt)
+        ptr = str->str;
+        match_result.cp = str->str;
+        for(i=0; i<limit; i++) {
+            if(regexp) {
+                hres = regexp_match_next(ctx, regexp, REM_NO_PARENS, str, &match_ptr);
+                if(hres != S_OK)
                     break;
-                ptr2 = match_result[i].str;
+                ptr2 = match_result.cp - match_result.match_len;
             }else if(match_str) {
-                ptr2 = strstrW(ptr, match_str);
+                ptr2 = strstrW(ptr, match_str->str);
                 if(!ptr2)
                     break;
             }else {
@@ -1226,20 +1139,19 @@ static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
                 ptr2 = ptr+1;
             }
 
-            V_VT(&var) = VT_BSTR;
-            V_BSTR(&var) = SysAllocStringLen(ptr, ptr2-ptr);
-            if(!V_BSTR(&var)) {
+            tmp_str = jsstr_alloc_len(ptr, ptr2-ptr);
+            if(!tmp_str) {
                 hres = E_OUTOFMEMORY;
                 break;
             }
 
-            hres = jsdisp_propput_idx(array, i, &var, ei, sp);
-            SysFreeString(V_BSTR(&var));
+            hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
+            jsstr_release(tmp_str);
             if(FAILED(hres))
                 break;
 
-            if(use_regexp)
-                ptr = match_result[i].str + match_result[i].len;
+            if(regexp)
+                ptr = match_result.cp;
             else if(match_str)
                 ptr = ptr2 + match_len;
             else
@@ -1247,101 +1159,87 @@ static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
         }
     }
 
-    if(SUCCEEDED(hres) && (match_str || use_regexp)) {
-        DWORD len = (str+length) - ptr;
+    if(SUCCEEDED(hres) && (match_str || regexp) && i<limit) {
+        DWORD len = (str->str+length) - ptr;
 
         if(len || match_str) {
-            V_VT(&var) = VT_BSTR;
-            V_BSTR(&var) = SysAllocStringLen(ptr, len);
+            tmp_str = jsstr_alloc_len(ptr, len);
 
-            if(V_BSTR(&var)) {
-                hres = jsdisp_propput_idx(array, i, &var, ei, sp);
-                SysFreeString(V_BSTR(&var));
+            if(tmp_str) {
+                hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
+                jsstr_release(tmp_str);
             }else {
                 hres = E_OUTOFMEMORY;
             }
         }
     }
 
-    SysFreeString(match_str);
-    SysFreeString(val_str);
-    heap_free(match_result);
+    if(regexp)
+        jsdisp_release(regexp);
+    if(match_str)
+        jsstr_release(match_str);
+    jsstr_release(str);
 
-    if(SUCCEEDED(hres) && retv) {
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(array);
-    }else {
+    if(SUCCEEDED(hres) && r)
+        *r = jsval_obj(array);
+    else
         jsdisp_release(array);
-    }
 
     return hres;
 }
 
-static HRESULT String_strike(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_strike(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR striketagW[] = {'S','T','R','I','K','E',0};
-    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, striketagW);
+    return do_attributeless_tag_format(ctx, jsthis, r, striketagW);
 }
 
-static HRESULT String_sub(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_sub(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR subtagW[] = {'S','U','B',0};
-    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, subtagW);
+    return do_attributeless_tag_format(ctx, jsthis, r, subtagW);
 }
 
 /* ECMA-262 3rd Edition    15.5.4.15 */
-static HRESULT String_substring(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_substring(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    const WCHAR *str;
-    BSTR val_str;
-    INT start=0, end;
-    DWORD length;
-    VARIANT v;
+    INT start=0, end, length;
+    jsstr_t *str;
+    double d;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(arg_cnt(dp) >= 1) {
-        hres = to_integer(ctx, get_arg(dp,0), ei, &v);
+    length = jsstr_length(str);
+    if(argc >= 1) {
+        hres = to_integer(ctx, argv[0], &d);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
 
-        if(V_VT(&v) == VT_I4) {
-            start = V_I4(&v);
-            if(start < 0)
-                start = 0;
-            else if(start >= length)
-                start = length;
-        }else {
-            start = V_R8(&v) < 0.0 ? 0 : length;
-        }
+        if(d >= 0)
+            start = is_int32(d) ? min(length, d) : length;
     }
 
-    if(arg_cnt(dp) >= 2) {
-        hres = to_integer(ctx, get_arg(dp,1), ei, &v);
+    if(argc >= 2) {
+        hres = to_integer(ctx, argv[1], &d);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
 
-        if(V_VT(&v) == VT_I4) {
-            end = V_I4(&v);
-            if(end < 0)
-                end = 0;
-            else if(end > length)
-                end = length;
-        }else {
-            end = V_R8(&v) < 0.0 ? 0 : length;
-        }
+        if(d >= 0)
+            end = is_int32(d) ? min(length, d) : length;
+        else
+            end = 0;
     }else {
         end = length;
     }
@@ -1352,175 +1250,160 @@ static HRESULT String_substring(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
         end = tmp;
     }
 
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = SysAllocStringLen(str+start, end-start);
-        if(!V_BSTR(retv)) {
-            SysFreeString(val_str);
-            return E_OUTOFMEMORY;
-        }
+    if(r) {
+        jsstr_t *ret = jsstr_substr(str, start, end-start);
+        if(ret)
+            *r = jsval_string(ret);
+        else
+            hres = E_OUTOFMEMORY;
     }
-    SysFreeString(val_str);
-    return S_OK;
+    jsstr_release(str);
+    return hres;
 }
 
 /* ECMA-262 3rd Edition    B.2.3 */
-static HRESULT String_substr(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_substr(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    BSTR val_str;
-    const WCHAR *str;
-    INT start=0, len;
-    DWORD length;
-    VARIANT v;
+    int start=0, len, length;
+    jsstr_t *str;
+    double d;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(arg_cnt(dp) >= 1) {
-        hres = to_integer(ctx, get_arg(dp,0), ei, &v);
+    length = jsstr_length(str);
+    if(argc >= 1) {
+        hres = to_integer(ctx, argv[0], &d);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
 
-        if(V_VT(&v) == VT_I4) {
-            start = V_I4(&v);
-            if(start < 0)
-                start = 0;
-            else if(start >= length)
-                start = length;
-        }else {
-            start = V_R8(&v) < 0.0 ? 0 : length;
-        }
+        if(d >= 0)
+            start = is_int32(d) ? min(length, d) : length;
     }
 
-    if(arg_cnt(dp) >= 2) {
-        hres = to_integer(ctx, get_arg(dp,1), ei, &v);
+    if(argc >= 2) {
+        hres = to_integer(ctx, argv[1], &d);
         if(FAILED(hres)) {
-            SysFreeString(val_str);
+            jsstr_release(str);
             return hres;
         }
 
-        if(V_VT(&v) == VT_I4) {
-            len = V_I4(&v);
-            if(len < 0)
-                len = 0;
-            else if(len > length-start)
-                len = length-start;
-        }else {
-            len = V_R8(&v) < 0.0 ? 0 : length-start;
-        }
+        if(d >= 0.0)
+            len = is_int32(d) ? min(length-start, d) : length-start;
+        else
+            len = 0;
     }else {
         len = length-start;
     }
 
     hres = S_OK;
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = SysAllocStringLen(str+start, len);
-        if(!V_BSTR(retv))
+    if(r) {
+        jsstr_t *ret = jsstr_substr(str, start, len);
+        if(ret)
+            *r = jsval_string(ret);
+        else
             hres = E_OUTOFMEMORY;
     }
 
-    SysFreeString(val_str);
+    jsstr_release(str);
     return hres;
 }
 
-static HRESULT String_sup(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_sup(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     static const WCHAR suptagW[] = {'S','U','P',0};
-    return do_attributeless_tag_format(ctx, jsthis, flags, dp, retv, ei, sp, suptagW);
+    return do_attributeless_tag_format(ctx, jsthis, r, suptagW);
 }
 
-static HRESULT String_toLowerCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_toLowerCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    const WCHAR* str;
-    DWORD length;
-    BSTR val_str;
+    jsstr_t *str;
     HRESULT  hres;
 
     TRACE("\n");
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(retv) {
-        if(!val_str) {
-            val_str = SysAllocStringLen(str, length);
-            if(!val_str)
-                return E_OUTOFMEMORY;
-        }
+    if(r) {
+        jsstr_t *ret;
 
-        strlwrW(val_str);
+        ret = jsstr_alloc_buf(jsstr_length(str));
+        if(!ret) {
+            jsstr_release(str);
+            return E_OUTOFMEMORY;
+        }
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = val_str;
+        jsstr_flush(str, ret->str);
+        strlwrW(ret->str);
+        *r = jsval_string(ret);
     }
-    else SysFreeString(val_str);
+    jsstr_release(str);
     return S_OK;
 }
 
-static HRESULT String_toUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_toUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
-    const WCHAR* str;
-    DWORD length;
-    BSTR val_str;
+    jsstr_t *str;
     HRESULT hres;
 
     TRACE("\n");
 
-    hres = get_string_val(ctx, jsthis, ei, &str, &length, &val_str);
+    hres = get_string_val(ctx, jsthis, &str);
     if(FAILED(hres))
         return hres;
 
-    if(retv) {
-        if(!val_str) {
-            val_str = SysAllocStringLen(str, length);
-            if(!val_str)
-                return E_OUTOFMEMORY;
-        }
+    if(r) {
+        jsstr_t *ret;
 
-        struprW(val_str);
+        ret = jsstr_alloc_buf(jsstr_length(str));
+        if(!ret) {
+            jsstr_release(str);
+            return E_OUTOFMEMORY;
+        }
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = val_str;
+        jsstr_flush(str, ret->str);
+        struprW(ret->str);
+        *r = jsval_string(ret);
     }
-    else SysFreeString(val_str);
+    jsstr_release(str);
     return S_OK;
 }
 
-static HRESULT String_toLocaleLowerCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_toLocaleLowerCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT String_toLocaleUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_toLocaleUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT String_localeCompare(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_localeCompare(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     FIXME("\n");
     return E_NOTIMPL;
 }
 
-static HRESULT String_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT String_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     StringInstance *This = string_from_vdisp(jsthis);
 
@@ -1528,14 +1411,9 @@ static HRESULT String_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
 
     switch(flags) {
     case INVOKE_FUNC:
-        return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL);
+        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
     case DISPATCH_PROPERTYGET: {
-        BSTR str = SysAllocString(This->str);
-        if(!str)
-            return E_OUTOFMEMORY;
-
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = str;
+        *r = jsval_string(jsstr_addref(This->str));
         break;
     }
     default:
@@ -1546,14 +1424,43 @@ static HRESULT String_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISP
     return S_OK;
 }
 
-static void String_destructor(DispatchEx *dispex)
+static void String_destructor(jsdisp_t *dispex)
 {
     StringInstance *This = (StringInstance*)dispex;
 
-    heap_free(This->str);
+    jsstr_release(This->str);
     heap_free(This);
 }
 
+static unsigned String_idx_length(jsdisp_t *jsdisp)
+{
+    StringInstance *string = (StringInstance*)jsdisp;
+
+    /*
+     * NOTE: For invoke version < 2, indexed array is not implemented at all.
+     * Newer jscript.dll versions implement it on string type, not class,
+     * which is not how it should work according to spec. IE9 implements it
+     * properly, but it uses its own JavaScript engine inside MSHTML. We
+     * implement it here, but in the way IE9 and spec work.
+     */
+    return string->dispex.ctx->version < 2 ? 0 : jsstr_length(string->str);
+}
+
+static HRESULT String_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r)
+{
+    StringInstance *string = (StringInstance*)jsdisp;
+    jsstr_t *ret;
+
+    ret = jsstr_substr(string->str, idx, 1);
+    if(!ret)
+        return E_OUTOFMEMORY;
+
+    TRACE("%p[%u] = %s\n", string, idx, debugstr_jsstr(ret));
+
+    *r = jsval_string(ret);
+    return S_OK;
+}
+
 static const builtin_prop_t String_props[] = {
     {anchorW,                String_anchor,                PROPF_METHOD|1},
     {bigW,                   String_big,                   PROPF_METHOD},
@@ -1599,39 +1506,54 @@ static const builtin_info_t String_info = {
     NULL
 };
 
+static const builtin_prop_t StringInst_props[] = {
+    {lengthW,                String_length,                0}
+};
+
+static const builtin_info_t StringInst_info = {
+    JSCLASS_STRING,
+    {NULL, String_value, 0},
+    sizeof(StringInst_props)/sizeof(*StringInst_props),
+    StringInst_props,
+    String_destructor,
+    NULL,
+    String_idx_length,
+    String_idx_get
+};
+
 /* ECMA-262 3rd Edition    15.5.3.2 */
 static HRESULT StringConstr_fromCharCode(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
-        DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+        unsigned argc, jsval_t *argv, jsval_t *r)
 {
     DWORD i, code;
-    BSTR ret;
+    jsstr_t *ret;
     HRESULT hres;
 
-    ret = SysAllocStringLen(NULL, arg_cnt(dp));
+    TRACE("\n");
+
+    ret = jsstr_alloc_buf(argc);
     if(!ret)
         return E_OUTOFMEMORY;
 
-    for(i=0; i<arg_cnt(dp); i++) {
-        hres = to_uint32(ctx, get_arg(dp, i), ei, &code);
+    for(i=0; i<argc; i++) {
+        hres = to_uint32(ctx, argv[i], &code);
         if(FAILED(hres)) {
-            SysFreeString(ret);
+            jsstr_release(ret);
             return hres;
         }
 
-        ret[i] = code;
-    }
-
-    if(retv) {
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = ret;
+        ret->str[i] = code;
     }
-    else SysFreeString(ret);
 
+    if(r)
+        *r = jsval_string(ret);
+    else
+        jsstr_release(ret);
     return S_OK;
 }
 
-static HRESULT StringConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+static HRESULT StringConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
 {
     HRESULT hres;
 
@@ -1639,43 +1561,39 @@ static HRESULT StringConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
 
     switch(flags) {
     case INVOKE_FUNC: {
-        BSTR str;
+        jsstr_t *str;
 
-        if(arg_cnt(dp)) {
-            hres = to_string(ctx, get_arg(dp, 0), ei, &str);
+        if(argc) {
+            hres = to_string(ctx, argv[0], &str);
             if(FAILED(hres))
                 return hres;
         }else {
-            str = SysAllocStringLen(NULL, 0);
-            if(!str)
-                return E_OUTOFMEMORY;
+            str = jsstr_empty();
         }
 
-        V_VT(retv) = VT_BSTR;
-        V_BSTR(retv) = str;
+        *r = jsval_string(str);
         break;
     }
     case DISPATCH_CONSTRUCT: {
-        DispatchEx *ret;
+        jsdisp_t *ret;
 
-        if(arg_cnt(dp)) {
-            BSTR str;
+        if(argc) {
+            jsstr_t *str;
 
-            hres = to_string(ctx, get_arg(dp, 0), ei, &str);
+            hres = to_string(ctx, argv[0], &str);
             if(FAILED(hres))
                 return hres;
 
-            hres = create_string(ctx, str, SysStringLen(str), &ret);
-            SysFreeString(str);
+            hres = create_string(ctx, str, &ret);
+            jsstr_release(str);
         }else {
-            hres = create_string(ctx, NULL, 0, &ret);
+            hres = create_string(ctx, jsstr_empty(), &ret);
         }
 
         if(FAILED(hres))
             return hres;
 
-        V_VT(retv) = VT_DISPATCH;
-        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(ret);
+        *r = jsval_obj(ret);
         break;
     }
 
@@ -1687,7 +1605,7 @@ static HRESULT StringConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags
     return S_OK;
 }
 
-static HRESULT string_alloc(script_ctx_t *ctx, DispatchEx *object_prototype, StringInstance **ret)
+static HRESULT string_alloc(script_ctx_t *ctx, jsdisp_t *object_prototype, jsstr_t *str, StringInstance **ret)
 {
     StringInstance *string;
     HRESULT hres;
@@ -1699,12 +1617,13 @@ static HRESULT string_alloc(script_ctx_t *ctx, DispatchEx *object_prototype, Str
     if(object_prototype)
         hres = init_dispex(&string->dispex, ctx, &String_info, object_prototype);
     else
-        hres = init_dispex_from_constr(&string->dispex, ctx, &String_info, ctx->string_constr);
+        hres = init_dispex_from_constr(&string->dispex, ctx, &StringInst_info, ctx->string_constr);
     if(FAILED(hres)) {
         heap_free(string);
         return hres;
     }
 
+    string->str = jsstr_addref(str);
     *ret = string;
     return S_OK;
 }
@@ -1722,46 +1641,33 @@ static const builtin_info_t StringConstr_info = {
     NULL
 };
 
-HRESULT create_string_constr(script_ctx_t *ctx, DispatchEx *object_prototype, DispatchEx **ret)
+HRESULT create_string_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
 {
     StringInstance *string;
     HRESULT hres;
 
     static const WCHAR StringW[] = {'S','t','r','i','n','g',0};
 
-    hres = string_alloc(ctx, object_prototype, &string);
+    hres = string_alloc(ctx, object_prototype, jsstr_empty(), &string);
     if(FAILED(hres))
         return hres;
 
-    hres = create_builtin_function(ctx, StringConstr_value, StringW, &StringConstr_info,
+    hres = create_builtin_constructor(ctx, StringConstr_value, StringW, &StringConstr_info,
             PROPF_CONSTR|1, &string->dispex, ret);
 
     jsdisp_release(&string->dispex);
     return hres;
 }
 
-HRESULT create_string(script_ctx_t *ctx, const WCHAR *str, DWORD len, DispatchEx **ret)
+HRESULT create_string(script_ctx_t *ctx, jsstr_t *str, jsdisp_t **ret)
 {
     StringInstance *string;
     HRESULT hres;
 
-    hres = string_alloc(ctx, NULL, &string);
+    hres = string_alloc(ctx, NULL, str, &string);
     if(FAILED(hres))
         return hres;
 
-    if(len == -1)
-        len = strlenW(str);
-
-    string->length = len;
-    string->str = heap_alloc((len+1)*sizeof(WCHAR));
-    if(!string->str) {
-        jsdisp_release(&string->dispex);
-        return E_OUTOFMEMORY;
-    }
-
-    memcpy(string->str, str, len*sizeof(WCHAR));
-    string->str[len] = 0;
-
     *ret = &string->dispex;
     return S_OK;
 
diff --git a/reactos/dll/win32/jscript/vbarray.c b/reactos/dll/win32/jscript/vbarray.c
new file mode 100644 (file)
index 0000000..593d62f
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Copyright 2010 Piotr 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
+ */
+
+#include "jscript.h"
+
+#include <wine/debug.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(jscript);
+
+typedef struct {
+    jsdisp_t dispex;
+
+    SAFEARRAY *safearray;
+} VBArrayInstance;
+
+static const WCHAR dimensionsW[] = {'d','i','m','e','n','s','i','o','n','s',0};
+static const WCHAR getItemW[] = {'g','e','t','I','t','e','m',0};
+static const WCHAR lboundW[] = {'l','b','o','u','n','d',0};
+static const WCHAR toArrayW[] = {'t','o','A','r','r','a','y',0};
+static const WCHAR uboundW[] = {'u','b','o','u','n','d',0};
+
+static inline VBArrayInstance *vbarray_from_vdisp(vdisp_t *vdisp)
+{
+    return (VBArrayInstance*)vdisp->u.jsdisp;
+}
+
+static inline VBArrayInstance *vbarray_this(vdisp_t *jsthis)
+{
+    return is_vclass(jsthis, JSCLASS_VBARRAY) ? vbarray_from_vdisp(jsthis) : NULL;
+}
+
+static HRESULT VBArray_dimensions(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    VBArrayInstance *vbarray;
+
+    TRACE("\n");
+
+    vbarray = vbarray_this(vthis);
+    if(!vbarray)
+        return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
+
+    if(r)
+        *r = jsval_number(SafeArrayGetDim(vbarray->safearray));
+    return S_OK;
+}
+
+static HRESULT VBArray_getItem(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    VBArrayInstance *vbarray;
+    int i, *indexes;
+    VARIANT out;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    vbarray = vbarray_this(vthis);
+    if(!vbarray)
+        return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
+
+    if(argc < SafeArrayGetDim(vbarray->safearray))
+        return throw_range_error(ctx, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
+
+    indexes = heap_alloc(sizeof(int)*argc);
+    if(!indexes)
+        return E_OUTOFMEMORY;
+
+    for(i=0; i<argc; i++) {
+        hres = to_int32(ctx, argv[i], indexes+i);
+        if(FAILED(hres)) {
+            heap_free(indexes);
+            return hres;
+        }
+    }
+
+    hres = SafeArrayGetElement(vbarray->safearray, indexes, (void*)&out);
+    heap_free(indexes);
+    if(hres == DISP_E_BADINDEX)
+        return throw_range_error(ctx, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
+    else if(FAILED(hres))
+        return hres;
+
+    if(r) {
+        hres = variant_to_jsval(&out, r);
+        VariantClear(&out);
+    }
+    return hres;
+}
+
+static HRESULT VBArray_lbound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    VBArrayInstance *vbarray;
+    int dim;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    vbarray = vbarray_this(vthis);
+    if(!vbarray)
+        return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
+
+    if(argc) {
+        hres = to_int32(ctx, argv[0], &dim);
+        if(FAILED(hres))
+            return hres;
+    } else
+        dim = 1;
+
+    hres = SafeArrayGetLBound(vbarray->safearray, dim, &dim);
+    if(hres == DISP_E_BADINDEX)
+        return throw_range_error(ctx, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
+    else if(FAILED(hres))
+        return hres;
+
+    if(r)
+        *r = jsval_number(dim);
+    return S_OK;
+}
+
+static HRESULT VBArray_toArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    VBArrayInstance *vbarray;
+    jsdisp_t *array;
+    jsval_t val;
+    VARIANT *v;
+    int i, size = 1, ubound, lbound;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    vbarray = vbarray_this(vthis);
+    if(!vbarray)
+        return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
+
+    for(i=1; i<=SafeArrayGetDim(vbarray->safearray); i++) {
+        SafeArrayGetLBound(vbarray->safearray, i, &lbound);
+        SafeArrayGetUBound(vbarray->safearray, i, &ubound);
+        size *= ubound-lbound+1;
+    }
+
+    hres = SafeArrayAccessData(vbarray->safearray, (void**)&v);
+    if(FAILED(hres))
+        return hres;
+
+    hres = create_array(ctx, 0, &array);
+    if(FAILED(hres)) {
+        SafeArrayUnaccessData(vbarray->safearray);
+        return hres;
+    }
+
+    for(i=0; i<size; i++) {
+        hres = variant_to_jsval(v, &val);
+        if(SUCCEEDED(hres)) {
+            hres = jsdisp_propput_idx(array, i, val);
+            jsval_release(val);
+        }
+        if(FAILED(hres)) {
+            SafeArrayUnaccessData(vbarray->safearray);
+            jsdisp_release(array);
+            return hres;
+        }
+        v++;
+    }
+
+    SafeArrayUnaccessData(vbarray->safearray);
+
+    if(r)
+        *r = jsval_obj(array);
+    else
+        jsdisp_release(array);
+    return S_OK;
+}
+
+static HRESULT VBArray_ubound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    VBArrayInstance *vbarray;
+    int dim;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    vbarray = vbarray_this(vthis);
+    if(!vbarray)
+        return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
+
+    if(argc) {
+        hres = to_int32(ctx, argv[0], &dim);
+        if(FAILED(hres))
+            return hres;
+    } else
+        dim = 1;
+
+    hres = SafeArrayGetUBound(vbarray->safearray, dim, &dim);
+    if(hres == DISP_E_BADINDEX)
+        return throw_range_error(ctx, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
+    else if(FAILED(hres))
+        return hres;
+
+    if(r)
+        *r = jsval_number(dim);
+    return S_OK;
+}
+
+static HRESULT VBArray_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    FIXME("\n");
+
+    switch(flags) {
+        default:
+            FIXME("unimplemented flags %x\n", flags);
+            return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static void VBArray_destructor(jsdisp_t *dispex)
+{
+    VBArrayInstance *vbarray = (VBArrayInstance*)dispex;
+
+    SafeArrayDestroy(vbarray->safearray);
+    heap_free(vbarray);
+}
+
+static const builtin_prop_t VBArray_props[] = {
+    {dimensionsW,           VBArray_dimensions,         PROPF_METHOD},
+    {getItemW,              VBArray_getItem,            PROPF_METHOD|1},
+    {lboundW,               VBArray_lbound,             PROPF_METHOD},
+    {toArrayW,              VBArray_toArray,            PROPF_METHOD},
+    {uboundW,               VBArray_ubound,             PROPF_METHOD}
+};
+
+static const builtin_info_t VBArray_info = {
+    JSCLASS_VBARRAY,
+    {NULL, VBArray_value, 0},
+    sizeof(VBArray_props)/sizeof(*VBArray_props),
+    VBArray_props,
+    VBArray_destructor,
+    NULL
+};
+
+static HRESULT alloc_vbarray(script_ctx_t *ctx, jsdisp_t *object_prototype, VBArrayInstance **ret)
+{
+    VBArrayInstance *vbarray;
+    HRESULT hres;
+
+    vbarray = heap_alloc_zero(sizeof(VBArrayInstance));
+    if(!vbarray)
+        return E_OUTOFMEMORY;
+
+    if(object_prototype)
+        hres = init_dispex(&vbarray->dispex, ctx, &VBArray_info, object_prototype);
+    else
+        hres = init_dispex_from_constr(&vbarray->dispex, ctx, &VBArray_info, ctx->vbarray_constr);
+
+    if(FAILED(hres)) {
+        heap_free(vbarray);
+        return hres;
+    }
+
+    *ret = vbarray;
+    return S_OK;
+}
+
+static HRESULT VBArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
+        jsval_t *r)
+{
+    VBArrayInstance *vbarray;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    switch(flags) {
+    case DISPATCH_METHOD:
+        if(argc<1 || !is_variant(argv[0]) || V_VT(get_variant(argv[0])) != (VT_ARRAY|VT_VARIANT))
+            return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
+
+        return jsval_copy(argv[0], r);
+
+    case DISPATCH_CONSTRUCT:
+        if(argc<1 || !is_variant(argv[0]) || V_VT(get_variant(argv[0])) != (VT_ARRAY|VT_VARIANT))
+            return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
+
+        hres = alloc_vbarray(ctx, NULL, &vbarray);
+        if(FAILED(hres))
+            return hres;
+
+        hres = SafeArrayCopy(V_ARRAY(get_variant(argv[0])), &vbarray->safearray);
+        if(FAILED(hres)) {
+            jsdisp_release(&vbarray->dispex);
+            return hres;
+        }
+
+        *r = jsval_obj(&vbarray->dispex);
+        break;
+
+    default:
+        FIXME("unimplemented flags: %x\n", flags);
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+HRESULT create_vbarray_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
+{
+    VBArrayInstance *vbarray;
+    HRESULT hres;
+
+    static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
+
+    hres = alloc_vbarray(ctx, object_prototype, &vbarray);
+    if(FAILED(hres))
+        return hres;
+
+    hres = create_builtin_constructor(ctx, VBArrayConstr_value, VBArrayW, NULL, PROPF_CONSTR|1, &vbarray->dispex, ret);
+
+    jsdisp_release(&vbarray->dispex);
+    return hres;
+}
+
+HRESULT create_vbarray(script_ctx_t *ctx, SAFEARRAY *sa, jsdisp_t **ret)
+{
+    VBArrayInstance *vbarray;
+    HRESULT hres;
+
+    hres = alloc_vbarray(ctx, NULL, &vbarray);
+    if(FAILED(hres))
+        return hres;
+
+    hres = SafeArrayCopy(sa, &vbarray->safearray);
+    if(FAILED(hres)) {
+        jsdisp_release(&vbarray->dispex);
+        return hres;
+    }
+
+    *ret = &vbarray->dispex;
+    return S_OK;
+}
index 1a0ddd3..e4757b7 100644 (file)
@@ -79,7 +79,7 @@ reactos/dll/win32/inseng          # Synced to Wine-1.5.4
 reactos/dll/win32/iphlpapi        # Out of sync
 reactos/dll/win32/itircl          # Synced to Wine-1.5.19
 reactos/dll/win32/itss            # Synced to Wine-1.5.4
-reactos/dll/win32/jscript         # Autosync
+reactos/dll/win32/jscript         # Synced to Wine-1.5.26
 reactos/dll/win32/loadperf        # Synced to Wine-1.5.19
 reactos/dll/win32/localspl        # Synced to Wine-1.1.14?
 reactos/dll/win32/localui         # Synced to Wine-1.5.19