⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jsfun.c

📁 一个基于alice开发的机器人
💻 C
📖 第 1 页 / 共 5 页
字号:
    void *mark;
    JSTokenStream *ts;
    JSPrincipals *principals;
    jschar *collected_args, *cp;
    size_t arg_length, args_length;
    JSTokenType tt;
    JSBool ok;

    fp = cx->fp;
    if (fp && !(fp->flags & JSFRAME_CONSTRUCTING)) {
        obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL);
        if (!obj)
            return JS_FALSE;
        *rval = OBJECT_TO_JSVAL(obj);
    }
    fun = (JSFunction *) JS_GetPrivate(cx, obj);
    if (fun)
        return JS_TRUE;

#if JS_HAS_CALL_OBJECT
    /*
     * NB: (new Function) is not lexically closed by its caller, it's just an
     * anonymous function in the top-level scope that its constructor inhabits.
     * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
     * and so would a call to f from another top-level's script or function.
     *
     * In older versions, before call objects, a new Function was adopted by
     * its running context's globalObject, which might be different from the
     * top-level reachable from scopeChain (in HTML frames, e.g.).
     */
    parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]));
#else
    /* Set up for dynamic parenting (see js_Invoke in jsinterp.c). */
    parent = NULL;
#endif

    fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA, parent,
                         JSVERSION_IS_ECMA(cx->version)
                         ? cx->runtime->atomState.anonymousAtom
                         : NULL);

    if (!fun)
        return JS_FALSE;

    /*
     * Function is static and not called directly by other functions in this
     * file, therefore it is callable only as a native function by js_Invoke.
     * Find the scripted caller, possibly skipping other native frames such as
     * are built for Function.prototype.call or .apply activations that invoke
     * Function indirectly from a script.
     */
    JS_ASSERT(!fp->script && fp->fun && fp->fun->native == Function);
    caller = JS_GetScriptedCaller(cx, fp);
    if (caller) {
        filename = caller->script->filename;
        lineno = js_PCToLineNumber(cx, caller->script, caller->pc);
        principals = JS_EvalFramePrincipals(cx, fp, caller);
    } else {
        filename = NULL;
        lineno = 0;
        principals = NULL;
    }

    n = argc ? argc - 1 : 0;
    if (n > 0) {
        /*
         * Collect the function-argument arguments into one string, separated
         * by commas, then make a tokenstream from that string, and scan it to
         * get the arguments.  We need to throw the full scanner at the
         * problem, because the argument string can legitimately contain
         * comments and linefeeds.  XXX It might be better to concatenate
         * everything up into a function definition and pass it to the
         * compiler, but doing it this way is less of a delta from the old
         * code.  See ECMA 15.3.2.1.
         */
        args_length = 0;
        for (i = 0; i < n; i++) {
            /* Collect the lengths for all the function-argument arguments. */
            arg = js_ValueToString(cx, argv[i]);
            if (!arg)
                return JS_FALSE;
            argv[i] = STRING_TO_JSVAL(arg);
            args_length += JSSTRING_LENGTH(arg);
        }
        /* Add 1 for each joining comma. */
        args_length += n - 1;

        /*
         * Allocate a string to hold the concatenated arguments, including room
         * for a terminating 0.  Mark cx->tempPool for later release, to free
         * collected_args and its tokenstream in one swoop.
         */
        mark = JS_ARENA_MARK(&cx->tempPool);
        JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool,
                               (args_length+1) * sizeof(jschar));
        if (!cp)
            return JS_FALSE;
        collected_args = cp;

        /*
         * Concatenate the arguments into the new string, separated by commas.
         */
        for (i = 0; i < n; i++) {
            arg = JSVAL_TO_STRING(argv[i]);
            arg_length = JSSTRING_LENGTH(arg);
            (void) js_strncpy(cp, JSSTRING_CHARS(arg), arg_length);
            cp += arg_length;

            /* Add separating comma or terminating 0. */
            *cp++ = (i + 1 < n) ? ',' : 0;
        }

        /*
         * Make a tokenstream (allocated from cx->tempPool) that reads from
         * the given string.
         */
        ts = js_NewTokenStream(cx, collected_args, args_length, filename,
                               lineno, principals);
        if (!ts) {
            JS_ARENA_RELEASE(&cx->tempPool, mark);
            return JS_FALSE;
        }

        /* The argument string may be empty or contain no tokens. */
        tt = js_GetToken(cx, ts);
        if (tt != TOK_EOF) {
            for (;;) {
                /*
                 * Check that it's a name.  This also implicitly guards against
                 * TOK_ERROR, which was already reported.
                 */
                if (tt != TOK_NAME)
                    goto bad_formal;

                /*
                 * Get the atom corresponding to the name from the tokenstream;
                 * we're assured at this point that it's a valid identifier.
                 */
                atom = CURRENT_TOKEN(ts).t_atom;
                if (!js_LookupProperty(cx, obj, (jsid)atom, &obj2,
                                       (JSProperty **)&sprop)) {
                    goto bad_formal;
                }
                dupflag = 0;
                if (sprop) {
                    ok = JS_TRUE;
                    if (obj2 == obj) {
                        const char *name = js_AtomToPrintableString(cx, atom);

                        /*
                         * A duplicate parameter name. We force a duplicate
                         * node on the SCOPE_LAST_PROP(scope) list with the
                         * same id, distinguished by the SPROP_IS_DUPLICATE
                         * flag, and not mapped by an entry in scope.
                         */
                        JS_ASSERT(sprop->getter == js_GetArgument);
                        ok = name &&
                             js_ReportCompileErrorNumber(cx, ts, NULL,
                                                         JSREPORT_WARNING |
                                                         JSREPORT_STRICT,
                                                         JSMSG_DUPLICATE_FORMAL,
                                                         name);

                        dupflag = SPROP_IS_DUPLICATE;
                    }
                    OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
                    if (!ok)
                        goto bad_formal;
                    sprop = NULL;
                }
                if (!js_AddNativeProperty(cx, fun->object, (jsid)atom,
                                          js_GetArgument, js_SetArgument,
                                          SPROP_INVALID_SLOT,
                                          JSPROP_ENUMERATE | JSPROP_PERMANENT |
                                          JSPROP_SHARED,
                                          SPROP_HAS_SHORTID | dupflag,
                                          fun->nargs)) {
                    goto bad_formal;
                }
                fun->nargs++;

                /*
                 * Get the next token.  Stop on end of stream.  Otherwise
                 * insist on a comma, get another name, and iterate.
                 */
                tt = js_GetToken(cx, ts);
                if (tt == TOK_EOF)
                    break;
                if (tt != TOK_COMMA)
                    goto bad_formal;
                tt = js_GetToken(cx, ts);
            }
        }

        /* Clean up. */
        ok = js_CloseTokenStream(cx, ts);
        JS_ARENA_RELEASE(&cx->tempPool, mark);
        if (!ok)
            return JS_FALSE;
    }

    if (argc) {
        str = js_ValueToString(cx, argv[argc-1]);
    } else {
        /* Can't use cx->runtime->emptyString because we're called too early. */
        str = js_NewStringCopyZ(cx, js_empty_ucstr, 0);
    }
    if (!str)
        return JS_FALSE;
    if (argv) {
        /* Use the last arg (or this if argc == 0) as a local GC root. */
        argv[(intN)(argc-1)] = STRING_TO_JSVAL(str);
    }

    mark = JS_ARENA_MARK(&cx->tempPool);
    ts = js_NewTokenStream(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
                           filename, lineno, principals);
    if (!ts) {
        ok = JS_FALSE;
    } else {
        ok = js_CompileFunctionBody(cx, ts, fun) &&
             js_CloseTokenStream(cx, ts);
    }
    JS_ARENA_RELEASE(&cx->tempPool, mark);
    return ok;

