/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * JS boolean implementation. */ #include "builtin/Boolean-inl.h" #include "jsapi.h" #include "jstypes.h" #include "jit/InlinableNatives.h" #include "js/PropertySpec.h" #include "util/StringBuffer.h" #include "vm/BigIntType.h" #include "vm/GlobalObject.h" #include "vm/JSAtom.h" #include "vm/JSContext.h" #include "vm/JSObject.h" #include "vm/ProxyObject.h" #include "vm/BooleanObject-inl.h" using namespace js; const JSClass BooleanObject::class_ = { "Boolean", JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean), JS_NULL_CLASS_OPS, &BooleanObject::classSpec_}; MOZ_ALWAYS_INLINE bool IsBoolean(HandleValue v) { return v.isBoolean() || (v.isObject() && v.toObject().is()); } // ES2020 draft rev ecb4178012d6b4d9abc13fcbd45f5c6394b832ce // 19.4.3 Properties of the Boolean Prototype Object, thisBooleanValue. static MOZ_ALWAYS_INLINE bool ThisBooleanValue(HandleValue val) { // Step 3, the error case, is handled by CallNonGenericMethod. MOZ_ASSERT(IsBoolean(val)); // Step 1. if (val.isBoolean()) { return val.toBoolean(); } // Step 2. return val.toObject().as().unbox(); } MOZ_ALWAYS_INLINE bool bool_toSource_impl(JSContext* cx, const CallArgs& args) { bool b = ThisBooleanValue(args.thisv()); JSStringBuilder sb(cx); if (!sb.append("(new Boolean(") || !BooleanToStringBuffer(b, sb) || !sb.append("))")) { return false; } JSString* str = sb.finishString(); if (!str) { return false; } args.rval().setString(str); return true; } static bool bool_toSource(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); return CallNonGenericMethod(cx, args); } // ES2020 draft rev ecb4178012d6b4d9abc13fcbd45f5c6394b832ce // 19.3.3.2 Boolean.prototype.toString ( ) MOZ_ALWAYS_INLINE bool bool_toString_impl(JSContext* cx, const CallArgs& args) { // Step 1. bool b = ThisBooleanValue(args.thisv()); // Step 2. args.rval().setString(BooleanToString(cx, b)); return true; } static bool bool_toString(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); return CallNonGenericMethod(cx, args); } // ES2020 draft rev ecb4178012d6b4d9abc13fcbd45f5c6394b832ce // 19.3.3.3 Boolean.prototype.valueOf ( ) MOZ_ALWAYS_INLINE bool bool_valueOf_impl(JSContext* cx, const CallArgs& args) { // Step 1. args.rval().setBoolean(ThisBooleanValue(args.thisv())); return true; } static bool bool_valueOf(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); return CallNonGenericMethod(cx, args); } static const JSFunctionSpec boolean_methods[] = { JS_FN(js_toSource_str, bool_toSource, 0, 0), JS_FN(js_toString_str, bool_toString, 0, 0), JS_FN(js_valueOf_str, bool_valueOf, 0, 0), JS_FS_END}; // ES2020 draft rev ecb4178012d6b4d9abc13fcbd45f5c6394b832ce // 19.3.1.1 Boolean ( value ) static bool Boolean(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); // Step 1. bool b = args.length() != 0 ? JS::ToBoolean(args[0]) : false; if (args.isConstructing()) { // Steps 3-4. RootedObject proto(cx); if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Boolean, &proto)) { return false; } JSObject* obj = BooleanObject::create(cx, b, proto); if (!obj) { return false; } // Step 5. args.rval().setObject(*obj); } else { // Step 2. args.rval().setBoolean(b); } return true; } JSObject* BooleanObject::createPrototype(JSContext* cx, JSProtoKey key) { BooleanObject* booleanProto = GlobalObject::createBlankPrototype(cx, cx->global()); if (!booleanProto) { return nullptr; } booleanProto->setFixedSlot(BooleanObject::PRIMITIVE_VALUE_SLOT, BooleanValue(false)); return booleanProto; } const ClassSpec BooleanObject::classSpec_ = { GenericCreateConstructor, BooleanObject::createPrototype, nullptr, nullptr, boolean_methods, nullptr}; PropertyName* js::BooleanToString(JSContext* cx, bool b) { return b ? cx->names().true_ : cx->names().false_; } JS_PUBLIC_API bool js::ToBooleanSlow(HandleValue v) { if (v.isString()) { return v.toString()->length() != 0; } if (v.isBigInt()) { return !v.toBigInt()->isZero(); } MOZ_ASSERT(v.isObject()); return !EmulatesUndefined(&v.toObject()); }