1 #include "function.h"
2 #include <QMetaMethod>
3 #include <QStringList>
4
5 namespace NeovimQt {
6
7 typedef QPair<QString,QString> StringPair;
8
9 /**
10 * \class NeovimQt::Function
11 *
12 * \brief Representation of a Neovim API function signature
13 */
14
15 /**
16 * Construct invalid function
17 */
Function()18 Function::Function()
19 :can_fail(false), m_valid(false)
20 {
21 }
22
23 /**
24 * Construct new function with the given return type, name, parameters and error
25 */
Function(const QString & ret,const QString & name,QList<QPair<QString,QString>> params,bool can_fail)26 Function::Function(const QString& ret, const QString& name, QList<QPair<QString,QString> > params, bool can_fail)
27 :m_valid(true)
28 {
29 this->return_type = ret;
30 this->name = name;
31 this->parameters = params;
32 this->can_fail = can_fail;
33 }
34
35 /**
36 * Construct new function with the given return type, name, parameters and error
37 */
Function(const QString & ret,const QString & name,QList<QString> paramTypes,bool can_fail)38 Function::Function(const QString& ret, const QString& name, QList<QString> paramTypes, bool can_fail)
39 :m_valid(true)
40 {
41 this->return_type = ret;
42 this->name = name;
43 foreach (QString type, paramTypes) {
44 this->parameters .append(QPair<QString,QString>(type, ""));
45 }
46 this->can_fail = can_fail;
47 }
48
49 /**
50 * Returns true if this function has all the necessary attributes
51 */
isValid() const52 bool Function::isValid() const
53 {
54 return m_valid;
55 }
56
57 /**
58 * Two functions are considered identical if their names
59 * argument and return types, and error status are identical
60 */
operator ==(const Function & other)61 bool Function::operator==(const Function& other)
62 {
63 if ( this->name != other.name ) {
64 return false;
65 }
66
67 if ( this->return_type != other.return_type ) {
68 return false;
69 }
70 if (this->parameters.size() != other.parameters.size()) {
71 return false;
72 }
73 for (int i=0; i<this->parameters.size(); i++) {
74 if ( this->parameters.at(i).first != other.parameters.at(i).first ) {
75 return false;
76 }
77 }
78 return true;
79 }
80
fromVariant(const QVariant & fun)81 Function Function::fromVariant(const QVariant& fun)
82 {
83 Function f;
84 if (!fun.canConvert<QVariantMap>()) {
85 qDebug() << "Found unexpected data type when unpacking function" << fun;
86 return f;
87 }
88
89 const QVariantMap& m = fun.toMap();
90 QMapIterator<QString,QVariant> it(m);
91 while(it.hasNext()) {
92 it.next();
93
94 if ( it.key() == "return_type" ) {
95 if (!it.value().canConvert<QByteArray>()) {
96 qDebug() << "Found unexpected data type when unpacking function" << fun;
97 return f;
98 }
99 f.return_type = QString::fromUtf8(it.value().toByteArray());
100 } else if ( it.key() == "name" ) {
101 if (!it.value().canConvert<QByteArray>()) {
102 qDebug() << "Found unexpected data type when unpacking function" << fun;
103 return f;
104 }
105 f.name = QString::fromUtf8(it.value().toByteArray());
106 } else if ( it.key() == "can_fail" ) {
107 if (!it.value().canConvert<bool>()) {
108 qDebug() << "Found unexpected data type when unpacking function" << fun;
109 return f;
110 }
111 f.can_fail = it.value().toBool();
112 } else if ( it.key() == "parameters" ) {
113 if (!it.value().canConvert<QVariantList>()) {
114 qDebug() << "Found unexpected data type when unpacking function" << fun;
115 return f;
116 }
117 f.parameters = parseParameters(it.value().toList());
118 } else if ( it.key() == "id" ) {
119 // Deprecated
120 } else if ( it.key() == "receives_channel_id" ) {
121 // Internal
122 } else if ( it.key() == "impl_name" ) {
123 // Internal
124 } else if ( it.key() == "method" ) {
125 // Internal
126 } else if ( it.key() == "noeval" ) {
127 // API only function
128 } else if ( it.key() == "deferred" || it.key() == "async" ) {
129 // Internal, "deferred" renamed "async" in neovim/ccdeb91
130 } else if ( it.key() == "deprecated_since" || it.key() == "since" ) {
131 // Creation/Deprecation
132 } else {
133 qDebug() << "Unsupported function attribute"<< it.key() << it.value();
134 }
135 }
136
137 f.m_valid = true;
138 return f;
139 }
140
141 /**
142 * Retrieve parameter types from a list of function parameters in the metadata
143 * object. Basically retrieves the even numbered elements of the array (types)
144 * i.e. [Type0 name0 Type1 name1 ... ] -> [Type0 Type1 ...]
145 *
146 */
parseParameters(const QVariantList & obj)147 QList<QPair<QString,QString> > Function::parseParameters(const QVariantList& obj)
148 {
149 QList<QPair<QString,QString> > fail;
150 QList<QPair<QString,QString> > res;
151 foreach(const QVariant& val, obj) {
152
153 const QVariantList& params = val.toList();
154 if ( params.size() % 2 != 0 ) {
155 return fail;
156 }
157
158 for (int j=0; j<params.size(); j+=2) {
159 QByteArray type, name;
160 if (!params.at(j).canConvert<QByteArray>() ||
161 !params.at(j+1).canConvert<QByteArray>()) {
162 return fail;
163 }
164 QPair<QString,QString> arg(
165 QString::fromUtf8(params.at(j).toByteArray()),
166 QString::fromUtf8(params.at(j+1).toByteArray()));
167 res.append(arg);
168 }
169 }
170 return res;
171 }
172
signature() const173 QString Function::signature() const
174 {
175 QStringList sigparams;
176 foreach(const StringPair p, parameters) {
177 sigparams.append(QString("%1 %2").arg(p.first).arg(p.second));
178 }
179
180 QString notes;
181 if (can_fail) {
182 notes += " !fail";
183 }
184 return QString("%1 %2(%3)%4").arg(return_type).arg(name).arg(sigparams.join(", ")).arg(notes);
185 }
186
187 } // Namespace
188
189