bad_formal:
    /*
     * Report "malformed formal parameter" iff no illegal char or similar
     * scanner error was already reported.
     */
    if (!(ts->flags & TSF_ERROR))
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_FORMAL);

    /*
     * Clean up the arguments string and tokenstream if we failed to parse
     * the arguments.
     */
    (void)js_CloseTokenStream(cx, ts);
    JS_ARENA_RELEASE(&cx->tempPool, mark);
    return JS_FALSE;
}

JSObject *
js_InitFunctionClass(JSContext *cx, JSObject *obj)
{
    JSObject *proto;
    JSAtom *atom;
    JSFunction *fun;

    proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
                         function_props, function_methods, NULL, NULL);
    if (!proto)
        return NULL;
    atom = js_Atomize(cx, js_FunctionClass.name, strlen(js_FunctionClass.name),
                      0);
    if (!atom)
        goto bad;
    fun = js_NewFunction(cx, proto, NULL, 0, 0, obj, NULL);
    if (!fun)
        goto bad;
    fun->script = js_NewScript(cx, 0, 0, 0);
    if (!fun->script)
        goto bad;
    return proto;

bad:
    cx->newborn[GCX_OBJECT] = NULL;
    return NULL;
}

#if JS_HAS_CALL_OBJECT
JSObject *
js_InitCallClass(JSContext *cx, JSObject *obj)
{
    return JS_InitClass(cx, obj, NULL, &js_CallClass, NULL, 0,
                        call_props, NULL, NULL, NULL);
}
#endif

