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

📄 jsparse.c

📁 一个基于alice开发的机器人
💻 C
📖 第 1 页 / 共 5 页
字号:
     *   GC attempted within js_AllocGCThing), or
     * - run for any reason on another thread if this thread is suspended on
     *   an object lock before it finishes generating bytecode into a script
     *   protected from the GC by a root or a stack frame reference.
     */
    JS_KEEP_ATOMS(cx->runtime);
    TREE_CONTEXT_INIT(&tc);
    pn = Statements(cx, ts, &tc);
    if (pn) {
        if (!js_MatchToken(cx, ts, TOK_EOF)) {
            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
                                        JSMSG_SYNTAX_ERROR);
            pn = NULL;
        } else {
            pn->pn_type = TOK_LC;
            if (!js_FoldConstants(cx, pn, &tc))
                pn = NULL;
        }
    }

    TREE_CONTEXT_FINISH(&tc);
    JS_UNKEEP_ATOMS(cx->runtime);
    cx->fp = fp;
    return pn;
}

/*
 * Compile a top-level script.
 */
JS_FRIEND_API(JSBool)
js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
                      JSCodeGenerator *cg)
{
    JSStackFrame *fp, frame;
    JSParseNode *pn;
    JSBool ok;
#ifdef METER_PARSENODES
    void *sbrk(ptrdiff_t), *before = sbrk(0);
#endif

    /*
     * Push a compiler frame if we have no frames, or if the top frame is a
     * lightweight function activation, or if its scope chain doesn't match
     * the one passed to us.
     */
    fp = cx->fp;
    if (!fp || !fp->varobj || fp->scopeChain != chain) {
        memset(&frame, 0, sizeof frame);
        frame.varobj = frame.scopeChain = chain;
        if (cx->options & JSOPTION_VAROBJFIX) {
            while ((chain = JS_GetParent(cx, chain)) != NULL)
                frame.varobj = chain;
        }
        frame.down = fp;
        cx->fp = &frame;
    }

    /* Prevent GC activation while compiling. */
    JS_KEEP_ATOMS(cx->runtime);

    pn = Statements(cx, ts, &cg->treeContext);
    if (!pn) {
        ok = JS_FALSE;
    } else if (!js_MatchToken(cx, ts, TOK_EOF)) {
        js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
                                    JSMSG_SYNTAX_ERROR);
        ok = JS_FALSE;
    } else {
#ifdef METER_PARSENODES
        printf("Parser growth: %d (%u nodes, %u max, %u unrecycled)\n",
               (char *)sbrk(0) - (char *)before,
               parsenodes,
               maxparsenodes,
               parsenodes - recyclednodes);
        before = sbrk(0);
#endif

        /*
         * No need to emit code here -- Statements already has, for each
         * statement in turn.  Search for TCF_COMPILING in Statements, below.
         * That flag is set for every tc == &cg->treeContext, and it implies
         * that the tc can be downcast to a cg and used to emit code during
         * parsing, rather than at the end of the parse phase.
         */
        JS_ASSERT(cg->treeContext.flags & TCF_COMPILING);
        ok = JS_TRUE;
    }

#ifdef METER_PARSENODES
    printf("Code-gen growth: %d (%u bytecodes, %u srcnotes)\n",
           (char *)sbrk(0) - (char *)before, CG_OFFSET(cg), cg->noteCount);
#endif
#ifdef JS_ARENAMETER
    JS_DumpArenaStats(stdout);
#endif
    JS_UNKEEP_ATOMS(cx->runtime);
    cx->fp = fp;
    return ok;
}

/*
 * Insist on a final return before control flows out of pn, but don't be too
 * smart about loops (do {...; return e2;} while(0) at the end of a function
 * that contains an early return e1 will get a strict-option-only warning).
 */
