1/*
2 * Copyright (C) 2012, 2016 Apple Inc. All rights reserved.
3 * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "SymbolPrototype.h"
29
30#include "Error.h"
31#include "JSCInlines.h"
32#include "JSString.h"
33#include "SymbolObject.h"
34
35namespace JSC {
36
37static EncodedJSValue JSC_HOST_CALL symbolProtoGetterDescription(ExecState*);
38static EncodedJSValue JSC_HOST_CALL symbolProtoFuncToString(ExecState*);
39static EncodedJSValue JSC_HOST_CALL symbolProtoFuncValueOf(ExecState*);
40
41}
42
43#include "SymbolPrototype.lut.h"
44
45namespace JSC {
46
47const ClassInfo SymbolPrototype::s_info = { "Symbol", &Base::s_info, &symbolPrototypeTable, nullptr, CREATE_METHOD_TABLE(SymbolPrototype) };
48
49/* Source for SymbolPrototype.lut.h
50@begin symbolPrototypeTable
51 description symbolProtoGetterDescription DontEnum|Accessor 0
52 toString symbolProtoFuncToString DontEnum|Function 0
53 valueOf symbolProtoFuncValueOf DontEnum|Function 0
54@end
55*/
56
57SymbolPrototype::SymbolPrototype(VM& vm, Structure* structure)
58 : Base(vm, structure)
59{
60}
61
62void SymbolPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
63{
64 Base::finishCreation(vm);
65 putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Symbol"), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
66 ASSERT(inherits(vm, info()));
67
68 JSFunction* toPrimitiveFunction = JSFunction::create(vm, globalObject, 1, "[Symbol.toPrimitive]"_s, symbolProtoFuncValueOf, NoIntrinsic);
69 putDirectWithoutTransition(vm, vm.propertyNames->toPrimitiveSymbol, toPrimitiveFunction, PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
70}
71
72// ------------------------------ Functions ---------------------------
73
74static const ASCIILiteral SymbolDescriptionTypeError { "Symbol.prototype.description requires that |this| be a symbol or a symbol object"_s };
75static const ASCIILiteral SymbolToStringTypeError { "Symbol.prototype.toString requires that |this| be a symbol or a symbol object"_s };
76static const ASCIILiteral SymbolValueOfTypeError { "Symbol.prototype.valueOf requires that |this| be a symbol or a symbol object"_s };
77
78inline Symbol* tryExtractSymbol(VM& vm, JSValue thisValue)
79{
80 if (thisValue.isSymbol())
81 return asSymbol(thisValue);
82
83 if (!thisValue.isObject())
84 return nullptr;
85 JSObject* thisObject = asObject(thisValue);
86 if (!thisObject->inherits<SymbolObject>(vm))
87 return nullptr;
88 return asSymbol(jsCast<SymbolObject*>(thisObject)->internalValue());
89}
90
91EncodedJSValue JSC_HOST_CALL symbolProtoGetterDescription(ExecState* exec)
92{
93 VM& vm = exec->vm();
94 auto scope = DECLARE_THROW_SCOPE(vm);
95
96 Symbol* symbol = tryExtractSymbol(vm, exec->thisValue());
97 if (!symbol)
98 return throwVMTypeError(exec, scope, SymbolDescriptionTypeError);
99 scope.release();
100 const auto description = symbol->description();
101 return JSValue::encode(description.isNull() ? jsUndefined() : jsString(&vm, description));
102}
103
104EncodedJSValue JSC_HOST_CALL symbolProtoFuncToString(ExecState* exec)
105{
106 VM& vm = exec->vm();
107 auto scope = DECLARE_THROW_SCOPE(vm);
108
109 Symbol* symbol = tryExtractSymbol(vm, exec->thisValue());
110 if (!symbol)
111 return throwVMTypeError(exec, scope, SymbolToStringTypeError);
112 RELEASE_AND_RETURN(scope, JSValue::encode(jsNontrivialString(&vm, symbol->descriptiveString())));
113}
114
115EncodedJSValue JSC_HOST_CALL symbolProtoFuncValueOf(ExecState* exec)
116{
117 VM& vm = exec->vm();
118 auto scope = DECLARE_THROW_SCOPE(vm);
119
120 Symbol* symbol = tryExtractSymbol(vm, exec->thisValue());
121 if (!symbol)
122 return throwVMTypeError(exec, scope, SymbolValueOfTypeError);
123
124 RELEASE_AND_RETURN(scope, JSValue::encode(symbol));
125}
126
127} // namespace JSC
128