File indexing completed on 2024-06-30 05:51:30

0001 /*
0002     This file is part of the Okteta Kasten Framework, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2011, 2012 Alex Richardson <alex.richardson@gmx.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "arrayscriptclass.hpp"
0010 #include "../../datatypes/array/arraydatainformation.hpp"
0011 #include "../../parsers/parserutils.hpp"
0012 #include "../../parsers/scriptvalueconverter.hpp"
0013 #include "../scriptlogger.hpp"
0014 #include <structureslogging.hpp>
0015 
0016 ArrayScriptClass::ArrayScriptClass(QScriptEngine* engine, ScriptHandlerInfo* handlerInfo)
0017     : DefaultScriptClass(engine, handlerInfo)
0018 {
0019     s_length = engine->toStringHandle(ParserStrings::PROPERTY_LENGTH());
0020     mIterableProperties.append(qMakePair(s_length, QScriptValue::PropertyFlags(QScriptValue::Undeletable)));
0021     s_childType = engine->toStringHandle(QStringLiteral("childType"));
0022     // the preferred property (the same as childType)
0023     s_type = engine->toStringHandle(ParserStrings::PROPERTY_TYPE());
0024     mIterableProperties.append(qMakePair(s_type, QScriptValue::PropertyFlags(QScriptValue::Undeletable)));
0025 
0026     mArrayPrototype = engine->newObject();
0027     mArrayPrototype.setProperty(QStringLiteral("toString"), engine->newFunction(Array_proto_toString));
0028 }
0029 
0030 ArrayScriptClass::~ArrayScriptClass() = default;
0031 
0032 bool ArrayScriptClass::queryAdditionalProperty(const DataInformation* data, const QScriptString& name, QScriptClass::QueryFlags* flags, uint* id)
0033 {
0034     Q_UNUSED(data)
0035     // no need to modify flags since both read and write are handled
0036     if (name == s_length) {
0037         return true;
0038     }
0039     if (name == s_type || name == s_childType) {
0040         return true;
0041     }
0042 
0043     bool isArrayIndex;
0044     quint32 pos = name.toArrayIndex(&isArrayIndex);
0045     if (isArrayIndex && pos <= data->childCount()) {
0046         *id = pos + 1; // add 1 to distinguish from the default value of 0
0047         *flags &= ~HandlesWriteAccess; // writing is not yet supported
0048         return true;
0049     }
0050     return false; // not found
0051 }
0052 
0053 bool ArrayScriptClass::additionalPropertyFlags(const DataInformation* data, const QScriptString& name, uint id, QScriptValue::PropertyFlags* flags)
0054 {
0055     Q_UNUSED(data)
0056     Q_UNUSED(name)
0057     if (name == s_childType) {
0058         return true; // undeleteable is on by default
0059     }
0060     if (id != 0) {
0061         *flags |= QScriptValue::ReadOnly;
0062         return true;
0063     }
0064     return false;
0065 }
0066 
0067 QScriptValue ArrayScriptClass::additionalProperty(const DataInformation* data, const QScriptString& name, uint id)
0068 {
0069     const ArrayDataInformation* aData = data->asArray();
0070     if (id != 0) {
0071         quint32 pos = id - 1;
0072         if (pos >= data->childCount()) {
0073             aData->logError() << "attempting to access out of bounds child: index was" << pos
0074                               << ", length is" << data->childCount();
0075             return engine()->currentContext()->throwError(QScriptContext::RangeError,
0076                                                           QStringLiteral("Attempting to access array index %1, but length is %2").arg(
0077                                                               QString::number(pos), QString::number(data->childCount())));
0078         }
0079 
0080         return aData->childToScriptValue(pos, engine(), mHandlerInfo);
0081     }
0082     if (name == s_length) {
0083         return aData->length();
0084     }
0085     if (name == s_type) {
0086         return aData->childType();
0087     }
0088     if (name == s_childType) {
0089         aData->logWarn() << "Using property 'childType' is deprecated, use the new name 'type' instead";
0090         return aData->childType();
0091     }
0092     return {};
0093 }
0094 
0095 bool ArrayScriptClass::setAdditionalProperty(DataInformation* data, const QScriptString& name, uint, const QScriptValue& value)
0096 {
0097     ArrayDataInformation* aData = data->asArray();
0098     if (name == s_length) {
0099         if (value.isFunction()) {
0100             aData->setLengthFunction(value);
0101         } else {
0102             ParsedNumber<uint> newLength = ParserUtils::uintFromScriptValue(value);
0103             if (!newLength.isValid) {
0104                 aData->logError() << "new length of array is invalid:" << newLength.string;
0105                 aData->setArrayLength(0);
0106             } else {
0107                 aData->setArrayLength(newLength.value);
0108             }
0109         }
0110         return true;
0111     }
0112     if (name == s_type || name == s_childType) {
0113         if (name == s_childType) {
0114             aData->logWarn() << "Using property 'childType' is deprecated, use the new name 'type' instead";
0115         }
0116 
0117         DataInformation* newChildType = ScriptValueConverter::convert(value,
0118                                                                       aData->name(), aData->logger(), aData);
0119 
0120         if (!newChildType) {
0121             aData->logError() << "Failed to parse new child type:" << value.toString();
0122         } else {
0123             aData->setArrayType(newChildType);
0124         }
0125         return true;
0126     }
0127     return false;
0128 }
0129 
0130 QScriptValue ArrayScriptClass::prototype() const
0131 {
0132     return mArrayPrototype;
0133 }
0134 
0135 QScriptValue ArrayScriptClass::Array_proto_toString(QScriptContext* ctx, QScriptEngine* eng)
0136 {
0137     DataInformation* data = toDataInformation(ctx->thisObject());
0138     if (!data) {
0139         qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data";
0140         return eng->undefinedValue();
0141     }
0142     return data->typeName();
0143 }