// ECMA262 25.4.4.6 Promise [ @@create ] ( ) static ejsval _ejs_Promise_create (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { // 1. Let F be the this value ejsval F = _this; // 2. Return AllocatePromise(F). // 1. Let obj be OrdinaryCreateFromConstructor(constructor, "%PromisePrototype%", ([[PromiseState]], [[PromiseConstructor]], [[PromiseResult]], [[PromiseFulfillReactions]], [[PromiseRejectReactions]]) ). ejsval proto = _ejs_undefined; if (!EJSVAL_IS_UNDEFINED(F)) { if (!EJSVAL_IS_CONSTRUCTOR(F)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "'this' in Promise[Symbol.create] is not a constructor"); EJSObject* F_ = EJSVAL_TO_OBJECT(F); proto = OP(F_,Get)(F, _ejs_atom_prototype, F); } if (EJSVAL_IS_UNDEFINED(proto)) proto = _ejs_Promise_prototype; EJSObject* obj = (EJSObject*)_ejs_gc_new (EJSPromise); _ejs_init_object (obj, proto, &_ejs_Promise_specops); // 2. Set the value of obj’s [[PromiseConstructor]] internal slot to constructor. ((EJSPromise*)obj)->constructor = F; // 3. Return obj. return OBJECT_TO_EJSVAL(obj); }
// ECMA262 25.4.1.6.2 GetCapabilitiesExecutor Functions static ejsval capabilitiesExecutor(ejsval env, ejsval _this, uint32_t argc, ejsval *args) { ejsval resolve = _ejs_undefined; if (argc > 0) resolve = args[0]; ejsval reject = _ejs_undefined; if (argc > 1) reject = args[1]; // 1. Assert: F has a [[Capability]] internal slot whose value is a PromiseCapability Record. // 2. Let promiseCapability be the value of F's [[Capability]] internal slot. ejsval promiseCapability = env; // 3. If promiseCapability.[[Resolve]] is not undefined, then throw a TypeError exception. if (!EJSVAL_IS_UNDEFINED(EJS_CAPABILITY_GET_RESOLVE(promiseCapability))) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, ""); // XXX // 4. If promiseCapability.[[Reject]] is not undefined, then throw a TypeError exception. if (!EJSVAL_IS_UNDEFINED(EJS_CAPABILITY_GET_REJECT(promiseCapability))) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, ""); // XXX // 5. Set promiseCapability.[[Resolve]] to resolve. EJS_CAPABILITY_SET_RESOLVE(promiseCapability, resolve); // 6. Set promiseCapability.[[Reject]] to reject. EJS_CAPABILITY_SET_REJECT(promiseCapability, reject); // 7. Return undefined. return _ejs_undefined; }
// 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_symbol_new (ejsval description) { EJSPrimSymbol* rv = _ejs_gc_new_primsym (sizeof(EJSPrimSymbol)); rv->description = EJSVAL_IS_UNDEFINED(description) ? description : ToString(description); return SYMBOL_TO_EJSVAL(rv); }
// ECMA262: 19.4.1 static EJS_NATIVE_FUNC(_ejs_Symbol_impl) { if (!EJSVAL_IS_UNDEFINED(newTarget)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Symbol cannot be called as a constructor"); } ejsval description = _ejs_undefined; if (argc > 0) description = args[0]; return _ejs_symbol_new(description); }
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; }
// 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); }
static ejsval Module_impl (ejsval env, ejsval _this, int argc, ejsval *args) { if (EJSVAL_IS_UNDEFINED(_this)) { // called as a function EJS_NOT_IMPLEMENTED(); } else { Module* module = ((Module*)EJSVAL_TO_OBJECT(_this)); REQ_UTF8_ARG(0, name); module->llvm_module = new llvm::Module(name, llvm::getGlobalContext()); return _this; } }
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(); }
static ejsval DIBuilder_impl (ejsval env, ejsval _this, int argc, ejsval *args) { if (EJSVAL_IS_UNDEFINED(_this)) { // called as a function EJS_NOT_IMPLEMENTED(); } else { DIBuilder* dib = ((DIBuilder*)EJSVAL_TO_OBJECT(_this)); REQ_LLVM_MODULE_ARG(0, module); dib->llvm_dibuilder = new llvm::DIBuilder (*module); return _this; } }
static ejsval Module_create (ejsval env, ejsval _this, int argc, ejsval *args) { ejsval F = _this; if (!EJSVAL_IS_CONSTRUCTOR(F)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "'this' in Module[Symbol.create] is not a constructor"); EJSObject* F_ = EJSVAL_TO_OBJECT(F); // 2. Let obj be the result of calling OrdinaryCreateFromConstructor(F, "%DatePrototype%", ([[DateData]]) ). ejsval proto = OP(F_,Get)(F, _ejs_atom_prototype, F); if (EJSVAL_IS_UNDEFINED(proto)) proto = _ejs_Module_prototype; EJSObject* obj = (EJSObject*)_ejs_gc_new (Module); _ejs_init_object (obj, proto, &_ejs_Module_specops); return OBJECT_TO_EJSVAL(obj); }
static ejsval BasicBlock_impl (ejsval env, ejsval _this, int argc, ejsval *args) { if (EJSVAL_IS_UNDEFINED(_this)) { // called as a function EJS_NOT_IMPLEMENTED(); } else { BasicBlock* bb = ((BasicBlock*)EJSVAL_TO_OBJECT(_this)); REQ_UTF8_ARG(0, name); REQ_LLVM_FUN_ARG(1, fun); bb->llvm_bb = llvm::BasicBlock::Create(llvm::getGlobalContext(), name, fun); free (name); return _this; } }
static ejsval _ejs_ArrayBuffer_impl (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { if (EJSVAL_IS_UNDEFINED(_this)) { printf ("ArrayBuffer called as a function\n"); EJS_NOT_IMPLEMENTED(); } uint32_t size = 0; if (argc > 0) size = ToUint32(args[0]); EJSArrayBuffer* buffer = (EJSArrayBuffer*)EJSVAL_TO_OBJECT(_this); buffer->dependent = EJS_FALSE; buffer->size = size; if (size) buffer->data.alloced_buf = calloc (1, size); return _this; }
static ejsval _ejs_DataView_impl (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { if (EJSVAL_IS_UNDEFINED(_this)) { _ejs_log ("DataView called as a function\n"); EJS_NOT_IMPLEMENTED(); } if (argc == 0 || !EJSVAL_IS_ARRAYBUFFER(args[0])) { _ejs_log ("arg0 not an ArrayBuffer object\n"); EJS_NOT_IMPLEMENTED(); } EJSDataView* view = (EJSDataView*)EJSVAL_TO_OBJECT(_this); EJSArrayBuffer* buff = (EJSArrayBuffer*)EJSVAL_TO_OBJECT(args[0]); uint32_t offset; uint32_t len; switch (argc) { case 1: offset = 0; len = buff->size; break; case 2: offset = EJSVAL_TO_NUMBER(args[1]); len = buff->size - offset; break; default: offset = EJSVAL_TO_NUMBER(args[1]); len = EJSVAL_TO_NUMBER(args[2]); } view->buffer = args[0]; view->byteOffset = offset; view->byteLength = len; _ejs_object_define_value_property (_this, _ejs_atom_byteLength, DOUBLE_TO_EJSVAL_IMPL(view->byteLength), EJS_PROP_FLAGS_ENUMERABLE); _ejs_object_define_value_property (_this, _ejs_atom_byteOffset, DOUBLE_TO_EJSVAL_IMPL(view->byteOffset), EJS_PROP_FLAGS_ENUMERABLE); _ejs_object_define_value_property (_this, _ejs_atom_buffer, view->buffer, EJS_PROP_FLAGS_ENUMERABLE); return _this; }
static ejsval GlobalVariable_impl (ejsval env, ejsval _this, int argc, ejsval *args) { if (EJSVAL_IS_UNDEFINED(_this)) { // called as a function EJS_NOT_IMPLEMENTED(); } else { GlobalVariable* gv = (GlobalVariable*)EJSVAL_TO_OBJECT(_this); REQ_LLVM_MODULE_ARG(0, module); REQ_LLVM_TYPE_ARG(1, type); REQ_UTF8_ARG(2, name); REQ_LLVM_CONST_ARG(3, init); gv->llvm_global = new ::llvm::GlobalVariable(*module, type, false, llvm::GlobalValue::InternalLinkage, init, name); free(name); return _this; } }
ejsval _ejs_unhandledException(ejsval env, ejsval _this, uint32_t argc, ejsval* args) { ejsval exc = _ejs_undefined; if (argc > 0) exc = args[0]; printf ("unhandled exception: "); if (EJSVAL_IS_UNDEFINED(exc)) { EJS_NOT_IMPLEMENTED(); } else { ejsval str = ToString(exc); printf ("%s\n", _ejs_string_to_utf8(_ejs_string_flatten(str))); } exit(-1); return _ejs_undefined; }
static EJS_NATIVE_FUNC(GlobalVariable_impl) { if (EJSVAL_IS_UNDEFINED(newTarget)) { // called as a function EJS_NOT_IMPLEMENTED(); } else { ejsval O = OrdinaryCreateFromConstructor(newTarget, _ejs_GlobalVariable_prototype, &_ejs_GlobalVariable_specops); *_this = O; GlobalVariable* gv = (GlobalVariable*)EJSVAL_TO_OBJECT(O); REQ_LLVM_MODULE_ARG(0, module); REQ_LLVM_TYPE_ARG(1, type); REQ_UTF8_ARG(2, name); REQ_NULLABLE_LLVM_CONST_ARG(3, init); REQ_BOOL_ARG(4, visible); gv->llvm_global = new ::llvm::GlobalVariable(*module, type, false, visible ? llvm::GlobalValue::ExternalLinkage : llvm::GlobalValue::InternalLinkage, init, name); return *_this; } }
// ECMA262: 19.4.3.2 Symbol.prototype.toString () static EJS_NATIVE_FUNC(_ejs_Symbol_prototype_toString) { // 1. Let s be the this value. ejsval s = *_this; EJSPrimSymbol* sym; // 2. If Type(s) is Symbol, then let sym be s. if (EJSVAL_IS_SYMBOL(s)) { sym = EJSVAL_TO_SYMBOL(s); } // 3. Else, else { // a. If s does not have a [[SymbolData]] internal slot, then throw a TypeError exception. if (!EJSVAL_IS_SYMBOL_OBJECT(s)) { _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Symbol.prototype.toString called with non-symbol this"); } // b. Let sym be the value of s’s [[SymbolData]] internal slot. sym = EJSVAL_TO_SYMBOL(EJSVAL_TO_SYMBOL_OBJECT(s)->primSymbol); } // 4. Let desc be the value of sym’s [[Description]] attribute. ejsval desc = sym->description; // 5. If desc is undefined, then let desc be the empty string. if (EJSVAL_IS_UNDEFINED(desc)) desc = _ejs_atom_empty; // 6. Assert: Type(desc) is String. // 7. Let result be the result of concatenating the strings "Symbol(", desc, and ")". ejsval result = _ejs_string_concatv (_ejs_atom_Symbol, _ejs_string_new_utf8("("), desc, _ejs_string_new_utf8(")"), _ejs_null); // 8. Return result. return result; }
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 _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_RegExp_create (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { // 1. Let F be the this value. ejsval F = _this; if (!EJSVAL_IS_CONSTRUCTOR(F)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "'this' in RegExp[Symbol.create] is not a constructor"); EJSObject* F_ = EJSVAL_TO_OBJECT(F); // 2. Let obj be the result of calling OrdinaryCreateFromConstructor(constructor, "%RegExpPrototype%", ( [[RegExpMatcher]], [[OriginalSource]], [[OriginalFlags]])). ejsval proto = OP(F_,Get)(F, _ejs_atom_prototype, F); if (EJSVAL_IS_UNDEFINED(proto)) proto = _ejs_RegExp_prototype; EJSRegExp* re = (EJSRegExp*)_ejs_gc_new (EJSRegExp); _ejs_init_object ((EJSObject*)re, proto, &_ejs_RegExp_specops); re->pattern = _ejs_undefined; re->flags = _ejs_undefined; return OBJECT_TO_EJSVAL((EJSObject*)re); }
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(); }
// 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; }
ejsval _ejs_op_typeof_is_undefined(ejsval exp) { return EJSVAL_IS_UNDEFINED(exp) ? _ejs_true : _ejs_false; }
int _ejs_op_foo(ejsval exp) { return (EJSVAL_IS_NULL(exp) || EJSVAL_IS_UNDEFINED(exp)) ? 1 : 0; }
// ES2015, June 2015 // 23.4.1.1 WeakSet ( [ iterable ] ) static EJS_NATIVE_FUNC(_ejs_WeakSet_impl) { ejsval iterable = _ejs_undefined; if (argc > 0) iterable = args[0]; // 1. If NewTarget is undefined, throw a TypeError exception. if (EJSVAL_IS_UNDEFINED(newTarget)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "WeakSet constructor must be called with new"); // 2. Let set be OrdinaryCreateFromConstructor(NewTarget, "%WeakSetPrototype%", «[[WeakSetData]]»). // 3. ReturnIfAbrupt(set). // 4. Set set’s [[WeakSetData]] internal slot to a new empty List. ejsval set = OrdinaryCreateFromConstructor(newTarget, _ejs_WeakSet_prototype, &_ejs_WeakSet_specops); *_this = set; // 5. If iterable is not present, let iterable be undefined. // 6. If iterable is either undefined or null, let iter be undefined. ejsval iter; ejsval adder; if (EJSVAL_IS_NULL_OR_UNDEFINED(iterable)) { iter = _ejs_undefined; } // 7. Else, else { // a. Let adder be Get(set, "add"). // b. ReturnIfAbrupt(adder). adder = Get (set, _ejs_atom_add); // c. If IsCallable(adder) is false, throw a TypeError exception. if (!IsCallable(adder)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "WeakSet.prototype.add is not a function"); // d. Let iter be GetIterator(iterable). // e. ReturnIfAbrupt(iter). iter = GetIterator(iterable, _ejs_undefined); } // 8. If iter is undefined, return set. if (EJSVAL_IS_UNDEFINED(iter)) return set; // 9. Repeat for (;;) { // a. Let next be IteratorStep(iter). // b. ReturnIfAbrupt(next). ejsval next = IteratorStep (iter); // c. If next is false, return set. if (!EJSVAL_TO_BOOLEAN(next)) return set; // d. Let nextValue be IteratorValue(next). // e. ReturnIfAbrupt(nextValue). ejsval nextValue = IteratorValue (next); // f. Let status be Call(adder, set, «nextValue »). // XXX _ejs_invoke_closure won't call proxy methods ejsval rv; EJSBool status = _ejs_invoke_closure_catch (&rv, adder, &set, 1, &nextValue, _ejs_undefined); // g. If status is an abrupt completion, return IteratorClose(iter, status). if (!status) return IteratorClose(iter, rv, EJS_TRUE); } }
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); }
// ES6: 23.2.1.1 Set ( [ iterable ] ) static ejsval _ejs_Set_impl (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { // 1. Let set be the this value. ejsval set = _this; if (EJSVAL_IS_UNDEFINED(set)) { EJSObject* obj = (EJSObject*)_ejs_gc_new(EJSSet); _ejs_init_object (obj, _ejs_Set_prototype, &_ejs_Set_specops); set = OBJECT_TO_EJSVAL(obj); } // 2. If Type(set) is not Object then, throw a TypeError exception. if (!EJSVAL_IS_OBJECT(set)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set constructor called with non-object this."); // 3. If set does not have a [[SetData]] internal slot, then throw a TypeError exception. if (!EJSVAL_IS_SET(set)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set constructor called with non-Set this."); EJSSet* _set = EJSVAL_TO_SET(set); // 4. If set’s [[SetData]] internal slot is not undefined, then throw a TypeError exception. if (_set->head_insert) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set constructor called with an already initialized Set"); // 5. If iterable is not present, let iterable be undefined. ejsval iterable = _ejs_undefined; if (argc > 0) iterable = args[0]; ejsval iter = _ejs_undefined; ejsval adder = _ejs_undefined; // 6. If iterable is either undefined or null, then let iter be undefined. // 7. Else, if (!EJSVAL_IS_UNDEFINED(iterable) && !EJSVAL_IS_NULL(iterable)) { // a. Let iter be the result of GetIterator(iterable). // b. ReturnIfAbrupt(iter). iter = GetIterator (iterable, _ejs_undefined); // c. Let adder be the result of Get(set, "add"). // d. ReturnIfAbrupt(adder). adder = Get (set, _ejs_atom_add); // e. If IsCallable(adder) is false, throw a TypeError Exception. if (!EJSVAL_IS_CALLABLE(adder)) _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "Set.prototype.add is not a function"); } // 8. If the value of sets’s [[SetData]] internal slot is not undefined, then throw a TypeError exception. // 9. Assert: set has not been reentrantly initialized. // 10. Set set’s [[SetData]] internal slot to a new empty List. // 11. If iter is undefined, then return set. if (EJSVAL_IS_UNDEFINED(iter)) return set; // 12. Repeat for (;;) { // a. Let next be the result of IteratorStep(iter). // b. ReturnIfAbrupt(next). ejsval next = IteratorStep (iter); // c. If next is false, then return set. if (!EJSVAL_TO_BOOLEAN(next)) return set; // d. Let nextValue be IteratorValue(next). // e. ReturnIfAbrupt(nextValue). ejsval nextValue = IteratorValue (next); // f. Let status be the result of calling the [[Call]] internal method of adder with set as thisArgument // and a List whose sole element is nextValue as argumentsList. // g. ReturnIfAbrupt(status). _ejs_invoke_closure (adder, set, 1, &nextValue); } return set; }