JSFunction *
js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
               uintN flags, JSObject *parent, JSAtom *atom)
{
    JSFunction *fun;

    /* Allocate a function struct. */
    fun = (JSFunction *) JS_malloc(cx, sizeof *fun);
    if (!fun)
        return NULL;

    /* If funobj is null, allocate an object for it. */
    if (funobj) {
        OBJ_SET_PARENT(cx, funobj, parent);
    } else {
        funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent);
        if (!funobj) {
            JS_free(cx, fun);
            return NULL;
        }
    }

    /* Initialize all function members. */
    fun->nrefs = 0;
    fun->object = NULL;
    fun->native = native;
    fun->script = NULL;
    fun->nargs = nargs;
    fun->extra = 0;
    fun->nvars = 0;
    fun->flags = flags & JSFUN_FLAGS_MASK;
    fun->spare = 0;
    fun->atom = atom;
    fun->clasp = NULL;

    /* Link fun to funobj and vice versa. */
    if (!js_LinkFunctionObject(cx, fun, funobj)) {
        cx->newborn[GCX_OBJECT] = NULL;
        JS_free(cx, fun);
        return NULL;
    }
    return fun;
}

JSObject *
js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
{
    JSObject *newfunobj;
    JSFunction *fun;

    JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
    newfunobj = js_NewObject(cx, &js_FunctionClass, funobj, parent);
    if (!newfunobj)
        return NULL;
    fun = (JSFunction *) JS_GetPrivate(cx, funobj);
    if (!js_LinkFunctionObject(cx, fun, newfunobj)) {
        cx->newborn[GCX_OBJECT] = NULL;
        return NULL;
    }
    return newfunobj;
}

JSBool
js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *funobj)
{
    if (!fun->object)
        fun->object = funobj;
    if (!JS_SetPrivate(cx, funobj, fun))
        return JS_FALSE;
    JS_ATOMIC_INCREMENT(&fun->nrefs);
    return JS_TRUE;
}

JSFunction *
js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
                  uintN nargs, uintN attrs)
{
    JSFunction *fun;

    fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);
    if (!fun)
        return NULL;
    if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, OBJECT_TO_JSVAL(fun->object),
                             NULL, NULL, attrs & ~JSFUN_FLAGS_MASK, NULL)) {
        return NULL;
    }
    return fun;
}

#if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
# error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
#endif

JSFunction *
js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags)
{
    jsval v;
    JSObject *obj;

    v = *vp;
    obj = NULL;
    if (JSVAL_IS_OBJECT(v)) {
        obj = JSVAL_TO_OBJECT(v);
        if (obj && OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {
            if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &v))
                return NULL;
            obj = JSVAL_IS_FUNCTION(cx, v) ? JSVAL_TO_OBJECT(v) : NULL;
        }
    }
    if (!obj) {
        js_ReportIsNotFunction(cx, vp, flags);
        return NULL;
    }
    return (JSFunction *) JS_GetPrivate(cx, obj);
}

void
js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
{
    JSType type;
    JSString *fallback;
    JSString *str;

    /*
     * We provide the typename as the fallback to handle the case when
     * valueOf is not a function, which prevents ValueToString from being
     * called as the default case inside js_DecompileValueGenerator (and
     * so recursing 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -