Пример #1
0
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) {
        jsval_t args[2];
        jsval_t res;
        double n;

        args[0] = v1;
        args[1] = v2;

        hres = jsdisp_call_value(cmp_func, NULL, DISPATCH_METHOD, 2, args, &res);
        if(FAILED(hres))
            return hres;

        hres = to_number(ctx, res, &n);
        jsval_release(res);
        if(FAILED(hres))
            return hres;

        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_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 {
        jsstr_t *x, *y;

        hres = to_string(ctx, v1, &x);
        if(FAILED(hres))
            return hres;

        hres = to_string(ctx, v2, &y);
        if(SUCCEEDED(hres)) {
            *cmp = jsstr_cmp(x, y);
            jsstr_release(y);
        }
        jsstr_release(x);
        if(FAILED(hres))
            return hres;
    }

    return S_OK;
}
Пример #2
0
bool MCVariableValue::coerce_to_string(MCExecPoint& ep)
{
	assert(!is_string());

	if (is_undefined())
	{
		assign_empty();
		return true;
	}

	if (is_number())
	{
		uint32_t t_length;
		t_length = MCU_r8tos(strnum . buffer . data, strnum . buffer . size, strnum . nvalue, ep . getnffw(), ep . getnftrailing(), ep . getnfforce());

		strnum . svalue . string = strnum . buffer . data;
		strnum . svalue . length = t_length;

		set_type(VF_BOTH);
		return true;
	}

	assign_empty();
	return true;
}
Пример #3
0
static HRESULT Function_call(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
        jsval_t *r)
{
    FunctionInstance *function;
    IDispatch *this_obj = NULL;
    unsigned cnt = 0;
    HRESULT hres;

    TRACE("\n");

    if(!(function = function_this(jsthis)))
        return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);

    if(argc) {
        if(!is_undefined(argv[0]) && !is_null(argv[0])) {
            hres = to_object(ctx, argv[0], &this_obj);
            if(FAILED(hres))
                return hres;
        }

        cnt = argc-1;
    }

    hres = call_function(ctx, function, this_obj, cnt, argv+1, r);

    if(this_obj)
        IDispatch_Release(this_obj);
    return hres;
}
Пример #4
0
void print(Value x)
{
	if (is_nil(x))
		prints("nil");
	else if (is_eof(x))
		printf("#eof");
	else if (is_fixnum(x))
		printf("%d", as_fixnum(x));
	else if (is_bool(x))
		printf("%s", as_bool(x) ? "true" : "false");
	else if (is_char(x))
		printf("'%c'", as_char(x));
	else if (is_pair(x))
		print_list(x);
	else if (is_symbol(x))
		prints(as_symbol(x)->value);
	else if (is_string(x))
		print_string(as_string(x));
	else if (is_procedure(x))
		printf("#<procedure %s>", as_procedure(x)->name->value);
	else if (is_module(x))
		printf("#<module>");
	else if (is_type(x))
		printf("#<type %s>", as_type(x)->name->value);
	else if (is_ptr(x))
		printf("#<object %p>", as_ptr(x));
	else if (is_undefined(x))
		printf("#undefined");
	else
		printf("#ufo");
}
Пример #5
0
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;
}
Пример #6
0
/*******************************************************************
 *         BuildSpec32File
 *
 * Build a Win32 C file from a spec file.
 */
void BuildSpec32File( DLLSPEC *spec )
{
    resolve_imports( spec );
    output_standard_file_header();
    output_module( spec );
    output_stubs( spec );
    output_exports( spec );
    output_imports( spec );
    if (is_undefined( "__wine_call_from_regs" )) output_asm_relays();
    output_resources( spec );
    output_gnu_stack_note();
}
Пример #7
0
 void unite_with_data(const relation_fact & f) {
     if (empty()) {
         assign_data(f);
         return;
     }
     unsigned n=get_signature().size();
     SASSERT(f.size()==n);
     for (unsigned i=0; i<n; i++) {
         SASSERT(!is_undefined(i));
         m_data[i] = get_plugin().mk_union(m_data[i], f[i]);
     }
 }
Пример #8
0
static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
{
    FunctionInstance *function;
    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, JS_E_FUNCTION_EXPECTED, NULL);

    if(argc) {
        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) {
        jsdisp_t *arg_array = NULL;

        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);
                arg_array = NULL;
            }
        }

        if(arg_array) {
            hres = array_to_args(ctx, arg_array, &cnt, &args);
            jsdisp_release(arg_array);
        }else {
            FIXME("throw TypeError\n");
            hres = E_FAIL;
        }
    }

    if(SUCCEEDED(hres))
        hres = call_function(ctx, function, this_obj, cnt, args, r);

    if(this_obj)
        IDispatch_Release(this_obj);
    for(i=0; i < cnt; i++)
        jsval_release(args[i]);
    heap_free(args);
    return hres;
}
Пример #9
0
	bool	as_value::operator==(const as_value& v) const
	// Return true if operands are equal.
	{
		// types don't match
		if (m_type != PROPERTY && v.m_type != PROPERTY && m_type != v.m_type)
		{
			if ((is_undefined() && v.is_null()) || (is_null() && v.is_undefined()))
			{
				return true;
			}
			return false;
		}

		switch (m_type)
		{
			case UNDEFINED:
				return v.m_type == UNDEFINED;

			case STRING:
				return m_string == v.to_tu_string();

			case NUMBER:
				return m_number == v.to_number();

			case BOOLEAN:
				return m_bool == v.to_bool();

			case OBJECT:
				return m_object.get() == v.to_object();

			case PROPERTY:
			{
				as_value prop;
				get_property(&prop);
				return prop == v;
			}

			default:
				assert(0);
				return false;
		}
	}
Пример #10
0
/*******************************************************************
 *         output_spec16_file
 *
 * Output the complete data for a spec 16-bit file.
 */
