// ES6: 23.2.3.9 // get Set.prototype.size static ejsval _ejs_Set_prototype_get_size (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { // 1. Let S be the this value. ejsval S = _this; // 2. If Type(S) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(S)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set size getter called with non-object this."); } // 3. If S does not have a [[SetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_SET(S)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set size getter called with non-Set this."); } EJSSet* _set = EJSVAL_TO_SET(S); // 4. If S’s [[SetData]] internal slot is undefined, then throw a TypeError exception. // 5. Let entries be the List that is the value of S’s [[SetData]] internal slot. EJSSetValueEntry* entries = _set->head_insert; // 6. Let count be 0. uint32_t count = 0; // 7. For each e that is an element of entries for (EJSSetValueEntry* e = entries; e; e = e->next_insert) { // a. If e is not empty then if (!EJSVAL_IS_NO_ITER_VALUE_MAGIC(e->value)) // i. Set count to count+1. count ++; } // 8. Return count. return NUMBER_TO_EJSVAL(count); }
ejsval _ejs_typedarray_new_from_array (EJSTypedArrayType element_type, ejsval arrayObj) { EJSObject *arr = EJSVAL_TO_OBJECT(arrayObj); int arrlen = EJSARRAY_LEN(arr); ejsval typedarr = _ejs_typedarray_new (element_type, arrlen); int i; void* data = _ejs_typedarray_get_data (EJSVAL_TO_OBJECT(typedarr)); // this is woefully underoptimized... for (i = 0; i < arrlen; i ++) { ejsval item = _ejs_object_getprop (arrayObj, NUMBER_TO_EJSVAL(i)); switch (element_type) { case EJS_TYPEDARRAY_INT8: ((int8_t*)data)[i] = (int8_t)EJSVAL_TO_NUMBER(item); break; case EJS_TYPEDARRAY_UINT8: ((uint8_t*)data)[i] = (uint8_t)EJSVAL_TO_NUMBER(item); break; case EJS_TYPEDARRAY_UINT8CLAMPED: EJS_NOT_IMPLEMENTED(); case EJS_TYPEDARRAY_INT16: ((int16_t*)data)[i] = (int16_t)EJSVAL_TO_NUMBER(item); break; case EJS_TYPEDARRAY_UINT16: ((uint16_t*)data)[i] = (uint16_t)EJSVAL_TO_NUMBER(item); break; case EJS_TYPEDARRAY_INT32: ((int32_t*)data)[i] = (int32_t)EJSVAL_TO_NUMBER(item); break; case EJS_TYPEDARRAY_UINT32: ((uint32_t*)data)[i] = (uint32_t)EJSVAL_TO_NUMBER(item); break; case EJS_TYPEDARRAY_FLOAT32: ((float*)data)[i] = (float)EJSVAL_TO_NUMBER(item); break; case EJS_TYPEDARRAY_FLOAT64: ((double*)data)[i] = (double)EJSVAL_TO_NUMBER(item); break; default: EJS_NOT_REACHED(); } } return typedarr; }
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); }
void _ejs_function_init(ejsval global) { trace = getenv("EJS_TRACE") != NULL; _ejs_function_init_proto(); _ejs_Function = _ejs_function_new_without_proto (_ejs_null, _ejs_atom_Function, (EJSClosureFunc)_ejs_Function_impl); _ejs_object_setprop (global, _ejs_atom_Function, _ejs_Function); // ECMA262 15.3.3.1 _ejs_object_define_value_property (_ejs_Function, _ejs_atom_prototype, _ejs_Function_prototype, EJS_PROP_NOT_ENUMERABLE | EJS_PROP_NOT_CONFIGURABLE | EJS_PROP_NOT_WRITABLE); // ECMA262 15.3.3.2 _ejs_object_define_value_property (_ejs_Function, _ejs_atom_length, NUMBER_TO_EJSVAL(1), EJS_PROP_NOT_ENUMERABLE | EJS_PROP_NOT_CONFIGURABLE | EJS_PROP_NOT_WRITABLE); #define PROTO_METHOD(x) EJS_INSTALL_ATOM_FUNCTION_FLAGS(_ejs_Function_prototype, x, _ejs_Function_prototype_##x, EJS_PROP_NOT_ENUMERABLE) PROTO_METHOD(toString); PROTO_METHOD(apply); PROTO_METHOD(call); PROTO_METHOD(bind); #undef PROTO_METHOD }
static ejsval _ejs_dataview_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; } } // Index for DataView is byte-based. if (is_index) { if (idx < 0 || idx > EJS_DATA_VIEW_BYTE_LEN(obj)) return _ejs_undefined; void *data = _ejs_dataview_get_data (EJSVAL_TO_OBJECT(obj)); return NUMBER_TO_EJSVAL ((double)((unsigned char*)data)[idx]); } // otherwise we fallback to the object implementation return _ejs_Object_specops.get (obj, propertyName, receiver); }
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); }
ejsval _ejs_op_bitwise_or (ejsval lhs, ejsval rhs) { int lhs_int = ToInteger(lhs); int rhs_int = ToInteger(rhs); return NUMBER_TO_EJSVAL (lhs_int | rhs_int); }
void _ejs_process_init(ejsval global, uint32_t argc, char **argv) { _ejs_Process = _ejs_object_new (_ejs_null, &_ejs_Object_specops); _ejs_object_setprop (global, _ejs_atom_process, _ejs_Process); ejsval _argv = _ejs_array_new (argc, EJS_FALSE); _ejs_object_setprop (_ejs_Process, _ejs_atom_argv, _argv); for (int i = 0; i < argc; i ++) _ejs_object_setprop (_argv, NUMBER_TO_EJSVAL(i), _ejs_string_new_utf8(argv[i])); #define OBJ_PROP(x) EJS_INSTALL_ATOM_GETTER(_ejs_Process, x, _ejs_Process_get_##x) #define OBJ_METHOD(x) EJS_INSTALL_ATOM_FUNCTION(_ejs_Process, x, _ejs_Process_##x) OBJ_PROP(env); OBJ_METHOD(exit); OBJ_METHOD(chdir); OBJ_METHOD(cwd); #undef OBJ_PROP #undef OBJ_METHOD }
static EJSBool json_value_to_ejsval(JSON_Value *v, ejsval *rv) { switch (json_value_get_type (v)) { case JSONNull: *rv = _ejs_null; return EJS_TRUE; case JSONString: *rv = _ejs_string_new_utf8 (json_value_get_string(v)); return EJS_TRUE; case JSONNumber: *rv = NUMBER_TO_EJSVAL(json_value_get_number(v)); return EJS_TRUE; case JSONObject: { JSON_Object *obj = json_value_get_object (v); *rv = _ejs_object_create (_ejs_null); int count = json_object_get_count (obj); for (int i = 0; i < count; i ++) { const char *propkey = json_object_get_name (obj, i); ejsval propval; if (!json_value_to_ejsval (json_object_get_value (obj, propkey), &propval)) return EJS_FALSE; _ejs_object_setprop_utf8 (*rv, propkey, propval); } return EJS_TRUE; } case JSONArray: { JSON_Array *arr = json_value_get_array (v); int count = json_array_get_count (arr); *rv = _ejs_array_new (count, EJS_FALSE); for (int i = 0; i < count; i ++) { ejsval propkey = _ejs_number_new (i); ejsval propval; if (!json_value_to_ejsval (json_array_get_value (arr, i), &propval)) return EJS_FALSE; _ejs_object_setprop (*rv, propkey, propval); } return EJS_TRUE; } case JSONBoolean: *rv = BOOLEAN_TO_EJSVAL(json_value_get_boolean(v)); return EJS_TRUE; case JSONError: EJS_NOT_IMPLEMENTED(); return EJS_FALSE; } }
// ES6: 23.2.3.1 Set.prototype.add ( value ) ejsval _ejs_Set_prototype_add (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval value = _ejs_undefined; if (argc > 0) value = args[0]; // 1. Let S be the this value. ejsval S = _this; // 2. If Type(S) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(S)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.add called with non-object this."); } // 3. If S does not have a [[SetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_SET(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.set called with non-Set this."); // 4. If S’s [[SetData]] internal slot is undefined, then throw a TypeError exception. EJSSet* _set = EJSVAL_TO_SET(S); // 5. Let entries be the List that is the value of S’s [[SetData]] internal slot. EJSSetValueEntry* entries = _set->head_insert; EJSSetValueEntry* e; // 6. Repeat for each e that is an element of entries, for (e = entries; e; e = e->next_insert) { // a. If e is not empty and SameValueZero(e, value) is true, then if (SameValueZero(e->value, value)) // i. Return S. return S; } // 7. If value is −0, then let value be +0. if (EJSVAL_IS_NUMBER(value) && EJSDOUBLE_IS_NEGZERO(EJSVAL_TO_NUMBER(value))) value = NUMBER_TO_EJSVAL(0); // 8. Append value as the last element of entries. e = calloc (1, sizeof (EJSSetValueEntry)); e->value = value; if (!_set->head_insert) _set->head_insert = e; if (_set->tail_insert) { _set->tail_insert->next_insert = e; _set->tail_insert = e; } else { _set->tail_insert = e; } // 9. Return S. return S; }
static ejsval _ejs_wrapFdWithStream (int fd) { ejsval stream = _ejs_object_create(_ejs_null); EJS_INSTALL_FUNCTION (stream, "write", _ejs_stream_write); EJS_INSTALL_FUNCTION (stream, "end", _ejs_stream_end); _ejs_object_setprop_utf8 (stream, "%internal_fd", NUMBER_TO_EJSVAL(fd)); return stream; }
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(); }
// 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; }
ejsval _ejs_fs_createWriteStream (ejsval env, ejsval _this, uint32_t argc, ejsval* args) { ejsval stream = _ejs_object_create(_ejs_null); EJS_INSTALL_FUNCTION (stream, "write", _ejs_stream_write); EJS_INSTALL_FUNCTION (stream, "end", _ejs_stream_end); char *utf8_path = ucs2_to_utf8(EJSVAL_TO_FLAT_STRING(args[0])); int fd = open (utf8_path, O_CREAT | O_TRUNC | O_WRONLY, 0777); free (utf8_path); if (fd == -1) { perror ("open"); printf ("we should totally throw an exception here\n"); return _ejs_undefined; } _ejs_object_setprop_utf8 (stream, "%internal_fd", NUMBER_TO_EJSVAL(fd)); return stream; }
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; }
static ejsval _ejs_RegExp_prototype_get_lastIndex (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { EJSRegExp* re = (EJSRegExp*)EJSVAL_TO_OBJECT(_this); return NUMBER_TO_EJSVAL(re->lastIndex); }
// ECMA262 15.3.4.3 static ejsval _ejs_Function_prototype_apply (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval func = _this; /* 1. If IsCallable(func) is false, then throw a TypeError exception. */ if (!EJSVAL_IS_CALLABLE(_this)) { printf ("throw TypeError, func is not callable\n"); EJS_NOT_IMPLEMENTED(); } ejsval thisArg = _ejs_undefined; ejsval argArray = _ejs_undefined; if (argc > 0) thisArg = args[0]; if (argc > 1) argArray = args[1]; /* 2. If argArray is null or undefined, then */ if (EJSVAL_IS_UNDEFINED(argArray) || EJSVAL_IS_NULL(argArray)) { /* a. Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value */ /* and an empty list of arguments. */ return _ejs_invoke_closure (func, thisArg, 0, NULL); } /* 3. If Type(argArray) is not Object, then throw a TypeError exception. */ if (!EJSVAL_IS_OBJECT(argArray)) { printf ("throw TypeError, argArray is not an object\n"); EJS_NOT_IMPLEMENTED(); } EJSObject* argArray_ = EJSVAL_TO_OBJECT(argArray); /* 4. Let len be the result of calling the [[Get]] internal method of argArray with argument "length". */ ejsval len = OP(argArray_,Get) (argArray, _ejs_atom_length, argArray); /* 5. Let n be ToUint32(len). */ uint32_t n = (uint32_t)EJSVAL_TO_NUMBER(len); ejsval* argList; EJSBool argList_allocated = EJS_FALSE; if (EJSVAL_IS_DENSE_ARRAY(argArray)) { argList = EJSDENSEARRAY_ELEMENTS(argArray_); } else { /* 6. Let argList be an empty List. */ argList = (ejsval*)malloc(sizeof(ejsval) * n); argList_allocated = EJS_TRUE; /* 7. Let index be 0. */ int index = 0; /* 8. Repeat while index < n */ while (index < n) { /* a. Let indexName be ToString(index). */ ejsval indexName = NUMBER_TO_EJSVAL(index); /* b. Let nextArg be the result of calling the [[Get]] internal method of argArray with indexName as the */ /* argument. */ ejsval nextArg = OP(argArray_,Get)(argArray, indexName, argArray); /* c. Append nextArg as the last element of argList. */ argList[index] = nextArg; /* d. Set index to index + 1. */ ++index; } } /* 9. Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and */ /* argList as the list of arguments. */ ejsval rv = EJSVAL_TO_FUNC(func) (EJSVAL_TO_ENV(func), thisArg, n, argList); if (argList_allocated) free (argList); return rv; }
// 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 F = _ejs_function_new_anon (bound_env, bound_wrapper); EJSFunction *F_ = (EJSFunction*)EJSVAL_TO_OBJECT(F); F_->bound = EJS_TRUE; #if not_anymore /* 5. Set all the internal methods, except for [[Get]], of F as specified in 8.12. */ /* 6. Set the [[Get]] internal property of F as specified in 15.3.5.4. */ /* 7. Set the [[TargetFunction]] internal property of F to Target. */ /* 8. Set the [[BoundThis]] internal property of F to the value of thisArg. */ F_->bound_this = thisArg; /* 9. Set the [[BoundArgs]] internal property of F to A. */ F_->bound_argc = bound_argc; F_->bound_args = bound_args; /* 10. Set the [[Class]] internal property of F to "Function". */ /* 11. Set the [[Prototype]] internal property of F to the standard built-in Function prototype object as specified in 15.3.3.1. */ /* 12. Set the [[Call]] internal property of F as described in 15.3.4.5.1. */ /* 13. Set the [[Construct]] internal property of F as described in 15.3.4.5.2. */ /* 14. Set the [[HasInstance]] internal property of F as described in 15.3.4.5.3. */ /* 15. If the [[Class]] internal property of Target is "Function", then */ /* a. Let L be the length property of Target minus the length of A. */ /* b. Set the length own property of F to either 0 or L, whichever is larger. */ /* 16. Else set the length own property of F to 0. */ /* 17. Set the attributes of the length own property of F to the values specified in 15.3.5.1. */ /* 18. Set the [[Extensible]] internal property of F to true. */ /* 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). */ /* 20. Call the [[DefineOwnProperty]] internal method of F with arguments "caller", PropertyDescriptor */ /* {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false. */ /* 21. Call the [[DefineOwnProperty]] internal method of F with arguments "arguments", PropertyDescriptor */ /* {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false. */ /* 22. Return F. */ #endif return F; }
void _ejs_init(int argc, char** argv) { // process class inheritance _ejs_init_classes(); // initialize our atoms before anything else _ejs_init_static_strings(); _ejs_gc_init(); _ejs_exception_init(); // initialization or ECMA262 builtins _ejs_gc_add_root (&_ejs_global); _ejs_global = _ejs_object_new (_ejs_null, &_ejs_Object_specops); _ejs_nan = NUMBER_TO_EJSVAL(nan("7734")); _ejs_object_setprop (_ejs_global, _ejs_atom_undefined, _ejs_undefined); _ejs_object_setprop (_ejs_global, _ejs_atom_NaN, _ejs_nan); _ejs_object_setprop (_ejs_global, _ejs_atom_Infinity, _ejs_Infinity); _ejs_object_setprop (_ejs_global, _ejs_atom_eval, _ejs_function_new_native (_ejs_undefined, _ejs_atom_eval, _ejs_eval)); _ejs_object_init_proto(); _ejs_function_init(_ejs_global); _ejs_object_init(_ejs_global); _ejs_symbol_init(_ejs_global); _ejs_error_init(_ejs_global); _ejs_arguments_init(_ejs_global); _ejs_array_init(_ejs_global); _ejs_boolean_init (_ejs_global); _ejs_string_init(_ejs_global); _ejs_number_init(_ejs_global); _ejs_regexp_init(_ejs_global); _ejs_date_init(_ejs_global); _ejs_json_init(_ejs_global); _ejs_math_init(_ejs_global); // ES6 bits _ejs_proxy_init(_ejs_global); _ejs_map_init(_ejs_global); _ejs_set_init(_ejs_global); _ejs_typedarrays_init(_ejs_global); #if IOS _ejs_webgl_init(_ejs_global); #endif #define GLOBAL_METHOD(x) EJS_MACRO_START \ _ejs_##x = _ejs_function_new_native (_ejs_null, _ejs_atom_##x, (EJSClosureFunc)_ejs_##x##_impl); \ _ejs_object_setprop (_ejs_global, _ejs_atom_##x, _ejs_##x); \ EJS_MACRO_END GLOBAL_METHOD(isNaN); GLOBAL_METHOD(isFinite); GLOBAL_METHOD(parseInt); GLOBAL_METHOD(parseFloat); GLOBAL_METHOD(decodeURI); GLOBAL_METHOD(decodeURIComponent); GLOBAL_METHOD(encodeURI); GLOBAL_METHOD(encodeURIComponent); #undef GLOBAL_METHOD // the node-like api we support in order for our driver to // function. this should really be a separate opt-in .a/.so. _ejs_require_init(_ejs_global); _ejs_console_init(_ejs_global); _ejs_process_init(_ejs_global, argc, argv); _ejs_xmlhttprequest_init(_ejs_global); // a special global (__ejs) under which we can stuff other // semi-useful runtime features, like a call to force a GC. the // compiler also uses the presence of __ejs to disable // buggy/nonfunctional code (like those that use regexps) ejsval _ejs_ejs_global = _ejs_object_new (_ejs_null, &_ejs_Object_specops); _ejs_object_setprop (_ejs_global, _ejs_atom___ejs, _ejs_ejs_global); _ejs_GC_init(_ejs_ejs_global); _ejs_gc_allocate_oom_exceptions(); }
ejsval Function_prototype_get_argSize(ejsval env, ejsval _this, int argc, ejsval *args) { Function* fun = ((Function*)EJSVAL_TO_OBJECT(_this)); return NUMBER_TO_EJSVAL (fun->llvm_fun->arg_size()); }
// ECMA262 25.4.4.1 Promise.all ( iterable ) static ejsval _ejs_Promise_all (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { EJSBool success; ejsval iterable = _ejs_undefined; if (argc > 0) iterable = args[0]; // 1. Let C be the this value. ejsval C = _this; // 2. Let promiseCapability be NewPromiseCapability(C). // 3. ReturnIfAbrupt(promiseCapability). ejsval promiseCapability = NewPromiseCapability(C); // 4. Let iterator be GetIterator(iterable). ejsval iterator; success = GetIteratorP(&iterator, iterable); // 5. IfAbruptRejectPromise(iterator, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &iterator); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // 6. Let values be ArrayCreate(0). ejsval values = _ejs_array_new(0, EJS_FALSE); // 7. Let remainingElementsCount be a new Record { [[value]]: 1 }. int remainingElementsCount = 1; // 8. Let index be 0. int index = 0; // 9. Repeat while (EJS_TRUE) { // a. Let next be IteratorStep(iterator). ejsval next; success = IteratorStepP(&next, iterator); // b. IfAbruptRejectPromise(next, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &next); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // c. If next is false, if (EJSVAL_IS_BOOLEAN(next) && !EJSVAL_TO_BOOLEAN(next)) { // i. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] - 1. remainingElementsCount --; // ii. If remainingElementsCount.[[value]] is 0, if (remainingElementsCount == 0) { // 1. Let resolveResult be the result of calling the [[Call]] internal method of promiseCapability.[[Resolve]] with undefined as thisArgument and (values) as argumentsList. ejsval resolveResult; success = _ejs_invoke_closure_catch(&resolveResult, EJS_CAPABILITY_GET_RESOLVE(promiseCapability), _ejs_undefined, 1, &values); // 2. ReturnIfAbrupt(resolveResult). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &resolveResult); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } } // iii. Return promiseCapability.[[Promise]]. return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // d. Let nextValue be IteratorValue(next). ejsval nextValue; success = IteratorValueP(&nextValue, next); // e. IfAbruptRejectPromise(nextValue, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &nextValue); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // f. Let nextPromise be Invoke(C, "resolve", (nextValue)). ejsval nextPromise; success = _ejs_invoke_closure_catch (&nextPromise, Get(C, _ejs_atom_resolve), C, 1, &nextValue); // g. IfAbruptRejectPromise(nextPromise, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &nextPromise); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // h. Let resolveElement be a new built-in function object as defined in Promise.all Resolve Element Functions. ejsval resolvingElement_env = _ejs_closureenv_new(6); ejsval resolveElement = _ejs_function_new_anon(resolvingElement_env, resolve_element); // i. Set the [[AlreadyCalled]] internal slot of resolveElement to false. EJS_RESOLVEELEMENT_SET_ALREADY_CALLED(resolvingElement_env, _ejs_false); // j. Set the [[Index]] internal slot of resolveElement to index. EJS_RESOLVEELEMENT_SET_INDEX(resolvingElement_env, NUMBER_TO_EJSVAL(index)); // k. Set the [[Values]] internal slot of resolveElement to values. EJS_RESOLVEELEMENT_SET_VALUES(resolvingElement_env, values); // l. Set the [[Capabilities]] internal slot of resolveElement to promiseCapability. EJS_RESOLVEELEMENT_SET_CAPABILITIES(resolvingElement_env, promiseCapability); // m. Set the [[RemainingElements]] internal slot of resolveElement to remainingElementsCount. EJS_RESOLVEELEMENT_SET_REMAINING_ELEMENTS(resolvingElement_env, NUMBER_TO_EJSVAL(remainingElementsCount)); // n. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] + 1. remainingElementsCount++; // o. Let result be Invoke(nextPromise, "then", (resolveElement, promiseCapability.[[Reject]])). ejsval thenargs[] = { resolveElement, EJS_CAPABILITY_GET_REJECT(promiseCapability) }; ejsval result; success = _ejs_invoke_closure_catch (&result, Get(nextPromise, _ejs_atom_then), nextPromise, 2, thenargs); // p. IfAbruptRejectPromise(result, promiseCapability). if (!success) { _ejs_invoke_closure(EJS_CAPABILITY_GET_REJECT(promiseCapability), _ejs_undefined, 1, &result); return EJS_CAPABILITY_GET_PROMISE(promiseCapability); } // q. Set index to index + 1. index ++; } }
ejsval _ejs_op_neg (ejsval exp) { return NUMBER_TO_EJSVAL (-ToDouble(exp)); }
static ejsval _ejs_SetIterator_prototype_next (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { /* 1. Let O be the this value. */ ejsval O = _this; /* 2. If Type(O) is not Object, throw a TypeError exception. */ if (!EJSVAL_IS_OBJECT(O)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, ".next called on non-object"); /* 3. If O does not have all of the internal slots of a Set Iterator Instance (23.2.5.3), * throw a TypeError exception. */ if (!EJSVAL_IS_SETITERATOR(O)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, ".next called on non-SetIterator instance"); EJSSetIterator *OObj = (EJSSetIterator*)EJSVAL_TO_OBJECT(O); /* 4. Let s be the value of the [[IteratedSet]] internal slot of O. */ ejsval s = OObj->iterated; /* 5. Let index be the value of the [[SetNextIndex]] internal slot of O. */ uint32_t index = OObj->next_index; /* 6. Let itemKind be the value of the [[SetIterationKind]] internal slot of O. */ EJSSetIteratorKind itemKind = OObj->kind; /* 7. If s is undefined, then return CreateIterResultObject(undefined, true). */ if (EJSVAL_IS_UNDEFINED(s)) return _ejs_create_iter_result (_ejs_undefined, _ejs_true); /* 8. Assert: s has a [[SetData]] internal slot and s has been initialized so the value of * [[SetData]] is not undefined. */ /* 9. Let entries be the List that is the value of the [[SetData]] internal slot of s. */ EJSSetValueEntry *entries = EJSVAL_TO_SET(s)->head_insert; /* 10. Repeat while index is less than the total number of elements of entries. The number of elements must * be redetermined each time this method is evaluated. */ uint32_t i = 0; for (EJSSetValueEntry *entry = entries; entry; entry = entry->next_insert) { /* Ignore this item if is marked as empty */ if (EJSVAL_IS_NO_ITER_VALUE_MAGIC(entry->value)) continue; /* Ignore this item if we haven't reached the initial needed point/index */ if (index > i++) continue; /* a. Let e be entries[index]. */ ejsval e = entry->value; /* b. Set index to index+1; */ index = index + 1; /* c. Set the [[SetNextIndex]] internal slot of O to index. */ OObj->next_index = index; /* d. If e is not empty, then */ /* (see EJSVAL_IS_NO_ITER_VALUE_MAGIC check at the beginning of the loop */ /* i. If itemKind is "key+value" then, */ if (itemKind == EJS_SET_ITER_KIND_KEYVALUE) { /* 1. Let result be the result of performing ArrayCreate(2). */ /* 2. Assert: result is a new, well-formed Array object so the following operations will never fail. */ ejsval result = _ejs_array_new (2, EJS_FALSE); /* 3. Call CreateDataProperty(result, "0", e) . */ _ejs_object_setprop (result, NUMBER_TO_EJSVAL(0), e); /* 4. Call CreateDataProperty(result, "1", e) . */ _ejs_object_setprop (result, NUMBER_TO_EJSVAL(1), e); return _ejs_create_iter_result (result, _ejs_false); } /* ii. Return CreateIterResultObject(e, false). */ return _ejs_create_iter_result (e, _ejs_false); } /* 11. Set the [[IteratedSet]] internal slot of O to undefined. */ OObj->iterated = _ejs_undefined; /* 12. Return CreateIterResultObject(undefined, true). */ return _ejs_create_iter_result (_ejs_undefined, _ejs_true); }
ejsval _ejs_op_plus (ejsval exp) { return NUMBER_TO_EJSVAL (ToDouble(exp)); }
ejsval _ejs_op_bitwise_not (ejsval val) { int val_int = ToInteger(val); return NUMBER_TO_EJSVAL (~val_int); }