File indexing completed on 2024-06-30 05:51:31
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 "structunionscriptclass.hpp" 0010 #include "../../datatypes/datainformationwithchildren.hpp" 0011 #include "../../datatypes/topleveldatainformation.hpp" 0012 #include "../../parsers/parserutils.hpp" 0013 #include "../scriptlogger.hpp" 0014 #include <structureslogging.hpp> 0015 0016 StructUnionScriptClass::StructUnionScriptClass(QScriptEngine* engine, ScriptHandlerInfo* handlerInfo) 0017 : DefaultScriptClass(engine, handlerInfo) 0018 { 0019 s_childCount = engine->toStringHandle(ParserStrings::PROPERTY_CHILD_COUNT()); // read-only 0020 mIterableProperties.append(qMakePair(s_childCount, QScriptValue::ReadOnly | QScriptValue::Undeletable)); 0021 s_children = engine->toStringHandle(ParserStrings::PROPERTY_CHILDREN()); // write-only 0022 0023 mStructUnionPrototype = engine->newObject(); 0024 mStructUnionPrototype.setProperty(QStringLiteral("toString"), 0025 engine->newFunction(StructUnion_proto_toString)); 0026 mStructUnionPrototype.setProperty(QStringLiteral("setChildren"), 0027 engine->newFunction(StructUnion_proto_setChildren)); 0028 mStructUnionPrototype.setProperty(QStringLiteral("child"), 0029 engine->newFunction(StructUnion_proto_child)); 0030 } 0031 0032 StructUnionScriptClass::~StructUnionScriptClass() = default; 0033 0034 bool StructUnionScriptClass::queryAdditionalProperty(const DataInformation* data, const QScriptString& name, QScriptClass::QueryFlags* flags, uint* id) 0035 { 0036 Q_UNUSED(data) 0037 // no need to modify flags since both read and write are handled 0038 if (name == s_childCount) { 0039 *flags &= ~HandlesWriteAccess; 0040 return true; 0041 } 0042 if (name == s_children) { 0043 *flags &= ~HandlesReadAccess; 0044 return true; 0045 } 0046 0047 bool isArrayIndex; 0048 quint32 pos = name.toArrayIndex(&isArrayIndex); 0049 uint count = data->childCount(); 0050 bool isValidChild = false; 0051 if (isArrayIndex && pos < count) { 0052 isValidChild = true; 0053 } else { 0054 // compare name, names that match special properties/functions will be 0055 // hidden since these were checked before 0056 QString objName = name.toString(); 0057 for (uint i = 0; i < count; ++i) { 0058 if (objName == data->childAt(i)->name()) { 0059 isValidChild = true; 0060 pos = i; 0061 break; 0062 } 0063 } 0064 } 0065 if (isValidChild) { 0066 *id = pos + 1; // add 1 to distinguish from the default value of 0 0067 *flags &= ~HandlesWriteAccess; // writing is not yet supported 0068 return true; 0069 } 0070 return false; // not found 0071 } 0072 0073 bool StructUnionScriptClass::additionalPropertyFlags(const DataInformation* data, const QScriptString& name, uint id, QScriptValue::PropertyFlags* flags) 0074 { 0075 Q_UNUSED(data) 0076 // no need to modify flags since both read and write are handled 0077 if (id != 0) { 0078 *flags |= QScriptValue::ReadOnly; 0079 return true; 0080 } 0081 // TODO is this necessary, will there be any way a child has no id set? 0082 // check named children 0083 QString objName = name.toString(); 0084 uint count = data->childCount(); 0085 for (uint i = 0; i < count; ++i) { 0086 DataInformation* child = data->childAt(i); 0087 Q_CHECK_PTR(child); 0088 if (objName == child->name()) { 0089 *flags |= QScriptValue::ReadOnly; 0090 return true; 0091 } 0092 } 0093 0094 return false; 0095 } 0096 0097 QScriptValue StructUnionScriptClass::additionalProperty(const DataInformation* data, const QScriptString& name, uint id) 0098 { 0099 const auto* dataW = static_cast<const DataInformationWithChildren*>(data); 0100 // do a dynamic cast in debug mode to ensure the static cast was valid 0101 Q_CHECK_PTR(dynamic_cast<const DataInformationWithChildren*>(dataW)); 0102 0103 if (id != 0) { 0104 quint32 pos = id - 1; 0105 if (pos >= data->childCount()) { 0106 dataW->logError() << "attempting to access out of bounds child: index was" << pos 0107 << ", maximum is" << (data->childCount() - 1); 0108 return engine()->currentContext()->throwError(QScriptContext::RangeError, 0109 QStringLiteral("Attempting to access struct index %1, but length is %2").arg( 0110 QString::number(pos), QString::number(data->childCount()))); 0111 } 0112 Q_CHECK_PTR(data->childAt(pos)); 0113 return data->childAt(pos)->toScriptValue(engine(), mHandlerInfo); 0114 } 0115 if (name == s_childCount) { 0116 return dataW->childCount(); 0117 } 0118 if (name == s_children) { 0119 dataW->logError() << "attempting to read read-only property" << s_children.toString(); 0120 return engine()->undefinedValue(); 0121 } 0122 // TODO is this necessary, will there be any way a child has no id set? 0123 // TODO testing seems to indicate this is not necessary, will leave it thought until I'm sure 0124 // check named children 0125 QString objName = name.toString(); 0126 uint count = data->childCount(); 0127 for (uint i = 0; i < count; ++i) { 0128 DataInformation* child = data->childAt(i); 0129 Q_CHECK_PTR(child); 0130 if (objName == child->name()) { 0131 return child->toScriptValue(engine(), mHandlerInfo); 0132 } 0133 } 0134 return {}; 0135 } 0136 0137 bool StructUnionScriptClass::setAdditionalProperty(DataInformation* data, const QScriptString& name, uint, const QScriptValue& value) 0138 { 0139 auto* dataW = static_cast<DataInformationWithChildren*>(data); 0140 // do a dynamic cast in debug mode to ensure the static cast was valid 0141 Q_CHECK_PTR(dynamic_cast<DataInformationWithChildren*>(dataW)); 0142 0143 if (name == s_children) { 0144 dataW->setChildren(value); 0145 return true; 0146 } 0147 // TODO set children!! 0148 return false; 0149 } 0150 0151 QScriptValue StructUnionScriptClass::prototype() const 0152 { 0153 return mStructUnionPrototype; 0154 } 0155 0156 QScriptValue StructUnionScriptClass::StructUnion_proto_toString(QScriptContext* ctx, QScriptEngine* eng) 0157 { 0158 DataInformation* data = toDataInformation(ctx->thisObject()); 0159 if (!data) { 0160 qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data"; 0161 return eng->undefinedValue(); 0162 } 0163 return data->typeName(); // TODO better toString 0164 } 0165 0166 QScriptValue StructUnionScriptClass::StructUnion_proto_child(QScriptContext* ctx, QScriptEngine* eng) 0167 { 0168 if (ctx->argumentCount() < 1) { 0169 ctx->throwError(QScriptContext::RangeError, 0170 QStringLiteral("(struct/union).child(name) needs at least one argument")); 0171 return eng->undefinedValue(); 0172 } 0173 QScriptValue arg = ctx->argument(0); 0174 if (!arg.isString()) { 0175 ctx->throwError(QScriptContext::TypeError, 0176 QStringLiteral("(struct/union).child(name) argument has to be a string")); 0177 return QScriptValue::UndefinedValue; 0178 } 0179 DataInformation* data = toDataInformation(ctx->thisObject()); 0180 if (!data) { 0181 qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data"; 0182 return eng->undefinedValue(); 0183 } 0184 uint count = data->childCount(); 0185 QString name = arg.toString(); 0186 for (uint i = 0; i < count; i++) { 0187 DataInformation* child = data->childAt(i); 0188 if (child->name() == name) { 0189 return child->toScriptValue(eng, data->topLevelDataInformation()->scriptHandler()->handlerInfo()); 0190 } 0191 } 0192 0193 return eng->nullValue(); 0194 } 0195 0196 QScriptValue StructUnionScriptClass::StructUnion_proto_setChildren(QScriptContext* ctx, QScriptEngine* eng) 0197 { 0198 if (ctx->argumentCount() < 1) { 0199 return ctx->throwError(QScriptContext::RangeError, 0200 QStringLiteral("(struct/union).child(children) needs one argument")); 0201 } 0202 DataInformation* data = toDataInformation(ctx->thisObject()); 0203 if (!data) { 0204 qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data"; 0205 return eng->undefinedValue(); 0206 } 0207 auto* dataW = static_cast<DataInformationWithChildren*>(data); 0208 // do a dynamic cast in debug mode to ensure the static cast was valid 0209 Q_CHECK_PTR(dynamic_cast<DataInformationWithChildren*>(dataW)); 0210 0211 dataW->setChildren(ctx->argument(0)); 0212 return eng->undefinedValue(); 0213 }