Beispiel #1
0
static EjsString *serialize(Ejs *ejs, EjsAny *vp, Json *json)
{
    EjsName     qname;
    EjsFunction *fn;
    EjsString   *result, *sv;
    EjsTrait    *trait;
    EjsObj      *pp, *obj, *replacerArgs[2];
    wchar       *cp;
    cchar       *key;
    int         c, isArray, i, count, slotNum, quotes;

    /*
        The main code below can handle Arrays, Objects, objects derrived from Object and also native classes with properties.
        All others just use toString.
     */
    count = ejsIsPot(ejs, vp) ? ejsGetLength(ejs, vp) : 0;
    if (count == 0 && TYPE(vp) != ESV(Object) && TYPE(vp) != ESV(Array)) {
        //  OPT - need some flag for this test.
        if (!ejsIsDefined(ejs, vp) || ejsIs(ejs, vp, Boolean) || ejsIs(ejs, vp, Number)) {
            return ejsToString(ejs, vp);
        } else if (json->regexp) {
            return ejsToString(ejs, vp);
        } else {
            return ejsToLiteralString(ejs, vp);
        }
    }
    obj = vp;
    json->nest++;
    if (json->buf == 0) {
        json->buf = mprCreateBuf(0, 0);
        mprAddRoot(json->buf);
    }
    isArray = ejsIs(ejs, vp, Array);
    mprPutCharToWideBuf(json->buf, isArray ? '[' : '{');
    if (json->pretty) {
        mprPutCharToWideBuf(json->buf, '\n');
    }
    if (++ejs->serializeDepth <= json->depth && !VISITED(obj)) {
        SET_VISITED(obj, 1);
        for (slotNum = 0; slotNum < count && !ejs->exception; slotNum++) {
            trait = ejsGetPropertyTraits(ejs, obj, slotNum);
            if (trait && (trait->attributes & (EJS_TRAIT_HIDDEN | EJS_TRAIT_DELETED | EJS_FUN_INITIALIZER | 
                    EJS_FUN_MODULE_INITIALIZER)) && !json->hidden) {
                continue;
            }
            pp = ejsGetProperty(ejs, obj, slotNum);
            if (ejs->exception) {
                SET_VISITED(obj, 0);
                json->nest--;
                return 0;
            }
            if (pp == 0) {
                continue;
            }
            if (isArray) {
                key = itos(slotNum);
                qname.name = ejsCreateStringFromAsc(ejs, key);
                qname.space = ESV(empty);
            } else {
                qname = ejsGetPropertyName(ejs, vp, slotNum);
            }

            quotes = json->quotes;
            if (!quotes) {
                //  UNICODE
                for (cp = qname.name->value; cp < &qname.name->value[qname.name->length]; cp++) {
                    if (!isalnum((uchar) *cp) && *cp != '_') {
                        quotes = 1;
                        break;
                    }
                }
            }
            if (json->pretty) {
                for (i = 0; i < ejs->serializeDepth; i++) {
                    mprPutStringToWideBuf(json->buf, json->indent);
                }
            }
            if (!isArray) {
                if (json->namespaces) {
                    if (qname.space != ESV(empty)) {
                        mprPutToBuf(json->buf, "\"%@\"::", qname.space);
                    }
                }
                if (quotes) {
                    mprPutCharToWideBuf(json->buf, '"');
                }
                for (cp = qname.name->value; cp && *cp; cp++) {
                    c = *cp;
                    if (c == '"' || c == '\\') {
                        mprPutCharToWideBuf(json->buf, '\\');
                        mprPutCharToWideBuf(json->buf, c);
                    } else {
                        mprPutCharToWideBuf(json->buf, c);
                    }
                }
                if (quotes) {
                    mprPutCharToWideBuf(json->buf, '"');
                }
                mprPutCharToWideBuf(json->buf, ':');
                if (json->pretty) {
                    mprPutCharToWideBuf(json->buf, ' ');
                }
            }
            fn = (EjsFunction*) ejsGetPropertyByName(ejs, TYPE(pp)->prototype, N(NULL, "toJSON"));
            // OPT - check that this is going directly to serialize most of the time
            if (!ejsIsFunction(ejs, fn) || (fn->isNativeProc && fn->body.proc == (EjsProc) ejsObjToJSON)) {
                sv = serialize(ejs, pp, json);
            } else {
                sv = (EjsString*) ejsRunFunction(ejs, fn, pp, 1, &json->options);
            }
            if (sv == 0 || !ejsIs(ejs, sv, String)) {
                if (ejs->exception) {
                    ejsThrowTypeError(ejs, "Cannot serialize property %@", qname.name);
                    SET_VISITED(obj, 0);
                    return 0;
                }
            } else {
                if (json->replacer) {
                    replacerArgs[0] = (EjsObj*) qname.name; 
                    replacerArgs[1] = (EjsObj*) sv; 

                    /* function replacer(key: String, value: String): String */
                    sv = ejsRunFunction(ejs, json->replacer, obj, 2, (EjsObj**) replacerArgs);
                }
                mprPutBlockToBuf(json->buf, sv->value, sv->length * sizeof(wchar));
            }
            if ((slotNum + 1) < count || json->commas) {
                mprPutCharToWideBuf(json->buf, ',');
            }
            if (json->pretty) {
                mprPutCharToWideBuf(json->buf, '\n');
            }
        }
        SET_VISITED(obj, 0);
    }
    --ejs->serializeDepth; 
    if (json->pretty) {
        for (i = ejs->serializeDepth; i > 0; i--) {
            mprPutStringToWideBuf(json->buf, json->indent);
        }
    }
    mprPutCharToWideBuf(json->buf, isArray ? ']' : '}');
    mprAddNullToWideBuf(json->buf);

    if (--json->nest == 0) {
        result = ejsCreateString(ejs, mprGetBufStart(json->buf), mprGetBufLength(json->buf) / sizeof(wchar));
        mprRemoveRoot(json->buf);
    } else {
        result = 0;
    }
    return result;
}
Beispiel #2
0
/*
    List the various property slot assignments
 */