void output_spec16_file( DLLSPEC *spec16 )
{
    DLLSPEC *spec32 = alloc_dll_spec();

    resolve_imports( spec16 );
    add_16bit_exports( spec32, spec16 );

    output_standard_file_header();
    output_module( spec32 );
    output_module16( spec16 );
    output_stubs( spec16 );
    output_exports( spec32 );
    output_imports( spec16 );
    if (is_undefined( "__wine_call_from_16" )) output_asm_relays16();
    if (spec16->main_module)
    {
        output( "\n\t%s\n", get_asm_string_section() );
        output( ".L__wine_spec_main_module:\n" );
        output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec16->main_module );
    }
    output_gnu_stack_note();
    free_dll_spec( spec32 );
	output("%s:/*?*/\n", asm_name("_end"));
}
Пример #11
0
/* ECMA-262 5.1 Edition    15.12.3 (abstract operation JO) */
static HRESULT stringify_object(stringify_ctx_t *ctx, jsdisp_t *obj)
{
    DISPID dispid = DISPID_STARTENUM;
    jsval_t val = jsval_undefined();
    unsigned prop_cnt = 0, i;
    size_t stepback;
    BSTR prop_name;
    HRESULT hres;

    if(is_on_stack(ctx, obj)) {
        FIXME("Found a cycle\n");
        return E_FAIL;
    }

    if(!stringify_push_obj(ctx, obj))
        return E_OUTOFMEMORY;

    if(!append_char(ctx, '{'))
        return E_OUTOFMEMORY;

    while((hres = IDispatchEx_GetNextDispID(&obj->IDispatchEx_iface, fdexEnumDefault, dispid, &dispid)) == S_OK) {
        jsval_release(val);
        hres = jsdisp_propget(obj, dispid, &val);
        if(FAILED(hres))
            return hres;

        if(is_undefined(val))
            continue;

        stepback = ctx->buf_len;

        if(prop_cnt && !append_char(ctx, ',')) {
            hres = E_OUTOFMEMORY;
            break;
        }

        if(*ctx->gap) {
            if(!append_char(ctx, '\n')) {
                hres = E_OUTOFMEMORY;
                break;
            }

            for(i=0; i < ctx->stack_top; i++) {
                if(!append_string(ctx, ctx->gap)) {
                    hres = E_OUTOFMEMORY;
                    break;
                }
            }
        }

        hres = IDispatchEx_GetMemberName(&obj->IDispatchEx_iface, dispid, &prop_name);
        if(FAILED(hres))
            break;

        hres = json_quote(ctx, prop_name, SysStringLen(prop_name));
        SysFreeString(prop_name);
        if(FAILED(hres))
            break;

        if(!append_char(ctx, ':') || (*ctx->gap && !append_char(ctx, ' '))) {
            hres = E_OUTOFMEMORY;
            break;
        }

        hres = stringify(ctx, val);
        if(FAILED(hres))
            break;

        if(hres == S_FALSE) {
            ctx->buf_len = stepback;
            continue;
        }

        prop_cnt++;
    }
    jsval_release(val);
    if(FAILED(hres))
        return hres;

    if(prop_cnt && *ctx->gap) {
        if(!append_char(ctx, '\n'))
            return E_OUTOFMEMORY;

        for(i=1; i < ctx->stack_top; i++) {
            if(!append_string(ctx, ctx->gap)) {
                hres = E_OUTOFMEMORY;
                break;
            }
        }
    }

    if(!append_char(ctx, '}'))
        return E_OUTOFMEMORY;

    stringify_pop_obj(ctx);
    return S_OK;
}
Пример #12
0
static HRESULT array_join(script_ctx_t *ctx, jsdisp_t *array, DWORD length, const WCHAR *sep, jsval_t *r)
{
    jsstr_t **str_tab, *ret;
    jsval_t val;
    DWORD i;
    HRESULT hres = E_FAIL;

    if(!length) {
        if(r)
            *r = jsval_string(jsstr_empty());
        return S_OK;
    }

    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, &val);
        if(hres == DISP_E_UNKNOWNNAME) {
            hres = S_OK;
            continue;
        } else 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)) {
        DWORD seplen = 0, len = 0;

        seplen = strlenW(sep);

        if(str_tab[0])
            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;
            }
        }

        if(SUCCEEDED(hres)) {
            WCHAR *ptr = NULL;

            ptr = jsstr_alloc_buf(len, &ret);
            if(ptr) {
                if(str_tab[0])
                    ptr += jsstr_flush(str_tab[0], ptr);

                for(i=1; i < length; i++) {
                    if(seplen) {
                        memcpy(ptr, sep, seplen*sizeof(WCHAR));
                        ptr += seplen;
                    }

                    if(str_tab[i])
                        ptr += jsstr_flush(str_tab[i], ptr);
                }
            }else {
                hres = E_OUTOFMEMORY;
            }
        }
    }

    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_jsstr(ret));

    if(r)
        *r = jsval_string(ret);
    else
        jsstr_release(ret);
    return S_OK;
}
Пример #13
0
/** 
 * Parse and evaluate a "logical" expression
 * 
 * @param string 
 *    Character string containing logical expression. [c]
 *    Must be of the form: "number logical number" where
 *    number is an integer or floating point number and
 *    logical is one of: 'LT', 'LE', 'GT', 'GE', 'EQ', 'NE'.
 *    Integers are converted to floating before being evaluated.
 *    Leading, trailing, and extra white space is ignored.
 * @param string_s 
 *    Length of \p string
 * @param result 
 *    - "TRUE" if expression is true
 *    - "FALSE" if expression is false
 *    - "ERROR" if and error occurred during parsing
 * @param result_s 
 *    Length of \p result
 *
 * @bug This should return an int (-1,0,1)
 *
 * @date   970129:  Add parameter (0) to cnvatf.  0 means that if a string
 *             of digits is too long, let it slide by.  maf 
 * @date   900606:  Modified tests for reals to handle case where
 *             both numbers are zero.
 * @date   871117:  Changed tests of (in)equality of reals to include
 *             the possible effects of roundoff.
 *             These are now tests for equivalence not equality.
 * @date   871103:  Added ability to check for (in)equality of strings.
 * @date   870811:  Original version.
 *
 */
