3 Copyright (c) 2012 Jakob Leben & Tim Blechmann
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "sc_introspection.hpp"
23 #include "../common/SC_DirUtils.h"
24 #include "../widgets/main_window.hpp"
26 #include "yaml-cpp/node.h"
27 #include "yaml-cpp/parser.h"
35 namespace ScLanguage
{
37 Introspection::Introspection()
42 Introspection::Introspection( QString
const & yamlString
)
45 bool parsingSuccessful
= parse(yamlString
);
46 if (!parsingSuccessful
)
47 throw std::runtime_error("Introspection parse error");
50 void Introspection::initPaths()
52 char userExtensionDir
[PATH_MAX
];
53 sc_GetUserExtensionDirectory(userExtensionDir
, PATH_MAX
);
54 mUserExtensionDir
= QString(userExtensionDir
) + QString("/");
56 char systemExtensionDir
[PATH_MAX
];
57 sc_GetSystemExtensionDirectory(systemExtensionDir
, PATH_MAX
);
58 mSystemExtensionDir
= QString(systemExtensionDir
) + QString("/");
61 Introspection::~Introspection()
66 bool Introspection::parse(const QString
& yamlString
)
72 //qDebug("parsing introspection...");
74 std::stringstream stream
;
75 stream
<< yamlString
.toStdString();
76 YAML::Parser
parser(stream
);
79 if(!parser
.GetNextDocument(doc
)) {
80 MainWindow::instance()->showStatusMessage("no YAML document");
84 assert (doc
.Type() == YAML::NodeType::Sequence
);
85 for (YAML::Iterator it
= doc
.begin(); it
!= doc
.end(); ++it
)
87 assert(it
->Type() == YAML::NodeType::Sequence
);
88 QString name
= (*it
)[0].to
<std::string
>().c_str();
89 Class
*klass
= new Class
;
91 mClassMap
.insert(make_pair(klass
->name
, QSharedPointer
<Class
>(klass
)));
94 for (YAML::Iterator docIterator
= doc
.begin(); docIterator
!= doc
.end(); ++docIterator
)
96 const YAML::Node
& node
= *docIterator
;
97 QString name
= node
[0].to
<std::string
>().c_str();
98 ClassMap::iterator it
= mClassMap
.find(name
);
99 assert(it
!= mClassMap
.end());
100 Class
*klass
= it
->second
.data();
102 //qDebug() << klass->name;
104 ClassMap::iterator class_it
;
106 QString metaClassName
= node
[1].to
<std::string
>().c_str();
107 class_it
= mClassMap
.find(metaClassName
);
108 assert(class_it
!= mClassMap
.end());
109 klass
->metaClass
= class_it
->second
.data();
111 if (node
[2].Read(YAML::Null
))
112 klass
->superClass
= 0;
114 QString superClassName
= node
[2].to
<std::string
>().c_str();
115 class_it
= mClassMap
.find(superClassName
);
116 assert(class_it
!= mClassMap
.end());
117 klass
->superClass
= class_it
->second
.data();
120 klass
->definition
.path
= node
[3].to
<std::string
>().c_str();
121 klass
->definition
.position
= node
[4].to
<int>();
123 const YAML::Node
&methodSeq
= node
[5];
124 if (methodSeq
.Type() != YAML::NodeType::Sequence
)
127 //assert(methodSeq.Type() == YAML::NodeType::Sequence);
128 for (YAML::Iterator mit
= methodSeq
.begin(); mit
!= methodSeq
.end(); ++mit
)
130 const YAML::Node
&methodNode
= *mit
;
131 assert(methodNode
.Type() == YAML::NodeType::Sequence
);
132 assert(methodNode
.size() >= 2);
134 assert(methodNode
[0].Type() == YAML::NodeType::Scalar
);
135 assert(methodNode
[1].Type() == YAML::NodeType::Scalar
);
137 Method
*method
= new Method
;
138 method
->ownerClass
= klass
;
139 method
->name
= methodNode
[1].to
<std::string
>().c_str();
140 method
->definition
.path
= methodNode
[2].to
<std::string
>().c_str();
141 method
->definition
.position
= methodNode
[3].to
<int>();
143 //qDebug() << "--" << method->name;
145 const YAML::Node
&argNode
= methodNode
[4];
146 assert(argNode
.Type() == YAML::NodeType::Sequence
);
147 YAML::Iterator arg
= argNode
.begin();
148 while (arg
!= argNode
.end())
153 assert(arg
->Type() == YAML::NodeType::Scalar
);
154 argument
.name
= arg
->to
<std::string
>().c_str();
156 //qDebug() << "---# " << argument.name;
158 // get arg default value
160 if (arg
== argNode
.end())
162 if(!arg
->Read(YAML::Null
)) {
163 assert(arg
->Type() == YAML::NodeType::Scalar
);
164 argument
.defaultValue
= arg
->to
<std::string
>().c_str();
167 method
->arguments
.append(argument
);
173 klass
->methods
.append(method
);
174 mMethodMap
.insert(make_pair(method
->name
, QSharedPointer
<Method
>(method
)));
178 inferClassLibraryPath();
180 //qDebug("done parsing introspection.");
184 QString
Introspection::compactLibraryPath(QString
const & path
) const
186 if (path
.startsWith(mClassLibraryPath
))
187 return path
.mid(mClassLibraryPath
.length());
189 if (path
.startsWith(mUserExtensionDir
))
190 return QString("Extensions/") + path
.mid(mUserExtensionDir
.length());
192 if (path
.startsWith(mSystemExtensionDir
))
193 return QString("Extensions/") + path
.mid(mSystemExtensionDir
.length());
198 void Introspection::inferClassLibraryPath()
200 ClassMap::const_iterator object_class_it
= mClassMap
.find("Object");
201 assert(object_class_it
!= mClassMap
.end());
202 Class
*objectClass
= object_class_it
->second
.data();
204 QString classLibPath
= objectClass
->definition
.path
;
205 int len
= classLibPath
.lastIndexOf("Common");
207 classLibPath
.truncate(len
);
209 classLibPath
.clear();
211 mClassLibraryPath
= classLibPath
;
214 bool Introspection::ensureIntrospectionData() const
216 if (!introspectionAvailable()) {
217 MainWindow::instance()->showStatusMessage("Sclang Introspection not available, yet!");
223 const Class
* Introspection::findClass(const QString
&className
) const
225 if (!ensureIntrospectionData())
228 ClassMap::const_iterator klass_it
= mClassMap
.find(className
);
229 if (klass_it
== mClassMap
.end()) {
230 MainWindow::instance()->showStatusMessage("Class not defined!");
233 return klass_it
->second
.data();
236 std::vector
<const Class
*> Introspection::findClassPartial(const QString
& partialClassName
) const
238 std::vector
<const Class
*> matchingClasses
;
239 if (!ensureIntrospectionData())
240 return matchingClasses
;
242 typedef ClassMap::const_iterator class_iterator
;
244 for (class_iterator it
= mClassMap
.begin(); it
!= mClassMap
.end(); ++it
) {
245 QString
const & key
= it
->first
;
246 if (key
.contains(partialClassName
, Qt::CaseInsensitive
)) {
247 if (!key
.startsWith("Meta_"))
248 matchingClasses
.push_back(it
->second
.data());
252 return matchingClasses
;
256 std::vector
<const Method
*> Introspection::findMethodPartial(const QString
& partialMethodName
) const
258 std::vector
<const Method
*> matchingMethods
;
259 if (!ensureIntrospectionData())
260 return matchingMethods
;
262 typedef MethodMap::const_iterator class_iterator
;
264 for (class_iterator it
= mMethodMap
.begin(); it
!= mMethodMap
.end(); ++it
) {
265 QString
const & key
= it
->first
;
266 if (key
.contains(partialMethodName
, Qt::CaseInsensitive
))
267 matchingMethods
.push_back(it
->second
.data());
270 return matchingMethods
;
273 Introspection::ClassMethodMap
Introspection::constructMethodMap(const Class
* klass
) const
275 ClassMethodMap methodMap
;
279 foreach (Method
*method
, klass
->metaClass
->methods
) {
280 QList
<Method
*> & list
= methodMap
[method
->definition
.path
];
284 foreach (Method
*method
, klass
->methods
) {
285 QList
<Method
*> & list
= methodMap
[method
->definition
.path
];
291 QString
Method::signature( SignatureStyle style
) const
293 QString sig
= ownerClass
->name
.get();
294 if (sig
.startsWith("Meta_")) {
301 sig
.append(name
.get());
303 if (style
== SignatureWithoutArguments
)
306 int argc
= arguments
.count();
309 for( int i
= 0; i
< argc
; ++i
)
311 const Argument
& arg
= arguments
[i
];
314 sig
.append(arg
.name
);
315 if (style
== SignatureWithArgumentsAndDefaultValues
&& !arg
.defaultValue
.get().isEmpty()) {
317 sig
.append(arg
.defaultValue
);
322 else if (name
.get().endsWith('_'))
323 sig
.append(" (value)");
328 } // namespace ScLanguage