static void lstSlotAssignments(EjsMod *mp, EjsModule *module, EjsObj *parent, int slotNum, EjsObj *obj)
{
    Ejs             *ejs;
    EjsTrait        *trait;
    EjsType         *type;
    EjsObj          *vp;
    EjsPot          *prototype;
    EjsFunction     *fun;
    EjsBlock        *block;
    EjsName         qname;
    int             i, numInherited, count;

    mprAssert(obj);
    mprAssert(module);

    ejs = mp->ejs;
    if (VISITED(obj)) {
        return;
    }
    SET_VISITED(obj, 1);

    if (obj == ejs->global) {
        mprFprintf(mp->file,  "\n#\n"
            "#  Global slot assignments (Num prop %d)\n"
            "#\n", ejsGetLength(ejs, obj));

        /*
            List slots for global
         */
        for (i = module->firstGlobal; i < module->lastGlobal; i++) {
            trait = ejsGetPropertyTraits(ejs, ejs->global, i);
            qname = ejsGetPropertyName(ejs, ejs->global, i);
            if (qname.name == 0) {
                continue;
            }
            lstVarSlot(mp, module, &qname, trait, i);
        }

        /*
            List slots for the initializer
         */
        fun = (EjsFunction*) module->initializer;
        if (fun) {
            mprFprintf(mp->file,  "\n#\n"
                "#  Initializer slot assignments (Num prop %d)\n"
                "#\n", ejsGetLength(ejs, (EjsObj*) fun));

            count = ejsGetLength(ejs, (EjsObj*) fun);
            for (i = 0; i < count; i++) {
                trait = ejsGetPropertyTraits(ejs, (EjsObj*) fun, i);
                qname = ejsGetPropertyName(ejs, (EjsObj*) fun, i);
                if (qname.name == 0) {
                    continue;
                }
                mprAssert(trait);
                lstVarSlot(mp, module, &qname, trait, i);
            }
        }

    } else if (ejsIsFunction(ejs, obj)) {
        fun = (EjsFunction*) obj;
        count = ejsGetLength(ejs, (EjsObj*) obj);
        if (count > 0) {
            mprFprintf(mp->file,  "\n#\n"
                "#  Local slot assignments for the \"%@\" function (Num slots %d)\n"
                "#\n", fun->name, count);

            for (i = 0; i < count; i++) {
                trait = ejsGetPropertyTraits(ejs, obj, i);
                mprAssert(trait);
                qname = ejsGetPropertyName(ejs, obj, i);
                lstVarSlot(mp, module, &qname, trait, i);
            }
        }

    } else if (ejsIsType(ejs, obj)) {
        /*
            Types
         */
        type = (EjsType*) obj;
        mprFprintf(mp->file,  "\n#\n"
            "#  Class slot assignments for the \"%@\" class (Num slots %d)\n"
            "#\n", type->qname.name,
            ejsGetLength(ejs, (EjsObj*) type));

        count = ejsGetLength(ejs, (EjsObj*) type);
        for (i = 0; i < count; i++) {
            trait = ejsGetPropertyTraits(ejs, (EjsObj*) type, i);
            mprAssert(trait);
            qname = ejsGetPropertyName(ejs, obj, i);
            lstVarSlot(mp, module, &qname, trait, i);
        }

        prototype = type->prototype;
        if (type->baseType && type->baseType->prototype) {
            numInherited = ejsGetLength(ejs, type->baseType->prototype);
        } else {
            numInherited = 0;
        }
        mprFprintf(mp->file,  "\n#\n"
            "#  Instance slot assignments for the \"%@\" class (Num prop %d, num inherited %d)\n"
            "#\n", type->qname.name,
            prototype ? ejsGetLength(ejs, prototype): 0, numInherited);

        if (prototype) {
            count = ejsGetLength(ejs, prototype);
            for (i = 0; i < count; i++) {
                trait = ejsGetPropertyTraits(ejs, prototype, i);
                mprAssert(trait);
                qname = ejsGetPropertyName(ejs, prototype, i);
                if (qname.name) {
                    lstVarSlot(mp, module, &qname, trait, i);
                }
            }
        }

    } else if (ejsIsBlock(ejs, obj)) {
        qname = ejsGetPropertyName(ejs, parent, slotNum);
        block = (EjsBlock*) obj;
        count = ejsGetLength(ejs, (EjsObj*) block);
        if (count > 0) {
            mprFprintf(mp->file,  
                "\n#\n"
                "#  Block slot assignments for the \"%@\" (Num slots %d)\n"
                "#\n", qname.name, ejsGetLength(ejs, obj));
            
            count = ejsGetLength(ejs, obj);
            for (i = 0; i < count; i++) {
                trait = ejsGetPropertyTraits(ejs, obj, i);
                mprAssert(trait);
                qname = ejsGetPropertyName(ejs, obj, i);
                lstVarSlot(mp, module, &qname, trait, i);
            }
        }
    }

    /*
        Now recurse on types, functions and blocks
     */
    if (obj == ejs->global) {
        i = module->firstGlobal;
        count = module->lastGlobal;
    } else {
        i = 0;
        count = ejsGetLength(ejs, obj);
    }
    for (; i < count; i++) {
        qname = ejsGetPropertyName(ejs, obj, i);
        vp = ejsGetProperty(ejs, obj, i);
        if (vp == 0) {
            continue;
        }
        if (ejsIsType(ejs, vp) || ejsIsFunction(ejs, vp) || ejsIsBlock(ejs, vp)) {
            lstSlotAssignments(mp, module, obj, i, vp);
        }
    }
    SET_VISITED(obj, 0);
}
Beispiel #3
0
/*
    Find a variable in an object considering namespaces. If the space is "", then search for the property name using
    the set of open namespaces.
 */