static JSBool
HasFinalReturn(JSParseNode *pn)
{
    JSBool ok, hasDefault;
    JSParseNode *pn2, *pn3;

    switch (pn->pn_type) {
      case TOK_LC:
        if (!pn->pn_head)
            return JS_FALSE;
        return HasFinalReturn(PN_LAST(pn));

      case TOK_IF:
        ok = HasFinalReturn(pn->pn_kid2);
        ok &= pn->pn_kid3 && HasFinalReturn(pn->pn_kid3);
        return ok;

#if JS_HAS_SWITCH_STATEMENT
      case TOK_SWITCH:
        ok = JS_TRUE;
        hasDefault = JS_FALSE;
        for (pn2 = pn->pn_kid2->pn_head; ok && pn2; pn2 = pn2->pn_next) {
            if (pn2->pn_type == TOK_DEFAULT)
                hasDefault = JS_TRUE;
            pn3 = pn2->pn_right;
            JS_ASSERT(pn3->pn_type == TOK_LC);
            if (pn3->pn_head)
                ok &= HasFinalReturn(PN_LAST(pn3));
        }
        /* If a final switch has no default case, we judge it harshly. */
        ok &= hasDefault;
        return ok;
#endif /* JS_HAS_SWITCH_STATEMENT */

      case TOK_WITH:
        return HasFinalReturn(pn->pn_right);

      case TOK_RETURN:
        return JS_TRUE;

#if JS_HAS_EXCEPTIONS
      case TOK_THROW:
        return JS_TRUE;

      case TOK_TRY:
        /* If we have a finally block that returns, we are done. */
        if (pn->pn_kid3 && HasFinalReturn(pn->pn_kid3))
            return JS_TRUE;

        /* Else check the try block and any and all catch statements. */
        ok = HasFinalReturn(pn->pn_kid1);
        if (pn->pn_kid2)
            ok &= HasFinalReturn(pn->pn_kid2);
        return ok;

      case TOK_CATCH:
        /* Check this block's code and iterate over further catch blocks. */
        ok = HasFinalReturn(pn->pn_kid3);
        for (pn2 = pn->pn_kid2; pn2; pn2 = pn2->pn_kid2)
            ok &= HasFinalReturn(pn2->pn_kid3);
        return ok;
#endif

      default:
        return JS_FALSE;
    }
}

static JSBool
ReportNoReturnValue(JSContext *cx, JSTokenStream *ts)
{
    JSFunction *fun;
    JSBool ok;

    fun = cx->fp->fun;
    if (fun->atom) {
        char *name = js_GetStringBytes(ATOM_TO_STRING(fun->atom));
        ok = js_ReportCompileErrorNumber(cx, ts, NULL,
                                         JSREPORT_WARNING |
                                         JSREPORT_STRICT,
                                         JSMSG_NO_RETURN_VALUE, name);
    } else {
        ok = js_ReportCompileErrorNumber(cx, ts, NULL,
                                         JSREPORT_WARNING |
                                         JSREPORT_STRICT,
                                         JSMSG_ANON_NO_RETURN_VALUE);
    }
    return ok;
}

static JSBool
CheckFinalReturn(JSContext *cx, JSTokenStream *ts, JSParseNode *pn)
{
    return HasFinalReturn(pn) || ReportNoReturnValue(cx, ts);
}

static JSParseNode *
FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
             JSTreeContext *tc)
{
    JSStackFrame *fp, frame;
    JSObject *funobj;
    uintN oldflags;
    JSParseNode *pn;

    fp = cx->fp;
    funobj = fun->object;
    if (!fp || fp->fun != fun || fp->varobj != funobj ||
        fp->scopeChain != funobj) {
        memset(&frame, 0, sizeof frame);
        frame.fun = fun;
        frame.varobj = frame.scopeChain = funobj;
        frame.down = fp;
        cx->fp = &frame;
    }

    oldflags = tc->flags;
    tc->flags &= ~(TCF_RETURN_EXPR | TCF_RETURN_VOID);
    tc->flags |= TCF_IN_FUNCTION;
    pn = Statements(cx, ts, tc);

    /* Check for falling off the end of a function that returns a value. */
    if (pn && JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR)) {
        if (!CheckFinalReturn(cx, ts, pn))
            pn = NULL;
    }

    cx->fp = fp;
    tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
    return pn;
}

/*
 * Compile a JS function body, which might appear as the value of an event
 * handler attribute in an HTML <INPUT> tag.
 */
