14#define qPrintableRef(x) reinterpret_cast<const char *>((x).unicode())
20XmlParser::~XmlParser()
24Node const *XmlParser::tree()
const
29bool XmlParser::parse(
const QString &filename)
33 std::cerr << qPrintable(file.errorString());
37 mReader.setDevice(&file);
38 while (!mReader.atEnd()) {
40 if (mReader.isStartElement() && mReader.name() == QLatin1StringView(
"protocol")) {
41 if (!parseProtocol()) {
50bool XmlParser::parseProtocol()
52 Q_ASSERT(mReader.name() == QLatin1StringView(
"protocol"));
54 const auto attrs = mReader.attributes();
55 if (!attrs.hasAttribute(QLatin1StringView(
"version"))) {
56 printError(QStringLiteral(
"Missing \"version\" attribute in <protocol> tag!"));
60 auto documentNode = std::make_unique<DocumentNode>(attrs.value(QLatin1StringView(
"version")).toInt());
62 while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView(
"protocol"))) {
64 if (mReader.isStartElement()) {
65 const auto elemName = mReader.name();
66 if (elemName == QLatin1StringView(
"class") || elemName == QLatin1StringView(
"command") || elemName == QLatin1StringView(
"response")
67 || elemName == QLatin1StringView(
"notification")) {
68 if (!parseCommand(documentNode.get())) {
72 printError(QStringLiteral(
"Unsupported tag: ").append(mReader.name()));
78 mTree = std::move(documentNode);
83bool XmlParser::parseCommand(DocumentNode *documentNode)
85 const auto attrs = mReader.attributes();
86 if (!attrs.hasAttribute(QLatin1StringView(
"name"))) {
87 printError(QStringLiteral(
"Missing \"name\" attribute in command tag!"));
91 auto classNode =
new ClassNode(attrs.value(QLatin1StringView(
"name")).
toString(), ClassNode::elementNameToType(mReader.name()), documentNode);
92 new CtorNode({}, classNode);
94 while (!mReader.atEnd() && !(mReader.isEndElement() && classNode->classType() == ClassNode::elementNameToType(mReader.name()))) {
96 if (mReader.isStartElement()) {
97 if (mReader.name() == QLatin1StringView(
"ctor")) {
98 if (!parseCtor(classNode)) {
101 }
else if (mReader.name() == QLatin1StringView(
"enum") || mReader.name() == QLatin1StringView(
"flag")) {
102 if (!parseEnum(classNode)) {
105 }
else if (mReader.name() == QLatin1StringView(
"param")) {
106 if (!parseParam(classNode)) {
110 printError(QStringLiteral(
"Unsupported tag: ").append(mReader.name()));
119bool XmlParser::parseCtor(ClassNode *classNode)
121 QList<CtorNode::Argument> args;
122 while (!mReader.atEnd() && !(mReader.isEndElement() && (mReader.name() == QLatin1StringView(
"ctor")))) {
124 if (mReader.isStartElement()) {
125 if (mReader.name() == QLatin1StringView(
"arg")) {
126 const auto attrs = mReader.attributes();
127 const QString
name = attrs.value(QLatin1StringView(
"name")).toString();
128 const QString def = attrs.value(QLatin1StringView(
"default")).toString();
129 args << CtorNode::Argument{
name, QString(), def};
131 printError(QStringLiteral(
"Unsupported tag: ").append(mReader.name()));
136 new CtorNode(args, classNode);
141bool XmlParser::parseEnum(ClassNode *classNode)
143 const auto attrs = mReader.attributes();
144 if (!attrs.hasAttribute(QLatin1StringView(
"name"))) {
145 printError(QStringLiteral(
"Missing \"name\" attribute in enum/flag tag!"));
149 auto enumNode =
new EnumNode(attrs.value(QLatin1StringView(
"name")).
toString(), EnumNode::elementNameToType(mReader.name()), classNode);
151 while (!mReader.atEnd() && !(mReader.isEndElement() && (enumNode->enumType() == EnumNode::elementNameToType(mReader.name())))) {
153 if (mReader.isStartElement()) {
154 if (mReader.name() == QLatin1StringView(
"value")) {
155 if (!parseEnumValue(enumNode)) {
159 printError(QStringLiteral(
"Invalid tag inside of enum/flag tag: ").append(mReader.name()));
168bool XmlParser::parseEnumValue(EnumNode *enumNode)
170 Q_ASSERT(mReader.name() == QLatin1StringView(
"value"));
172 const auto attrs = mReader.attributes();
173 if (!attrs.hasAttribute(QLatin1StringView(
"name"))) {
174 printError(QStringLiteral(
"Missing \"name\" attribute in <value> tag!"));
178 auto valueNode =
new EnumValueNode(attrs.value(QLatin1StringView(
"name")).
toString(), enumNode);
179 if (attrs.hasAttribute(QLatin1StringView(
"value"))) {
180 valueNode->setValue(attrs.value(QLatin1StringView(
"value")).
toString());
186bool XmlParser::parseParam(ClassNode *classNode)
188 Q_ASSERT(mReader.name() == QLatin1StringView(
"param"));
190 const auto attrs = mReader.attributes();
191 if (!attrs.hasAttribute(QLatin1StringView(
"name"))) {
192 printError(QStringLiteral(
"Missing \"name\" attribute in <param> tag!"));
195 if (!attrs.hasAttribute(QLatin1StringView(
"type"))) {
196 printError(QStringLiteral(
"Missing \"type\" attribute in <param> tag!"));
200 const auto name = attrs.value(QLatin1StringView(
"name")).toString();
201 const auto type = attrs.value(QLatin1StringView(
"type")).toString();
203 for (
const auto child : classNode->children()) {
204 if (child->type() == Node::Ctor) {
205 auto ctor =
const_cast<CtorNode *
>(
static_cast<const CtorNode *
>(child));
206 ctor->setArgumentType(name, type);
210 auto paramNode =
new PropertyNode(name, type, classNode);
212 if (attrs.hasAttribute(QLatin1StringView(
"default"))) {
213 paramNode->setDefaultValue(attrs.value(QLatin1StringView(
"default")).
toString());
215 if (attrs.hasAttribute(QLatin1StringView(
"readOnly"))) {
216 paramNode->setReadOnly(attrs.value(QLatin1StringView(
"readOnly")) == QLatin1StringView(
"true"));
218 if (attrs.hasAttribute(QLatin1StringView(
"asReference"))) {
219 paramNode->setAsReference(attrs.value(QLatin1StringView(
"asReference")) == QLatin1StringView(
"true"));
222 while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView(
"param"))) {
224 if (mReader.isStartElement()) {
225 if (mReader.name() == QLatin1StringView(
"setter")) {
226 if (!parseSetter(paramNode)) {
229 }
else if (mReader.name() == QLatin1StringView(
"depends")) {
230 auto dependsAttrs = mReader.attributes();
231 if (!dependsAttrs.hasAttribute(QLatin1StringView(
"enum"))) {
232 printError(QStringLiteral(
"Missing \"enum\" attribute in <depends> tag!"));
235 if (!dependsAttrs.hasAttribute(QLatin1StringView(
"value"))) {
236 printError(QStringLiteral(
"Missing \"value\" attribute in <depends> tag!"));
239 paramNode->addDependency(dependsAttrs.value(QLatin1StringView(
"enum")).
toString(), dependsAttrs.value(QLatin1StringView(
"value")).
toString());
241 printError(QStringLiteral(
"Unknown tag: ").append(mReader.name()));
250bool XmlParser::parseSetter(PropertyNode *parent)
252 const auto attrs = mReader.attributes();
253 auto setter =
new PropertyNode::Setter;
254 setter->name = attrs.value(QLatin1StringView(
"name")).toString();
255 setter->type = attrs.value(QLatin1StringView(
"type")).toString();
257 while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView(
"setter"))) {
259 if (mReader.isStartElement()) {
260 if (mReader.name() == QLatin1StringView(
"append")) {
261 setter->append = mReader.attributes().value(QLatin1StringView(
"name")).toString();
262 }
else if (mReader.name() == QLatin1StringView(
"remove")) {
263 setter->remove = mReader.attributes().value(QLatin1StringView(
"name")).toString();
268 parent->setSetter(setter);
273void XmlParser::printError(
const QString &error)
275 std::cerr <<
"Error:" << mReader.lineNumber() <<
":" << mReader.columnNumber() <<
": " << qPrintable(error) << std::endl;
char * toString(const EngineQuery &query)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
QString name(StandardAction id)