1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include <qv4symbol_p.h>
41 #include <qv4functionobject_p.h>
42 #include <qv4identifiertable_p.h>
43 
44 using namespace QV4;
45 
46 DEFINE_OBJECT_VTABLE(SymbolCtor);
47 DEFINE_MANAGED_VTABLE(Symbol);
48 DEFINE_OBJECT_VTABLE(SymbolObject);
49 
init(const QString & s)50 void Heap::Symbol::init(const QString &s)
51 {
52     Q_ASSERT(s.at(0) == QLatin1Char('@'));
53     identifier = PropertyKey::fromStringOrSymbol(this);
54     QString desc(s);
55     text = desc.data_ptr();
56     text->ref.ref();
57 }
58 
init(QV4::ExecutionContext * scope)59 void Heap::SymbolCtor::init(QV4::ExecutionContext *scope)
60 {
61     Heap::FunctionObject::init(scope, QStringLiteral("Symbol"));
62 }
63 
init(const QV4::Symbol * s)64 void Heap::SymbolObject::init(const QV4::Symbol *s)
65 {
66     Object::init();
67     symbol.set(internalClass->engine, s->d());
68 }
69 
virtualCall(const QV4::FunctionObject * f,const QV4::Value *,const QV4::Value * argv,int argc)70 ReturnedValue QV4::SymbolCtor::virtualCall(const QV4::FunctionObject *f, const QV4::Value *, const QV4::Value *argv, int argc)
71 {
72     Scope scope(f);
73     QString desc = QChar::fromLatin1('@');
74     if (argc && !argv[0].isUndefined()) {
75         ScopedString s(scope, argv[0].toString(scope.engine));
76         if (scope.hasException())
77             return Encode::undefined();
78         desc += s->toQString();
79     }
80     return Symbol::create(scope.engine, desc)->asReturnedValue();
81 }
82 
virtualCallAsConstructor(const FunctionObject * f,const Value *,int,const Value *)83 ReturnedValue SymbolCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *, int, const Value *)
84 {
85     return f->engine()->throwTypeError(QStringLiteral("Symbol can't be used together with |new|."));
86 }
87 
method_for(const FunctionObject * f,const Value *,const Value * argv,int argc)88 ReturnedValue SymbolCtor::method_for(const FunctionObject *f, const Value *, const Value *argv, int argc)
89 {
90     Scope scope(f);
91     ScopedValue k(scope, argc ? argv[0]: Value::undefinedValue());
92     ScopedString key(scope, k->toString(scope.engine));
93     if (scope.hasException())
94         return Encode::undefined();
95     QString desc = QLatin1Char('@') + key->toQString();
96     return scope.engine->identifierTable->insertSymbol(desc)->asReturnedValue();
97 }
98 
method_keyFor(const FunctionObject * f,const Value *,const Value * argv,int argc)99 ReturnedValue SymbolCtor::method_keyFor(const FunctionObject *f, const Value *, const Value *argv, int argc)
100 {
101     ExecutionEngine *e = f->engine();
102     if (!argc || !argv[0].isSymbol())
103         return e->throwTypeError(QLatin1String("Symbol.keyFor: Argument is not a symbol."));
104     const Symbol &arg = static_cast<const Symbol &>(argv[0]);
105     Heap::Symbol *s = e->identifierTable->symbolForId(arg.propertyKey());
106     Q_ASSERT(!s || s == arg.d());
107     if (s)
108         return e->newString(arg.toQString().mid((1)))->asReturnedValue();
109     return Encode::undefined();
110 }
111 
init(ExecutionEngine * engine,Object * ctor)112 void SymbolPrototype::init(ExecutionEngine *engine, Object *ctor)
113 {
114     Scope scope(engine);
115     ScopedValue v(scope);
116     ctor->defineReadonlyProperty(engine->id_prototype(), (v = this));
117     ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(0));
118 
119     ctor->defineDefaultProperty(QStringLiteral("for"), SymbolCtor::method_for, 1);
120     ctor->defineDefaultProperty(QStringLiteral("keyFor"), SymbolCtor::method_keyFor, 1);
121     ctor->defineReadonlyProperty(QStringLiteral("hasInstance"), *engine->symbol_hasInstance());
122     ctor->defineReadonlyProperty(QStringLiteral("isConcatSpreadable"), *engine->symbol_isConcatSpreadable());
123     ctor->defineReadonlyProperty(QStringLiteral("iterator"), *engine->symbol_iterator());
124     ctor->defineReadonlyProperty(QStringLiteral("match"), *engine->symbol_match());
125     ctor->defineReadonlyProperty(QStringLiteral("replace"), *engine->symbol_replace());
126     ctor->defineReadonlyProperty(QStringLiteral("search"), *engine->symbol_search());
127     ctor->defineReadonlyProperty(QStringLiteral("species"), *engine->symbol_species());
128     ctor->defineReadonlyProperty(QStringLiteral("split"), *engine->symbol_split());
129     ctor->defineReadonlyProperty(QStringLiteral("toPrimitive"), *engine->symbol_toPrimitive());
130     ctor->defineReadonlyProperty(QStringLiteral("toStringTag"), *engine->symbol_toStringTag());
131     ctor->defineReadonlyProperty(QStringLiteral("unscopables"), *engine->symbol_unscopables());
132 
133     defineDefaultProperty(QStringLiteral("constructor"), (v = ctor));
134     defineDefaultProperty(QStringLiteral("toString"), method_toString);
135     defineDefaultProperty(QStringLiteral("valueOf"), method_valueOf);
136     defineDefaultProperty(engine->symbol_toPrimitive(), method_symbolToPrimitive, 1, Attr_ReadOnly_ButConfigurable);
137 
138     v = engine->newString(QStringLiteral("Symbol"));
139     defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), v);
140 
141 }
142 
method_toString(const FunctionObject * f,const Value * thisObject,const Value *,int)143 ReturnedValue SymbolPrototype::method_toString(const FunctionObject *f, const Value *thisObject, const Value *, int)
144 {
145     Scope scope(f);
146     Scoped<Symbol> s(scope, thisObject->as<Symbol>());
147     if (!s) {
148         if (const SymbolObject *o = thisObject->as<SymbolObject>())
149             s = o->d()->symbol;
150         else
151             return scope.engine->throwTypeError();
152     }
153     return scope.engine->newString(s->descriptiveString())->asReturnedValue();
154 }
155 
method_valueOf(const FunctionObject * f,const Value * thisObject,const Value *,int)156 ReturnedValue SymbolPrototype::method_valueOf(const FunctionObject *f, const Value *thisObject, const Value *, int)
157 {
158     Scope scope(f);
159     Scoped<Symbol> s(scope, thisObject->as<Symbol>());
160     if (!s) {
161         if (const SymbolObject *o = thisObject->as<SymbolObject>())
162             s = o->d()->symbol;
163         else
164             return scope.engine->throwTypeError();
165     }
166     return s->asReturnedValue();
167 }
168 
method_symbolToPrimitive(const FunctionObject * f,const Value * thisObject,const Value *,int)169 ReturnedValue SymbolPrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *, int)
170 {
171     if (thisObject->isSymbol())
172         return thisObject->asReturnedValue();
173     if (const SymbolObject *o = thisObject->as<SymbolObject>())
174         return o->d()->symbol->asReturnedValue();
175     return f->engine()->throwTypeError();
176 }
177 
create(ExecutionEngine * e,const QString & s)178 Heap::Symbol *Symbol::create(ExecutionEngine *e, const QString &s)
179 {
180     Q_ASSERT(s.at(0) == QLatin1Char('@'));
181     return e->memoryManager->alloc<Symbol>(s);
182 }
183 
descriptiveString() const184 QString Symbol::descriptiveString() const
185 {
186     return QLatin1String("Symbol(") + toQString().midRef(1) + QLatin1String(")");
187 }
188