Esempio n. 1
0
static ejsval
_ejs_RegExp_impl (ejsval env, ejsval _this, uint32_t argc, ejsval *args)
{
    EJSRegExp *re;

    if (EJSVAL_IS_UNDEFINED(_this)) {
        // called as a function
        _this = _ejs_object_new(_ejs_RegExp_prototype, &_ejs_RegExp_specops);
    }

    re = (EJSRegExp*)EJSVAL_TO_OBJECT(_this);

    re->pattern = _ejs_undefined;
    re->flags = _ejs_undefined;

    if (argc > 0) re->pattern = args[0];
    if (argc > 1) re->flags = args[1];

    if (!EJSVAL_IS_STRING(re->pattern))
        EJS_NOT_IMPLEMENTED();

    EJSPrimString *flat_pattern = _ejs_string_flatten (re->pattern);
    jschar* chars = flat_pattern->data.flat;

    const unsigned char* pcre16_tables = pcre16_maketables();
    const char *pcre_error;
    int pcre_erroffset;

    re->compiled_pattern = pcre16_compile(chars,
                                          PCRE_UTF16 | PCRE_NO_UTF16_CHECK,
                                          &pcre_error, &pcre_erroffset,
                                          pcre16_tables);

    _ejs_object_define_value_property (_this, _ejs_atom_source, re->pattern, EJS_PROP_NOT_ENUMERABLE | EJS_PROP_NOT_CONFIGURABLE | EJS_PROP_NOT_WRITABLE);

    if (EJSVAL_IS_STRING(re->flags)) {
        EJSPrimString *flat_flags = _ejs_string_flatten(re->flags);
        chars = flat_flags->data.flat;

        for (int i = 0; i < flat_flags->length; i ++) {
            if      (chars[i] == 'g' && !re->global)     { re->global     = EJS_TRUE; continue; }
            else if (chars[i] == 'i' && !re->ignoreCase) { re->ignoreCase = EJS_TRUE; continue; }
            else if (chars[i] == 'm' && !re->multiline)  { re->multiline  = EJS_TRUE; continue; }
            else if (chars[i] == 'y' && !re->sticky)     { re->sticky     = EJS_TRUE; continue; }
            else if (chars[i] == 'u' && !re->unicode)    { re->unicode    = EJS_TRUE; continue; }
            _ejs_throw_nativeerror_utf8 (EJS_SYNTAX_ERROR, "Invalid flag supplied to RegExp constructor");
        }
    }

    return _this;
}
Esempio n. 2
0
static ejsval
_ejs_arguments_specop_get (ejsval obj, ejsval propertyName, ejsval receiver)
{
    EJSArguments* arguments = EJSVAL_TO_ARGUMENTS(obj);

    // check if propertyName is an integer, or a string that we can convert to an int
    EJSBool is_index = EJS_FALSE;
    ejsval idx_val = ToNumber(propertyName);
    int idx;
    if (EJSVAL_IS_NUMBER(idx_val)) {
        double n = EJSVAL_TO_NUMBER(idx_val);
        if (floor(n) == n) {
            idx = (int)n;
            is_index = EJS_TRUE;
        }
    }

    if (is_index) {
        if (idx < 0 || idx > arguments->argc) {
            printf ("getprop(%d) on an arguments, returning undefined\n", idx);
            return _ejs_undefined;
        }
        return arguments->args[idx];
    }

    // we also handle the length getter here
    if (EJSVAL_IS_STRING(propertyName) && !ucs2_strcmp (_ejs_ucs2_length, EJSVAL_TO_FLAT_STRING(propertyName))) {
        return NUMBER_TO_EJSVAL(arguments->argc);
    }

    // otherwise we fallback to the object implementation
    return _ejs_Object_specops.Get (obj, propertyName, receiver);
}
Esempio n. 3
0
// returns an EJSPrimString*.
// maybe we could change it to return a char* to match ToDouble?  that way string concat wouldn't create
// temporary strings for non-PrimString objects only to throw them away after concatenation?
ejsval ToString(ejsval exp)
{
    if (EJSVAL_IS_MAGIC_IMPL(exp)) {
        // holes in dense arrays end up here
        return _ejs_atom_empty;
    }
    else if (EJSVAL_IS_NULL(exp))
        return _ejs_atom_null;
    else if (EJSVAL_IS_UNDEFINED(exp))
        return _ejs_atom_undefined;
    else if (EJSVAL_IS_BOOLEAN(exp)) 
        return EJSVAL_TO_BOOLEAN(exp) ? _ejs_atom_true : _ejs_atom_false;
    else if (EJSVAL_IS_NUMBER(exp))
        return NumberToString(EJSVAL_TO_NUMBER(exp));
    else if (EJSVAL_IS_STRING(exp))
        return exp;
    else if (EJSVAL_IS_OBJECT(exp)) {
        ejsval toString = _ejs_object_getprop (exp, _ejs_atom_toString);
        if (!EJSVAL_IS_FUNCTION(toString)) {
            return _ejs_Object_prototype_toString(_ejs_null, exp, 0, NULL);
        }

        // should we be checking if this returns a string?  i'd assume so...
        return _ejs_invoke_closure (toString, exp, 0, NULL);
    }
    else
        EJS_NOT_IMPLEMENTED();
}
Esempio n. 4
0
static ejsval
_ejs_arraybuffer_specop_get (ejsval obj, ejsval propertyName, ejsval receiver)
{
    // check if propertyName is an integer, or a string that we can convert to an int
    EJSBool is_index = EJS_FALSE;
    int idx = 0;
    if (EJSVAL_IS_NUMBER(propertyName)) {
        double n = EJSVAL_TO_NUMBER(propertyName);
        if (floor(n) == n) {
            idx = (int)n;
            is_index = EJS_TRUE;
        }
    }

    if (is_index) {
        if (idx < 0 || idx > EJS_ARRAY_LEN(obj)) {
            printf ("getprop(%d) on an array, returning undefined\n", idx);
            return _ejs_undefined;
        }
        return EJS_DENSE_ARRAY_ELEMENTS(obj)[idx];
    }

    // we also handle the length getter here
    if (EJSVAL_IS_STRING(propertyName) && !ucs2_strcmp (_ejs_ucs2_byteLength, EJSVAL_TO_FLAT_STRING(propertyName))) {
        return NUMBER_TO_EJSVAL (EJS_ARRAY_BUFFER_BYTE_LEN(obj));
    }

    // otherwise we fallback to the object implementation
    return _ejs_Object_specops.get (obj, propertyName, receiver);
}
Esempio n. 5
0
static EJS_NATIVE_FUNC(_ejs_Process_chdir) {
    ejsval dir = _ejs_undefined;
    if (argc > 0)
        dir = args[0];

    if (!EJSVAL_IS_STRING(dir))
        _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "chdir passed non-string");
        
    char *dir_utf8 = ucs2_to_utf8(EJSVAL_TO_FLAT_STRING(dir));
    chdir(dir_utf8);
    free(dir_utf8);

    return _ejs_undefined;
}
Esempio n. 6
0
// same as SameValue, except in its treatment of +/- 0
EJSBool
SameValueZero(ejsval x, ejsval y)
{
    // 1. ReturnIfAbrupt(x).
    // 2. ReturnIfAbrupt(y).

    // 3. If Type(x) is different from Type(y), return false.
    if (EJSVAL_TO_TAG(x) != EJSVAL_TO_TAG(y)) return EJS_FALSE;

    // 4. If Type(x) is Undefined, return true.
    if (EJSVAL_IS_UNDEFINED(x)) return EJS_TRUE;

    // 5. If Type(x) is Null, return true.
    if (EJSVAL_IS_NULL(x)) return EJS_TRUE;

    // 6. If Type(x) is Number, then
    if (EJSVAL_IS_NUMBER(x)) {
        //    a. If x is NaN and y is NaN, return true.
        if (isnan(EJSVAL_TO_NUMBER(x)) && isnan(EJSVAL_TO_NUMBER(y))) return EJS_TRUE;
        //    b. If x is +0 and y is -0, return true.
        if (EJSVAL_TO_NUMBER(x) == 0.0 && EJSDOUBLE_IS_NEGZERO(EJSVAL_TO_NUMBER(y))) return EJS_TRUE;
        //    c. If x is -0 and y is +0, return tryue.
        if (EJSDOUBLE_IS_NEGZERO(EJSVAL_TO_NUMBER(x)) == 0.0 && EJSVAL_TO_NUMBER(y) == 0) return EJS_TRUE;
        //    d. If x is the same Number value as y, return true.
        if (EJSVAL_TO_NUMBER(x) == EJSVAL_TO_NUMBER(y)) return EJS_TRUE;
        //    e. Return false.
        return EJS_FALSE;
    }
    // 7. If Type(x) is String, then
    if (EJSVAL_IS_STRING(x)) {
        //    a. If x and y are exactly the same sequence of code units (same length and same code units in corresponding positions) return true;
        //       otherwise, return false.
        if (EJSVAL_TO_STRLEN(x) != EJSVAL_TO_STRLEN(y)) return EJS_FALSE;

        // XXX there is doubtless a more efficient way to compare two ropes, but we convert but to flat strings for now.
        return ucs2_strcmp (EJSVAL_TO_FLAT_STRING(x), EJSVAL_TO_FLAT_STRING(y)) ? EJS_FALSE : EJS_TRUE;
    }
    // 8. If Type(x) is Boolean, then
    if (EJSVAL_IS_BOOLEAN(x)) {
        //    a. If x and y are both true or both false, then return true; otherwise, return false.
        return EJSVAL_TO_BOOLEAN(x) == EJSVAL_TO_BOOLEAN(y) ? EJS_TRUE : EJS_FALSE;
    }
    // 9. If Type(x) is Symbol, then
    if (EJSVAL_IS_SYMBOL(x)) {
        //    a. If x and y are both the same Symbol value, then return true; otherwise, return false.
        EJS_NOT_IMPLEMENTED();
    }
    // 10. Return true if x and y are the same Object value. Otherwise, return false.
    return EJSVAL_EQ(x, y);
}
Esempio n. 7
0
EJSBool ToEJSBool(ejsval exp)
{
    if (EJSVAL_IS_NULL(exp) || EJSVAL_IS_UNDEFINED(exp))
        return EJS_FALSE;
    else if (EJSVAL_IS_BOOLEAN(exp))
        return EJSVAL_TO_BOOLEAN(exp);
    else if (EJSVAL_IS_NUMBER(exp))
        return EJSVAL_TO_NUMBER(exp) != 0;
    else if (EJSVAL_IS_STRING(exp))
        return EJSVAL_TO_STRLEN(exp) != 0;
    else if (EJSVAL_IS_OBJECT(exp))
        return EJS_TRUE;
    else
        EJS_NOT_IMPLEMENTED();
}
Esempio n. 8
0
static ejsval
_ejs_require_impl (ejsval env, ejsval _this, uint32_t argc, ejsval *args)
{
    if (argc < 1) {
        return _ejs_undefined;
    }

    ejsval arg = args[0];

    if (!EJSVAL_IS_STRING(arg)) {
        _ejs_log ("required called with non-string\n");
        return _ejs_null;
    }

    return _ejs_module_get(arg);
}
Esempio n. 9
0
static ejsval
_ejs_Process_chdir (ejsval env, ejsval _this, uint32_t argc, ejsval* args)
{
    ejsval dir = _ejs_undefined;
    if (argc > 0)
        dir = args[0];

    if (!EJSVAL_IS_STRING(dir))
        _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "chdir passed non-string");
        
    char *dir_utf8 = ucs2_to_utf8(EJSVAL_TO_FLAT_STRING(dir));
    chdir(dir_utf8);
    free(dir_utf8);

    return _ejs_undefined;
}
Esempio n. 10
0
static ejsval
_ejs_path_resolve (ejsval env, ejsval _this, uint32_t argc, ejsval* args)
{
    char** paths_utf8 = (char**)calloc(argc + 1, sizeof(char*));
    int num_paths = 0;

    char cwd[MAXPATHLEN];
    getcwd(cwd, MAXPATHLEN);

    paths_utf8[num_paths++] = strdup(cwd);

    for (int i = 0; i < argc; i ++) {
        ejsval arg = args[i];

        if (!EJSVAL_IS_STRING(arg)) {
            for (int j = 0; j < num_paths; j ++) free(paths_utf8[j]);
            free (paths_utf8);
            _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Arguments to path.resolve must be strings");
        }

        paths_utf8[num_paths++] = ucs2_to_utf8(EJSVAL_TO_FLAT_STRING(arg));
    }

    int start_path;
    for (start_path = num_paths-1; start_path >= 0; start_path --) {
        if (paths_utf8[start_path][0] == '/')
            break;
    }
    // at this point paths_utf8[start_path] is our "root" for
    // resolving.  it is either the right-most absolute path in the
    // argument list, or $cwd if there wasn't an absolute path in the
    // args.

    char* resolved = resolvev(&paths_utf8[start_path], num_paths - start_path);

    ejsval rv = _ejs_string_new_utf8(resolved);

    free (resolved);
    for (int j = 0; j < num_paths; j ++) free(paths_utf8[j]);
    free (paths_utf8);

    return rv;
}
Esempio n. 11
0
// ECMA262 15.3.4.5
static ejsval
_ejs_Function_prototype_bind (ejsval env, ejsval _this, uint32_t argc, ejsval *args)
{
    /* 1. Let Target be the this value. */
    ejsval Target = _this;

    /* 2. If IsCallable(Target) is false, throw a TypeError exception. */
    if (!EJSVAL_IS_CALLABLE(Target)) {
        _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "object not a function");
    }

    ejsval thisArg = _ejs_undefined;
    if (argc > 0)
        thisArg = args[0];

    /* 3. Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order. */
    int bound_argc = argc > 1 ? argc - 1 : 0;

    /* 4. Let F be a new native ECMAScript object . */

    ejsval bound_env = EJS_BOUNDFUNC_ENV_NEW(bound_argc);
    EJS_BOUNDFUNC_ENV_SET_TARGET(bound_env, Target);
    EJS_BOUNDFUNC_ENV_SET_THIS(bound_env, thisArg);
    EJS_BOUNDFUNC_ENV_SET_ARGC(bound_env, NUMBER_TO_EJSVAL(bound_argc));
    for (int i = 0; i < bound_argc; i ++) {
        EJS_BOUNDFUNC_ENV_SET_ARG(bound_env, i, args[i+1]);
    }

    ejsval target_name = _ejs_object_getprop (Target, _ejs_atom_name);
    ejsval bound_name;
    if (EJSVAL_IS_STRING(target_name))
        bound_name = _ejs_string_concat(_ejs_atom_bound_space, target_name);
    else
        bound_name = _ejs_atom_bound_space;
    

    ejsval F = _ejs_function_new (bound_env, bound_name, bound_wrapper);
    EJSFunction *F_ = (EJSFunction*)EJSVAL_TO_OBJECT(F);

    F_->bound = EJS_TRUE;

    return F;
}
Esempio n. 12
0
ejsval ToNumber(ejsval exp)
{
    if (EJSVAL_IS_NUMBER(exp))
        return exp;
    else if (EJSVAL_IS_BOOLEAN(exp))
        return EJSVAL_TO_BOOLEAN(exp) ? _ejs_one : _ejs_zero;
    else if (EJSVAL_IS_STRING(exp)) {
        char* num_utf8 = ucs2_to_utf8(EJSVAL_TO_FLAT_STRING(exp));
        char *endptr;
        double d = strtod(num_utf8, &endptr);
        if (*endptr != '\0')
            return _ejs_nan;
        ejsval rv = NUMBER_TO_EJSVAL(d); // XXX NaN
        free (num_utf8);
        return rv;
    }
    else if (EJSVAL_IS_UNDEFINED(exp))
        return _ejs_nan;
    else if (EJSVAL_IS_OBJECT(exp)) {
        if (EJSVAL_IS_DATE(exp)) {
            return NUMBER_TO_EJSVAL(_ejs_date_get_time ((EJSDate*)EJSVAL_TO_OBJECT(exp)));
        }
        else if (EJSVAL_IS_ARRAY(exp)) {
            int len = EJS_ARRAY_LEN(exp);
            if (len == 0) return _ejs_zero;
            else if (len > 1) return _ejs_nan;
            else {
                // XXX we need to support sparse arrays here too
                EJS_ASSERT (EJSVAL_IS_DENSE_ARRAY(exp));
                return ToNumber(EJS_DENSE_ARRAY_ELEMENTS(exp)[0]);
            }
        }
        else
            return _ejs_nan;
    }
    else
        EJS_NOT_IMPLEMENTED();
}
Esempio n. 13
0
ejsval
_ejs_op_mod (ejsval lhs, ejsval rhs)
{
    if (EJSVAL_IS_NUMBER(lhs)) {
        if (EJSVAL_IS_NUMBER(rhs)) {
            return NUMBER_TO_EJSVAL (fmod(EJSVAL_TO_NUMBER(lhs), EJSVAL_TO_NUMBER(rhs)));
        }
        else {
            // need to call valueOf() on the object, or convert the string to a number
            EJS_NOT_IMPLEMENTED();
        }
    }
    else if (EJSVAL_IS_STRING(lhs)) {
        // string+ with anything we don't implement yet - it will call toString() on objects, and convert a number to a string
        EJS_NOT_IMPLEMENTED();
    }
    else {
        // object+... how does js implement this anyway?
        EJS_NOT_IMPLEMENTED();
    }

    return _ejs_nan;
}
Esempio n. 14
0
ejsval
_ejs_op_typeof (ejsval exp)
{
    if (EJSVAL_IS_NULL(exp))
        return _ejs_atom_null;
    else if (EJSVAL_IS_BOOLEAN(exp))
        return _ejs_atom_boolean;
    else if (EJSVAL_IS_STRING(exp))
        return _ejs_atom_string;
    else if (EJSVAL_IS_SYMBOL(exp))
        return _ejs_atom_symbol;
    else if (EJSVAL_IS_NUMBER(exp))
        return _ejs_atom_number;
    else if (EJSVAL_IS_UNDEFINED(exp))
        return _ejs_atom_undefined;
    else if (EJSVAL_IS_OBJECT(exp)) {
        if (EJSVAL_IS_FUNCTION(exp))
            return _ejs_atom_function;
        else
            return _ejs_atom_object;
    }
    else
        EJS_NOT_IMPLEMENTED();
}
Esempio n. 15
0
ejsval ToObject(ejsval exp)
{
    if (EJSVAL_IS_BOOLEAN(exp)) {
        ejsval new_boolean = _ejs_object_new (_ejs_Boolean_proto, &_ejs_Boolean_specops);
        _ejs_invoke_closure (_ejs_Boolean, new_boolean, 1, &exp);
        return new_boolean;
    }
    else if (EJSVAL_IS_NUMBER(exp)) {
        ejsval new_number = _ejs_object_new (_ejs_Number_proto, &_ejs_Number_specops);
        _ejs_invoke_closure (_ejs_Number, new_number, 1, &exp);
        return new_number;
    }
    else if (EJSVAL_IS_STRING(exp)) {
        ejsval new_str = _ejs_object_new (_ejs_String_prototype, &_ejs_String_specops);
        _ejs_invoke_closure (_ejs_String, new_str, 1, &exp);
        return new_str;
    }
    else if (EJSVAL_IS_UNDEFINED(exp))
        return exp; // XXX
    else if (EJSVAL_IS_OBJECT(exp))
        return exp;
    else
        EJS_NOT_IMPLEMENTED();
}
Esempio n. 16
0
ejsval
_ejs_op_typeof_is_string(ejsval exp)
{
    return EJSVAL_IS_STRING(exp) ? _ejs_true : _ejs_false;
}
Esempio n. 17
0
static ejsval
_ejs_path_relative (ejsval env, ejsval _this, uint32_t argc, ejsval* args)
{
    ejsval from = _ejs_undefined;
    ejsval to   = _ejs_undefined;

    if (argc > 0) from = args[0];
    if (argc > 1) to   = args[1];

    if (!EJSVAL_IS_STRING(from) || !EJSVAL_IS_STRING(to))
        _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Arguments to path.relative must be strings");

    char *from_utf8 = ucs2_to_utf8(EJSVAL_TO_FLAT_STRING(from));
    char *to_utf8   = ucs2_to_utf8(EJSVAL_TO_FLAT_STRING(to));

    if (from_utf8[0] != '/') from_utf8 = make_absolute(from_utf8);
    if (to_utf8[0]   != '/') to_utf8   = make_absolute(to_utf8);

    char* p = to_utf8 + strlen(to_utf8) - 1;
    int up = 0;
    EJSBool seen_slash = EJS_FALSE;

    while (p != to_utf8) {
        if (*p == '/') {
            if (seen_slash) continue; // skip adjacent slashes
            seen_slash = EJS_TRUE;
            char* prefix = strndup(to_utf8, p - to_utf8);
            if (!strcmp(from_utf8, prefix)) {
                up = -1;
                free (prefix);
                goto done;
            }
            if (strstr(from_utf8, prefix) == from_utf8) {
                free (prefix);
                goto done;
            }
            free (prefix);
            up ++;
        }
        else {
            seen_slash = EJS_FALSE;
        }
        p--;
    }
    // we made it all the way to the end, fall through to building up our string

 done:
    {
        ejsval dotdotslash = _ejs_string_new_utf8("../");
        ejsval rv = _ejs_string_new_utf8(p+1);
        while (up >= 0) {
            rv = _ejs_string_concat(dotdotslash, rv);
            up--;
        }

        free (from_utf8);
        free (to_utf8);

        return rv;
    }
}