void 
evallogical(char *string, 
            int   string_s, 
            char *result, 
            int   result_s) {

  UNUSED(string);
  UNUSED(string_s);

	int lresult;
	float x, y;

  Token *t1, *t2, *top;

  if(!(t1 = arg()))  { goto ERROR; }
  arg_next();
  if(!(top = arg())) { goto ERROR; }
  arg_next();
  if(!(t2 = arg()))  { goto ERROR; }
  arg_next();

	/* - If first and third tokens are not floating point numbers (i.e. strings)
	 *   then the only tests that are allowed are "EQ" and "NE". */

	if( (token_is_string(t1) || token_is_quoted_string(t1) || token_is_escape_string(t1)) &&
      (token_is_string(t2) || token_is_quoted_string(t2) || token_is_escape_string(t2))) {
    lresult = strcmp(t1->str, t2->str);
    if(is_undefined(t1->str) && strcmp(t2->str, "-12345  ") == 0) {
      lresult = 0;
    }
    if(is_undefined(t2->str) && strcmp(t1->str, "-12345  ") == 0) {
      lresult = 0;
    }
    if( token_is_eq(top) ) {
      lresult = lresult == 0;
      goto L_8000;
    }	else if( token_is_ne(top) ) {
      lresult = lresult != 0;
			goto L_8000;
    }	else {
			goto ERROR;
    }
  }
  if(!token_is_number(t1) || !token_is_number(t2)) {
    if( (token_is_string(t1) || token_is_quoted_string(t1) || token_is_escape_string(t1)) &&
        is_undefined(t1->str) &&
        token_is_number(t2) ) {
        t1->value = -12345;
    } else if( (token_is_string(t2) || token_is_quoted_string(t2) || token_is_escape_string(t2)) &&
               is_undefined(t2->str) &&
               token_is_number(t1) ) {
      t2->value = -12345;
    } else {
      goto ERROR;
    }
  }

	/* - Evaluate logical expressions involving floating point numbers. */

  if(token_is_lt(top)) {
    lresult = t1->value < t2->value;
  } else if(token_is_le(top)) {
    lresult = t1->value <= t2->value;
  } else if(token_is_gt(top)) {
    lresult = t1->value > t2->value;
  } else if(token_is_ge(top)) {
    lresult = t1->value >= t2->value;
  } else if(token_is_eq(top)) {
    /* y = t1 - t2;
       x = MAX((t1 + t2)/2, 1e-30)
       (t1-t2)/(t1+t2)/2 <= RNDOFF
    */
    y = fabs( t1->value - t2->value );
    x = fmax( 0.5*(t1->value + t2->value), VSMALL );
    lresult = (y/x) <= RNDOFF;
  } else if(token_is_ne(top)) {
    y = fabs( t1->value - t2->value );
    x = fmax( 0.5*(t1->value + t2->value), VSMALL );
    lresult = (y/x) > RNDOFF;
  } else {
    goto ERROR;
  }

L_8000:
	if( lresult ){
		fstrncpy( result, result_s - 1, "TRUE", 4 );
		}
	else{
		fstrncpy( result, result_s - 1, "FALSE", 5 );
		}
	return;

 ERROR:
  fstrncpy( result, result_s-1, "ERROR", 5 );
  return;
} /* end of function */
Пример #14
0
/* ECMA-262 3rd Edition    15.11.4.4 */
static HRESULT Error_toString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags,
        unsigned argc, jsval_t *argv, jsval_t *r)
{
    jsdisp_t *jsthis;
    jsstr_t *name = NULL, *msg = NULL, *ret = NULL;
    jsval_t v;
    HRESULT hres;

    static const WCHAR object_errorW[] = {'[','o','b','j','e','c','t',' ','E','r','r','o','r',']',0};

    TRACE("\n");

    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(jsthis, nameW, &v);
    if(FAILED(hres))
        return hres;

    if(!is_undefined(v)) {
        hres = to_string(ctx, v, &name);
        jsval_release(v);
        if(FAILED(hres))
            return hres;
    }

    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)) {
        unsigned name_len = name ? jsstr_length(name) : 0;
        unsigned msg_len = msg ? jsstr_length(msg) : 0;

        if(name_len && msg_len) {
            ret = jsstr_alloc_buf(name_len + msg_len + 2);
            if(ret) {
                jsstr_flush(name, ret->str);
                ret->str[name_len] = ':';
                ret->str[name_len+1] = ' ';
                jsstr_flush(msg, ret->str+name_len+2);
            }
        }else if(name_len) {
            ret = name;
            name = NULL;
        }else if(msg_len) {
            ret = msg;
            msg = NULL;
        }else {
            ret = jsstr_alloc(object_errorW);
        }
    }

    if(msg)
        jsstr_release(msg);
    if(name)
        jsstr_release(name);
    if(FAILED(hres))
        return hres;
    if(!ret)
        return E_OUTOFMEMORY;

    if(r)
        *r = jsval_string(ret);
    else
        jsstr_release(ret);
    return S_OK;
}
Пример #15
0
static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
                            jsval_t *r)
{
    match_state_t match_result, *match_ptr = &match_result;
    DWORD length, i, match_len = 0;
    const WCHAR *ptr, *ptr2, *str, *match_str = NULL;
    unsigned limit = ~0u;
    jsdisp_t *array, *regexp = NULL;
    jsstr_t *jsstr, *match_jsstr, *tmp_str;
    HRESULT hres;

    TRACE("\n");

    if(argc != 1 && argc != 2) {
        FIXME("unsupported argc %u\n", argc);
        return E_NOTIMPL;
    }

    hres = get_string_flat_val(ctx, jsthis, &jsstr, &str);
    if(FAILED(hres))
        return hres;

    length = jsstr_length(jsstr);

    if(argc > 1 && !is_undefined(argv[1])) {
        hres = to_uint32(ctx, argv[1], &limit);
        if(FAILED(hres)) {
            jsstr_release(jsstr);
            return hres;
        }
    }

    if(is_object_instance(argv[0])) {
        regexp = iface_to_jsdisp(get_object(argv[0]));
        if(regexp) {
            if(!is_class(regexp, JSCLASS_REGEXP)) {
                jsdisp_release(regexp);
                regexp = NULL;
            }
        }
    }

    if(!regexp) {
        hres = to_flat_string(ctx, argv[0], &match_jsstr, &match_str);
        if(FAILED(hres)) {
            jsstr_release(jsstr);
            return hres;
        }

        match_len = jsstr_length(match_jsstr);
        if(!match_len) {
            jsstr_release(match_jsstr);
            match_str = NULL;
        }
    }

    hres = create_array(ctx, 0, &array);

    if(SUCCEEDED(hres)) {
        ptr = str;
        match_result.cp = str;
        for(i=0; i<limit; i++) {
            if(regexp) {
                hres = regexp_match_next(ctx, regexp, REM_NO_PARENS, jsstr, &match_ptr);
                if(hres != S_OK)
                    break;
                ptr2 = match_result.cp - match_result.match_len;
            } else if(match_str) {
                ptr2 = strstrW(ptr, match_str);
                if(!ptr2)
                    break;
            } else {
                if(!*ptr)
                    break;
                ptr2 = ptr+1;
            }

            tmp_str = jsstr_alloc_len(ptr, ptr2-ptr);
            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;

            if(regexp)
                ptr = match_result.cp;
            else if(match_str)
                ptr = ptr2 + match_len;
            else
                ptr++;
        }
    }

    if(SUCCEEDED(hres) && (match_str || regexp) && i<limit) {
        DWORD len = (str+length) - ptr;

        if(len || match_str) {
            tmp_str = jsstr_alloc_len(ptr, len);

            if(tmp_str) {
                hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
                jsstr_release(tmp_str);
            } else {
                hres = E_OUTOFMEMORY;
            }
        }
    }

    if(regexp)
        jsdisp_release(regexp);
    if(match_str)
        jsstr_release(match_jsstr);
    jsstr_release(jsstr);

    if(SUCCEEDED(hres) && r)
        *r = jsval_obj(array);
    else
        jsdisp_release(array);

    return hres;
}