int ejsLookupVarWithNamespaces(Ejs *ejs, EjsAny *obj, EjsName name, EjsLookup *lookup)
{
    EjsNamespace    *nsp;
    EjsName         qname, target;
    EjsString       *space;
    EjsBlock        *b;
    MprList         *globalSpaces;
    int             next, slotNum;

    assert(obj);
    assert(name.name);
    assert(name.space);
    assert(lookup);

    b = (EjsBlock*) ejs->global;
    globalSpaces = &b->namespaces;

    if (name.space->value[0]) {
        /* Lookup with an explicit namespace */
        slotNum = ejsLookupProperty(ejs, obj, name);
        lookup->name = name;

    } else {
        /* 
            Lookup with the set of open namespaces in the current scope 
            Special lookup with space == NULL. Means lookup only match if there is only one property of this name 
         */
        qname.space = NULL;
        qname.name = name.name;
        if ((slotNum = ejsLookupProperty(ejs, obj, qname)) >= 0) {
            if (TYPE(obj)->virtualSlots) {
                lookup->name = name;
            } else {
                target = ejsGetPropertyName(ejs, obj, slotNum);
                lookup->name = target;
                space = name.space;
                if (space->value[0] && space != target.space) {
                    /* Unique name match. Name matches, but namespace does not */
                    slotNum = -1;
                } else if (target.space && target.space->value[0]) {
                    /* OPT - Look at global spaces first */
                    for (next = -1; (nsp = mprGetPrevItem(globalSpaces, &next)) != 0; ) {
                        if (nsp->value == target.space) {
                            goto done;
                        }
                    }
                    //  OPT -- need a fast way to know if the space is a standard reserved namespace or not */
                    /* Verify namespace is open */
                    for (b = ejs->state->bp; b; b = b->scope) {
                        //  OPT. Doing some namespaces multiple times. Fix in compiler.
                        for (next = -1; (nsp = mprGetPrevItem(&b->namespaces, &next)) != 0; ) {
                            if (nsp->value == target.space) {
                                goto done;
                            }
                        }
                    }
                    slotNum = -1;
                }
            }

        } else {
            qname = name;
            for (b = ejs->state->bp; b; b = b->scope) {
                for (next = -1; (nsp = (EjsNamespace*) mprGetPrevItem(&b->namespaces, &next)) != 0; ) {
                    qname.space = nsp->value;
                    if ((slotNum = ejsLookupProperty(ejs, obj, qname)) >= 0) {
                        lookup->name = qname;
                        goto done;
                    }
                }
            }
            for (next = -1; (nsp = mprGetPrevItem(globalSpaces, &next)) != 0; ) {
                qname.space = nsp->value;
                if ((slotNum = ejsLookupProperty(ejs, obj, qname)) >= 0) {
                    lookup->name = qname;
                    goto done;
                }
            }
        }
    }
done:
    if (slotNum >= 0) {
        //  OPT MUST GET RID OF THIS. Means that every store does a get
        lookup->ref = ejsGetProperty(ejs, obj, slotNum);
        if (ejs->exception) {
            slotNum = -1;
        } else {
            lookup->obj = obj;
            lookup->slotNum = slotNum;
            lookup->trait = ejsGetPropertyTraits(ejs, lookup->obj, lookup->slotNum);
        }
    }
    return slotNum;
}
Beispiel #4
0
static void lstFunction(EjsMod *mp, EjsModule *module, EjsObj *block, int slotNum, EjsName qname, EjsFunction *fun, 
        int attributes)
{
    Ejs         *ejs;
    EjsTrait    *trait;
    EjsName     lname;
    EjsType     *resultType;
    EjsPot      *activation;
    EjsString   *space, *blockName;
    int         i, numLocals, numProp;

    ejs = mp->ejs;
    activation = fun->activation;
    numProp = activation ? activation->numProp : 0;
    space = mapSpace(ejs, qname.space);

    mprFprintf(mp->file,  "\nFUNCTION:   ");

    /*
        Do the function declaration
     */
    if (attributes) {
        if (slotNum < 0) {
            /* Special just for global initializers */
            mprFprintf(mp->file,  "[initializer]  %@ %sfunction %@(", space, getAttributeString(mp, attributes), 
                qname.name);
        } else {
            blockName = getBlockName(mp, block, slotNum);
            mprFprintf(mp->file,  "[%@-%02d]  %@ %sfunction %@(", blockName, slotNum, space,
                getAttributeString(mp, attributes), qname.name);
        }
    } else {
        blockName = getBlockName(mp, block, slotNum);
        mprFprintf(mp->file,  "[%@-%02d]  %@ function %@(", blockName, slotNum, space, qname.name);
    }

    for (i = 0; i < (int) fun->numArgs; ) {
        lname = ejsGetPropertyName(ejs, activation, i);
        trait = ejsGetPropertyTraits(ejs, activation, i);
        if (trait->type) {
            mprFprintf(mp->file,  "%@: %@", lname.name, trait->type->qname.name);
        } else {
            mprFprintf(mp->file,  "%@", lname.name);
        }
        if (++i < (int) fun->numArgs) {
            mprFprintf(mp->file,  ", ");
        }
    }

    resultType = fun->resultType;
    mprFprintf(mp->file,  ") : %@\n", resultType ? resultType->qname.name : EST(Void)->qname.name);

    /*
        Repeat the args
     */
    for (i = 0; i < (int) fun->numArgs; i++) {
        lname = ejsGetPropertyName(ejs, activation, i);
        trait = ejsGetPropertyTraits(ejs, activation, i);
        mprFprintf(mp->file,  "     ARG:   [arg-%02d]   %@ %@", i, lname.space, lname.name);
        if (trait->type) {
            mprFprintf(mp->file,  " : %@", trait->type->qname.name);
        }
        mprFprintf(mp->file,  "\n");
    }
    numLocals = numProp - fun->numArgs;
    for (i = 0; i < numLocals; i++) {
        lname = ejsGetPropertyName(ejs, activation, i + fun->numArgs);
        trait = ejsGetPropertyTraits(ejs, activation, i + fun->numArgs);
        mprFprintf(mp->file,  "   LOCAL:   [local-%02d]  var %@", i + fun->numArgs, lname.name);
        if (trait->type) {
            mprFprintf(mp->file,  " : %@", trait->type->qname.name);
        }
        mprFprintf(mp->file,  "\n");
    }
    if (fun->body.code) {
        mprFprintf(mp->file,  "\n");
        interp(mp, module, fun);
    }
    mprFprintf(mp->file,  "\n");
}