JSBool
js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun)
{
    JSArenaPool codePool, notePool;
    JSCodeGenerator funcg;
    JSStackFrame *fp, frame;
    JSObject *funobj;
    JSParseNode *pn;
    JSBool ok;

    JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode));
    JS_InitArenaPool(&notePool, "note", 1024, sizeof(jssrcnote));
    if (!js_InitCodeGenerator(cx, &funcg, &codePool, &notePool,
                              ts->filename, ts->lineno,
                              ts->principals)) {
        return JS_FALSE;
    }

    /* Prevent GC activation while compiling. */
    JS_KEEP_ATOMS(cx->runtime);

    /* Push a JSStackFrame for use by FunctionBody and js_EmitFunctionBody. */
    fp = cx->fp;
    funobj = fun->object;
    JS_ASSERT(!fp || fp->fun != fun || fp->varobj != funobj ||
              fp->scopeChain != funobj);
    memset(&frame, 0, sizeof frame);
    frame.fun = fun;
    frame.varobj = frame.scopeChain = funobj;
    frame.down = fp;
    cx->fp = &frame;

    /* Ensure that the body looks like a block statement to js_EmitTree. */
    CURRENT_TOKEN(ts).type = TOK_LC;
    pn = FunctionBody(cx, ts, fun, &funcg.treeContext);
    if (!pn) {
        ok = JS_FALSE;
    } else {
        /*
         * No need to emit code here -- Statements (via FunctionBody) already
         * has.  See similar comment in js_CompileTokenStream, and bug 108257.
         */
        fun->script = js_NewScriptFromCG(cx, &funcg, fun);
        if (!fun->script) {
            ok = JS_FALSE;
        } else {
            if (funcg.treeContext.flags & TCF_FUN_HEAVYWEIGHT)
                fun->flags |= JSFUN_HEAVYWEIGHT;
            ok = JS_TRUE;
        }
    }

    /* Restore saved state and release code generation arenas. */
    cx->fp = fp;
    JS_UNKEEP_ATOMS(cx->runtime);
    js_FinishCodeGenerator(cx, &funcg);
    JS_FinishArenaPool(&codePool);
    JS_FinishArenaPool(&notePool);
    return ok;
}

static JSParseNode *
FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
            JSBool lambda)
{
    JSParseNode *pn, *body;
    JSOp op, prevop;
    JSAtom *funAtom, *argAtom;
    JSFunction *fun;
    JSObject *parent;
    JSObject *pobj;
    JSScopeProperty *sprop;
    uintN dupflag;
    JSBool ok;
    JSTreeContext funtc;
    JSAtomListElement *ale;

    /* Make a TOK_FUNCTION node. */
    pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_FUNC, tc);
    if (!pn)
        return NULL;
#if JS_HAS_GETTER_SETTER
    op = CURRENT_TOKEN(ts).t_op;
#endif

    /* Scan the optional function name into funAtom. */
    if (js_MatchToken(cx, ts, TOK_NAME))
        funAtom = CURRENT_TOKEN(ts).t_atom;
    else
        funAtom = NULL;

    /* Find the nearest variable-declaring scope and use it as our parent. */
    parent = cx->fp->varobj;
    fun = js_NewFunction(cx, NULL, NULL, 0, lambda ? JSFUN_LAMBDA : 0, parent,
                         funAtom);
    if (!fun)
        return NULL;

#if JS_HAS_GETTER_SETTER
    if (op != JSOP_NOP)
        fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER;
#endif

    /* Now parse formal argument list and compute fun->nargs. */
    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL);
    if (!js_MatchToken(cx, ts, TOK_RP)) {
        do {
            MUST_MATCH_TOKEN(TOK_NAME, JSMSG_MISSING_FORMAL);
            argAtom = CURRENT_TOKEN(ts).t_atom;
            pobj = NULL;
            if (!js_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj,
                                   (JSProperty **)&sprop)) {
                return NULL;
            }
            dupflag = 0;
            if (sprop) {
                ok = JS_TRUE;
                if (pobj == fun->object &&
                    sprop->getter == js_GetArgument) {
                    const char *name = js_AtomToPrintableString(cx, argAtom);

                    /*
                     * 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.
                     */
                    ok = name &&
                         js_ReportCompileErrorNumber(cx, ts, NULL,
                                                     JSREPORT_WARNING |
                                                     JSREPORT_STRICT,
                                                     JSMSG_DUPLICATE_FORMAL,
                                                     name);

                    dupflag = SPROP_IS_DUPLICATE;
                }
                OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
                if (!ok)
                    return NULL;
                sprop = NULL;
            }
            if (!js_AddNativeProperty(cx, fun->object, (jsid)argAtom,
                                      js_GetArgument, js_SetArgument,

⌨️ 快捷键说明

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