// ECMA262: 15.3.5.3 static EJSBool _ejs_function_specop_has_instance (ejsval F, ejsval V) { /* 1. If V is not an object, return false. */ if (!EJSVAL_IS_OBJECT(V)) return EJS_FALSE; /* 2. Let O be the result of calling the [[Get]] internal method of F with property name "prototype". */ ejsval O = OP(EJSVAL_TO_OBJECT(F),Get)(F, _ejs_atom_prototype, F); /* 3. If Type(O) is not Object, throw a TypeError exception. */ if (!EJSVAL_IS_OBJECT(O)) { printf ("throw TypeError, O is not an object\n"); EJS_NOT_IMPLEMENTED(); } /* 4. Repeat */ while (1) { /* a. Let V be the value of the [[Prototype]] internal property of V. */ V = EJSVAL_TO_OBJECT(V)->proto; /* b. If V is null, return false. */ if (EJSVAL_IS_NULL(V)) return EJS_FALSE; /* c. If O and V refer to the same object, return true. */ if (EJSVAL_EQ(O, V)) return EJS_TRUE; } }
// ES6: 23.1.3.1 // Map.prototype.clear () ejsval _ejs_Set_prototype_clear (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { // 1. Let S be 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.clear 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.clear called with non-Set this."); // 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 = EJSVAL_TO_SET(S)->head_insert; // 6. Repeat for each e that is an element of entries, for (EJSSetValueEntry* e = entries; e; e = e->next_insert) { // a. Replace the element of entries whose value is e with an element whose value is empty. e->value = MAGIC_TO_EJSVAL_IMPL(EJS_NO_ITER_VALUE); } // 7. Return undefined. return _ejs_undefined; }
// 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); }
// ES6: 23.2.3.7 // Set.prototype.has ( value ) ejsval _ejs_Set_prototype_has (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.has 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.has 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; // 6. Repeat for each e that is an element of entries, for (EJSSetValueEntry* e = entries; e; e = e->next_insert) { // a. If e is not empty and SameValueZero(e, value) is true, then return true. if (SameValueZero (e->value, value)) return _ejs_true; } // 7. Return false. return _ejs_false; }
// ECMA262 25.4.1.6.1 CreatePromiseCapabilityRecord( promise, constructor ) static ejsval CreatePromiseCapabilityRecord (ejsval promise, ejsval constructor) { // 1. Assert: promise is an uninitialized object created as if by invoking @@create on constructor. // 2. Assert: IsConstructor(constructor) is true. // 3. Let promiseCapability be a new PromiseCapability { [[Promise]]: promise, [[Resolve]]: undefined, [[Reject]]: undefined }. ejsval promiseCapability = EJS_CAPABILITY_NEW(); EJS_CAPABILITY_SET_PROMISE(promiseCapability, promise); EJS_CAPABILITY_SET_RESOLVE(promiseCapability, _ejs_undefined); EJS_CAPABILITY_SET_REJECT(promiseCapability, _ejs_undefined); // 4. Let executor be a new built-in function object as defined in GetCapabilitiesExecutor Functions (25.4.1.5.1). ejsval executor = _ejs_function_new_anon (promiseCapability, capabilitiesExecutor); // 5. Set the [[Capability]] internal slot of executor to promiseCapability. // 6. Let constructorResult be the result of calling the [[Call]] internal method of constructor, passing promise and (executor) as the arguments. // 7. ReturnIfAbrupt(constructorResult). ejsval constructorResult = _ejs_invoke_closure (constructor, promise, 1, &executor); // 8. If IsCallable(promiseCapability.[[Resolve]]) is false, then throw a TypeError exception. if (!EJSVAL_IS_CALLABLE(EJS_CAPABILITY_GET_RESOLVE(promiseCapability))) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, ""); // XXX // 9. If IsCallable(promiseCapability.[[Reject]]) is false, then throw a TypeError exception. if (!EJSVAL_IS_CALLABLE(EJS_CAPABILITY_GET_REJECT(promiseCapability))) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, ""); // XXX // 10. If Type(constructorResult) is Object and SameValue(promise, constructorResult) is false, then throw a TypeError exception. if (EJSVAL_IS_OBJECT(constructorResult) && !SameValue(promise, constructorResult)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "1"); // XXX // 11. Return promiseCapability. return promiseCapability; }
// 25.4.3.1 Promise ( executor ) static ejsval _ejs_Promise_impl (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval executor = _ejs_undefined; if (argc > 0) executor = args[0]; // 1. Let promise be the this value. ejsval promise = _this; // 2. If Type(promise) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(promise)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "`this' is not an object"); // 3. If promise does not have a [[PromiseState]] internal slot, then throw a TypeError exception. if (!EJSVAL_IS_PROMISE(promise)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "`this' is not an promise"); EJSPromise* _promise = EJSVAL_TO_PROMISE(promise); // 4. If promise's [[PromiseState]] internal slot is not undefined, then throw a TypeError exception. if (_promise->state != PROMISE_STATE_UNINITIALIZED) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Promise constructor called on previously created object"); // 5. If IsCallable(executor) is false, then throw a TypeError exception. if (!EJSVAL_IS_CALLABLE(executor)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "executor is not callable"); // 6. Return InitializePromise(promise, executor). // 1. Assert: promise has a [[PromiseState]] internal slot and it’s value is undefined. // 2. Assert: IsCallable(executor) is true. // 3. Set promise's [[PromiseState]] internal slot to "pending". _promise->state = PROMISE_STATE_PENDING; // 4. Set promise's [[PromiseFulfillReactions]] internal slot to a new empty List. _promise->fulfillReactions = NULL; // 5. Set promise's [[PromiseRejectReactions]] internal slot to a new empty List. _promise->rejectReactions = NULL; // 6. Let resolvingFunctions be CreateResolvingFunctions(promise). ejsval resolvingFunctions_resolve; ejsval resolvingFunctions_reject; CreateResolvingFunctions(promise, &resolvingFunctions_resolve, &resolvingFunctions_reject); // 7. Let completion be the result of calling the [[Call]] internal method of executor with undefined as thisArgument and (resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]) a argumentsList. ejsval completion; ejsval executor_args[] = { resolvingFunctions_resolve, resolvingFunctions_reject }; EJSBool success = _ejs_invoke_closure_catch(&completion, executor, _ejs_undefined, 2, executor_args); // 8. If completion is an abrupt completion, then if (!success) { // a. Let status be the result of calling the [[Call]] internal method of resolvingFunctions.[[Reject]] with undefined as thisArgument and (completion.[[value]]) as argumentsList. // b. ReturnIfAbrupt(status). _ejs_invoke_closure(resolvingFunctions_reject, _ejs_undefined, 1, &completion); } // 9. Return promise. return promise; }
// 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(); }
ejsval _ejs_set_iterator_new (ejsval set, EJSSetIteratorKind kind) { /* 1. If Type(set) is not Object, throw a TypeError exception. */ if (!EJSVAL_IS_OBJECT(set)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "set is not a Object"); /* 2. If set does not have a [[SetData]] internal slot throw a TypeError exception. */ if (!EJSVAL_IS_SET(set)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "value is not a Set"); /* 3. If set’s [[SetData]] internal slot is undefined, then throw a TypeError exception. */ /* 4. Let iterator be the result of ObjectCreate(%SetIteratorPrototype%, * ([[IteratedSet]], [[SetNextIndex]], [[SetIterationKind]])). */ EJSSetIterator *iter = _ejs_gc_new (EJSSetIterator); _ejs_init_object ((EJSObject*) iter, _ejs_SetIterator_prototype, &_ejs_SetIterator_specops); /* 5. Set iterator’s [[IteratedSet]] internal slot to set. */ iter->iterated = set; /* 6. Set iterator’s [[SetNextIndex]] internal slot to 0. */ iter->next_index = 0; /* 7. Set iterator’s [[SetIterationKind]] internal slot to kind. */ iter->kind = kind; /* 8. Return iterator */ return OBJECT_TO_EJSVAL(iter); }
ejsval ToPrimitive(ejsval exp) { if (EJSVAL_IS_OBJECT(exp)) { return OP(EJSVAL_TO_OBJECT(exp),default_value) (exp, "PreferredType"); } else return exp; }
static EJS_NATIVE_FUNC(_ejs_Generator_prototype_next) { ejsval O = *_this; if (!EJSVAL_IS_OBJECT(O)) _ejs_throw_nativeerror_utf8(EJS_TYPE_ERROR, ".next called on non-object"); if (!EJSVAL_IS_GENERATOR(O)) _ejs_throw_nativeerror_utf8(EJS_TYPE_ERROR, ".next called on non-generator"); return _ejs_generator_send(O, argc > 0 ? args[0] : _ejs_undefined); }
// ES6: 23.4.3.3 // WeakSet.prototype.delete ( value ) static EJS_NATIVE_FUNC(_ejs_WeakSet_prototype_delete) { 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, "delete called with non-object this."); // 3. If S does not have a [[WeakSetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_WEAKSET(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "delete called with non-WeakSet this."); // 4. If S’s [[WeakSetData]] internal slot is undefined, then throw a TypeError exception. // 5. If Type(value) is not Object, then return false. if (!EJSVAL_IS_OBJECT(value)) return _ejs_false; // 6. Let entries be the List that is the value of M’s [[WeakSetData]] internal slot. #if WEAK_COLLECTIONS_USE_INVERTED_REP ejsval iset = _ejs_object_getprop(value, _ejs_WeakSetData_symbol); if (EJSVAL_IS_NULL_OR_UNDEFINED(iset)) return _ejs_false; if (!EJSVAL_IS_SET(iset)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "[[WeakSetData]] internal error"); return _ejs_set_delete (iset, S); #else // 7. Repeat for each e that is an element of entries, // a. If e is not empty and SameValue(e, value) is true, then // i. Replace the element of entries whose value is e with an element whose value is empty. // ii. Return true. // 8. Return false. return _ejs_false; #endif }
// ES6: 23.4.3.1 // WeakSet.prototype.add ( value ) static EJS_NATIVE_FUNC(_ejs_WeakSet_prototype_add) { 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, "add called with non-object this."); // 3. If S does not have a [[WeakSetData]] internal slot throw a TypeError exception. if (!EJSVAL_IS_WEAKSET(S)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "add called with non-WeakSet this."); // 4. If S’s [[WeakSetData]] internal slot is undefined, then throw a TypeError exception. // 6. If Type(value) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(value)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "add called with non-Object value."); #if WEAK_COLLECTIONS_USE_INVERTED_REP ejsval iset = _ejs_object_getprop(value, _ejs_WeakSetData_symbol); if (EJSVAL_IS_NULL_OR_UNDEFINED(iset)) { iset = _ejs_set_new(); _ejs_object_setprop(value, _ejs_WeakSetData_symbol, iset); } if (!EJSVAL_IS_SET(iset)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "[[WeakSetData]] internal error"); _ejs_set_add (iset, S); return S; #else // 7. Let entries be the List that is the value of S’s [[WeakSetData]] internal slot. // a. If e is not empty and SameValue(e, value) is true, then // 1. Return S. // 8. Append value as the last element of entries. // 9. Return S. #endif }
// ES6: 23.2.3.6 Set.prototype.forEach ( callbackfn , thisArg = undefined ) ejsval _ejs_Set_prototype_forEach (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval callbackfn = _ejs_undefined; ejsval thisArg = _ejs_undefined; if (argc > 0) callbackfn = args[0]; if (argc > 1) thisArg = args[1]; // 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.forEach 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.forEach called with non-Set this."); // 4. If S’s [[SetData]] internal slot is undefined, then throw a TypeError exception. // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. if (!EJSVAL_IS_CALLABLE(callbackfn)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.forEach callbackfn isn't a function."); // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. ejsval T = thisArg; EJSSet* set = EJSVAL_TO_SET(S); // 7. Let entries be the List that is the value of S’s [[SetData]] internal slot. EJSSetValueEntry* entries = set->head_insert; // 8. Repeat for each e that is an element of entries, in original insertion order 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)) continue; // i. Let funcResult be the result of calling the [[Call]] internal method of callbackfn with T as thisArgument and a List containing e, e, and S as argumentsList. // ii. ReturnIfAbrupt(funcResult). ejsval callback_args[3]; callback_args[0] = e->value; callback_args[1] = e->value; callback_args[2] = S; _ejs_invoke_closure (callbackfn, T, 3, callback_args); } // 9. Return undefined. return _ejs_undefined; }
static ejsval _ejs_Generator_prototype_throw (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval O = _this; if (!EJSVAL_IS_OBJECT(O)) _ejs_throw_nativeerror_utf8(EJS_TYPE_ERROR, ".throw called on non-object"); if (!EJSVAL_IS_GENERATOR(O)) _ejs_throw_nativeerror_utf8(EJS_TYPE_ERROR, ".throw called on non-generator"); return _ejs_generator_throw(O, argc > 0 ? args[0] : _ejs_undefined); }
// 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; }
// ECMA262 25.4.1.4 Promise Resolve Functions static ejsval resolve(ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval resolution = _ejs_undefined; if (argc > 0) resolution = args[0]; // 1. Assert: F has a [[Promise]] internal slot whose value is an Object. // 2. Let promise be the value of F's [[Promise]] internal slot. ejsval promise = _ejs_closureenv_get_slot(env, 1); // 3. Let alreadyResolved by be the value of F's [[AlreadyResolved]] internal slot. ejsval alreadyResolved = _ejs_closureenv_get_slot(env, 0); // 4. If alreadyResolved. [[value]] is true, then return undefined. if (EJSVAL_TO_BOOLEAN(alreadyResolved)) { return _ejs_undefined; } // 5. Set alreadyResolved.[[value]] to true. *_ejs_closureenv_get_slot_ref(env, 0) = _ejs_true; // 6. If SameValue(resolution, promise) is true, then if (SameValue(resolution, promise)) { // a. Let selfResolutionError be a newly-created TypeError object. ejsval selfResolutionError = _ejs_nativeerror_new_utf8(EJS_TYPE_ERROR, ""); // XXX // b. Return RejectPromise(promise, selfResolutionError). return RejectPromise(promise, selfResolutionError); } // 7. If Type(resolution) is not Object, then if (!EJSVAL_IS_OBJECT(resolution)) { // a. Return FulfillPromise(promise, resolution). return FulfillPromise(promise, resolution); } // 8. Let then be Get(resolution, "then"). ejsval then = Get(resolution, _ejs_atom_then); // 9. If then is an abrupt completion, then // a. Return RejectPromise(promise, then.[[value]]). // XXX // 10. Let then be then.[[value]]. // 11. If IsCallable(then) is false, then if (!EJSVAL_IS_CALLABLE(then)) { // a. Return FulfillPromise(promise, resolution). return FulfillPromise(promise, resolution); } // 12. Perform EnqueueTask ("PromiseTasks", PromiseResolveThenableTask, (promise, resolution, then)) EnqueuePromiseResolveThenableTask (promise, resolution, then); // 13. Return undefined. return _ejs_undefined; }
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(); }
// ECMA262 25.4.1.6 NewPromiseCapability ( C ) static ejsval NewPromiseCapability(ejsval C) { // 1. If IsConstructor(C) is false, throw a TypeError exception. // 2. Assert: C is a constructor function that supports the parameter conventions of the Promise constructor (see 25.4.3.1). // 3. Let promise be CreateFromConstructor(C). ejsval creator = Get(C, _ejs_Symbol_create); // 4. ReturnIfAbrupt(promise). ejsval promise = _ejs_invoke_closure (creator, _ejs_undefined, 0, NULL); // 5. If Type(promise) is not Object, then throw a TypeError exception. if (!EJSVAL_IS_OBJECT(promise)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "promise constructor returned non-object"); // 6. Return CreatePromiseCapabilityRecord(promise, C). return CreatePromiseCapabilityRecord(promise, C); }
static EJS_NATIVE_FUNC(_ejs_Error_prototype_toString) { ejsval O = *_this; if (!EJSVAL_IS_OBJECT(O)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Error.prototype.toString called on non-object"); } EJSObject *_thisobj = EJSVAL_TO_OBJECT(O); ejsval name = OP(_thisobj,Get)(O, _ejs_atom_name, O); if (EJSVAL_IS_NULL_OR_UNDEFINED(name)) name = _ejs_atom_Error; ejsval message = OP(_thisobj,Get)(O, _ejs_atom_message, O); if (EJSVAL_IS_NULL_OR_UNDEFINED(message)) return name; ejsval sep = _ejs_string_new_utf8(": "); return _ejs_string_concatv (name, sep, message, _ejs_null); }
// ES6 Draft rev32 Feb 2, 2015 // 9.2.3 // [[Construct]] ( argumentsList, newTarget) ejsval _ejs_construct_closure (ejsval _closure, ejsval newTarget, uint32_t argc, ejsval* args) { // 1. Assert: F is an ECMAScript function object. EJSFunction* F = (EJSFunction*)EJSVAL_TO_OBJECT(_closure); // 2. Assert: Type(newTarget) is Object. // 3. Let callerContext be the running execution context. // 4. Let kind be F’s [[ConstructorKind]] internal slot. EJSConstructorKind kind = F->constructor_kind; ejsval thisArgument = _ejs_undefined; // 5. If kind is "base", then if (kind == CONSTRUCTOR_KIND_BASE) { // a. Let thisArgument be OrdinaryCreateFromConstructor(newTarget, "%ObjectPrototype%"). // b. ReturnIfAbrupt(thisArgument). } // 6. Let calleeContext be PrepareForOrdinaryCall(F, newTarget). // 7. ReturnIfAbrupt(calleeContext). // 8. Assert: calleeContext is now the active execution context. // 9. If kind is "base", then if (kind == CONSTRUCTOR_KIND_BASE) { // a. Let status be OrdinaryCallBindThis(F, calleeContext, thisArgument). // b. If status is an abrupt completion, then // i. Remove calleeContext from the execution context stack and restore callerContext as the running execution context. // ii. Return status. } // 10. Let constructorEnv be the LexicalEnvironment of calleeContext. // 11. Let envRec be constructorEnv’s environment record. // 12. Let result be OrdinaryCallEvaluateBody(F, calleeContext, argumentsList). ejsval result = _ejs_invoke_closure(_closure, thisArgument, argc, args); // 13. Remove calleeContext from the execution context stack and restore callerContext as the running execution context. // 14. If result.[[type]] is return, then // a. If Type(result.[[value]]) is Object, return NormalCompletion(result.[[value]]). if (EJSVAL_IS_OBJECT(result)) return result; // b. If kind is "base", return NormalCompletion(thisArgument). if (kind == CONSTRUCTOR_KIND_BASE) return thisArgument; // c. Throw a TypeError exception. _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "9.2.3/14.c"); // 15. ReturnIfAbrupt(result). // 16. Return the result of calling the GetThisBinding concrete method of envRec’s with no arguments EJS_NOT_IMPLEMENTED(); }
// ES2015, June 2015 // 19.4.3.3 Symbol.prototype.valueOf ( ) static EJS_NATIVE_FUNC(_ejs_Symbol_prototype_valueOf) { // 1. Let s be the this value. ejsval s = *_this; // 2. If Type(s) is Symbol, return s. if (EJSVAL_IS_SYMBOL(s)) return s; // 3. If Type(s) is not Object, throw a TypeError exception. if (!EJSVAL_IS_OBJECT(s)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Symbol.prototype.valueOf called with non-object this"); // 4. If s does not have a [[SymbolData]] internal slot, throw a TypeError exception. if (!EJSVAL_IS_SYMBOL_OBJECT(s)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Symbol.prototype.valueOf called with non-symbol this"); // 5. Return the value of s’s [[SymbolData]] internal slot. return EJSVAL_TO_SYMBOL_OBJECT(s)->primSymbol; }
static ejsval _ejs_Error_prototype_toString (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { if (!EJSVAL_IS_OBJECT(_this)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Error.prototype.toString called on non-object"); } EJSObject *_thisobj = EJSVAL_TO_OBJECT(_this); ejsval name = OP(_thisobj,Get)(_this, _ejs_atom_name, _this); if (EJSVAL_IS_NULL_OR_UNDEFINED(name)) name = _ejs_atom_Error; ejsval message = OP(_thisobj,Get)(_this, _ejs_atom_message, _this); if (EJSVAL_IS_NULL_OR_UNDEFINED(message)) return name; ejsval sep = _ejs_string_new_utf8(": "); return _ejs_string_concatv (name, sep, message, _ejs_null); }
// ECMA262: 26.1.14 Reflect.setPrototypeOf ( target, proto ) static ejsval _ejs_Reflect_setPrototypeOf (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval target = _ejs_undefined; ejsval proto = _ejs_undefined; if (argc > 0) target = args[0]; if (argc > 1) proto = args[1]; // 1. Let obj be ToObject(target). // 2. ReturnIfAbrupt(obj). ejsval obj = ToObject(target); // 3. If Type(proto) is not Object and proto is not null, then throw a TypeError exception if (!EJSVAL_IS_OBJECT(proto) && !EJSVAL_IS_NULL(proto)) _ejs_throw_nativeerror_utf8(EJS_TYPE_ERROR, "prototype argument must be an object or null"); // 4. Return the result of calling the [[SetPrototypeOf]] internal method of obj with argument proto. return BOOLEAN_TO_EJSVAL(OP(EJSVAL_TO_OBJECT(obj), SetPrototypeOf)(target, proto)); }
// 23.2.3.4 Set.prototype.delete ( value ) ejsval _ejs_Set_prototype_delete (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { // NOTE The value empty is used as a specification device to // indicate that an entry has been deleted. Actual implementations // may take other actions such as physically removing the entry // from internal data structures. 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.delete 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.delete called with non-Set this."); // 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 = EJSVAL_TO_SET(S)->head_insert; // 6. Repeat for each e that is an element of entries, for (EJSSetValueEntry* 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. Replace the element of entries whose value is e with an element whose value is empty. e->value = MAGIC_TO_EJSVAL_IMPL(EJS_NO_ITER_VALUE); // ii. Return true. return _ejs_true; } } // 7. Return false. return _ejs_false; }
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(); }
static ejsval _ejs_Function_prototype_create(ejsval env, ejsval _this, uint32_t argc, ejsval* args) { ejsval F = _this; if (!EJSVAL_IS_CONSTRUCTOR(F)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "'this' in Function.prototype[Symbol.create] is not a constructor"); EJSObject* F_ = EJSVAL_TO_OBJECT(F); ejsval proto = OP(F_,Get)(F, _ejs_atom_prototype, F); if (EJSVAL_IS_UNDEFINED(proto)) { proto = _ejs_Function_prototype; } if (!EJSVAL_IS_OBJECT(proto)) { EJS_NOT_IMPLEMENTED(); // cross-realm doesn't exist in ejs yet } EJSObject* obj = (EJSObject*)_ejs_gc_new (EJSObject); _ejs_init_object (obj, proto, &_ejs_Object_specops); return OBJECT_TO_EJSVAL(obj); }
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(); }
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(); }
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); }
// 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; }