22 #include <QMetaObject>
23 #include <QMetaMethod>
24 #include <QScriptEngine>
25 #include <QScriptValueIterator>
29 using namespace Kross;
34 class EcmaScript::Private
38 QScriptEngine* m_engine;
42 explicit Private(
EcmaScript* script) : m_script(script), m_engine(0) {}
43 ~Private() {
delete m_engine; }
46 if( m_script->action()->hadError() )
47 m_script->action()->clearError();
50 m_engine =
new QScriptEngine();
51 m_engine->installTranslatorFunctions();
55 m_engine->importExtension(
"kross");
56 if( m_engine->hasUncaughtException() ) {
64 QScriptValue global = m_engine->globalObject();
65 m_kross = global.property(
"Kross");
66 Q_ASSERT( m_kross.isQObject() );
67 Q_ASSERT( ! m_engine->hasUncaughtException() );
72 m_self = m_engine->newQObject( m_script->action() );
73 global.setProperty(
"self", m_self, QScriptValue::ReadOnly|QScriptValue::Undeletable);
78 for(; it !=
end; ++it)
79 global.setProperty(it.key(), m_engine->newQObject( it.value() ) );
85 for(; it !=
end; ++it) {
86 copyEnumsToProperties( it.value() );
87 global.setProperty(it.key(), m_engine->newQObject( it.value() ) );
91 return ! m_engine->hasUncaughtException();
94 void copyEnumsToProperties(
QObject*
object) {
95 const QMetaObject* meta =
object->metaObject();
96 for (
int i = 0; i < meta->enumeratorCount(); ++i) {
97 QMetaEnum metaenum = meta->enumerator(i);
98 for (
int j = 0; j < metaenum.keyCount(); ++j) {
99 object->setProperty(metaenum.key(j), metaenum.value(j));
104 void handleException() {
105 Q_ASSERT( m_engine );
106 Q_ASSERT( m_engine->hasUncaughtException() );
107 const QString err = m_engine->uncaughtException().toString();
108 const int linenr = m_engine->uncaughtExceptionLineNumber();
109 const QString trace = m_engine->uncaughtExceptionBacktrace().join(
"\n");
110 krossdebug(
QString(
"%1, line:%2, backtrace:\n%3").arg(err).arg(linenr).arg(trace) );
111 m_script->action()->setError(err, trace, linenr);
112 m_engine->clearExceptions();
116 Q_ASSERT( m_engine );
117 Q_ASSERT( ! m_engine->hasUncaughtException() );
118 QScriptValue global = m_engine->globalObject();
119 QScriptValue value = m_engine->newQObject(
object);
120 global.setProperty(
name.isEmpty() ?
object->objectName() :
name, value);
124 Q_ASSERT( m_engine );
125 Q_ASSERT( ! m_engine->hasUncaughtException() );
127 QScriptValue global = m_engine->globalObject();
128 QHashIterator< QString, ChildrenInterface::Options > it( children->
objectOptions() );
129 while(it.hasNext()) {
135 QScriptValue obj = m_engine->globalObject().property(it.key());
136 if( ! obj.isQObject() )
138 const QMetaObject* mo = sender->metaObject();
139 const int count = mo->methodCount();
140 for(
int i = 0; i < count; ++i) {
141 QMetaMethod mm = mo->method(i);
142 const QString signature = mm.signature();
143 const QString name = signature.left(signature.indexOf(
'('));
144 if( mm.methodType() == QMetaMethod::Signal ) {
145 QScriptValue func = global.property(name);
146 if( ! func.isFunction() ) {
150 krossdebug(
QString(
"EcmaScript::connectFunctions Connecting with %1.%2").arg(it.key()).arg(name) );
151 eval +=
QString(
"try { %1.%2.connect(%3); } catch(e) { print(e); }\n").arg(it.key()).arg(name).arg(name);
156 Q_ASSERT( ! m_engine->hasUncaughtException() );
157 if( ! eval.isNull() ) {
158 m_engine->evaluate(eval);
159 Q_ASSERT( ! m_engine->hasUncaughtException() );
181 d->handleException();
186 if( scriptCode.startsWith(QLatin1String(
"#!")) )
187 scriptCode.remove(0, scriptCode.indexOf(
'\n'));
193 Q_ASSERT( d->m_engine );
195 if( d->m_engine->hasUncaughtException() ) {
196 d->m_engine->clearExceptions();
199 d->m_engine->evaluate( scriptCode, fileName );
201 if( d->m_engine->hasUncaughtException() ) {
202 d->handleException();
207 d->connectFunctions(
action() );
212 if( ! d->m_engine && ! d->init() ) {
213 d->handleException();
217 QScriptValueIterator it( d->m_engine->globalObject() );
218 while( it.hasNext() ) {
220 if( it.value().isFunction() ) {
229 if( ! d->m_engine && ! d->init() ) {
230 d->handleException();
234 QScriptValue obj = d->m_engine->globalObject();
235 QScriptValue
function = obj.property(name);
236 if( !
function.isFunction() ) {
243 QScriptValueList arguments;
245 arguments << d->m_engine->toScriptValue(v);
246 QScriptValue result =
function.call(obj, arguments);
247 if( d->m_engine->hasUncaughtException() ) {
248 d->handleException();
251 return result.toVariant();
256 if( ! d->m_engine && ! d->init() ) {
257 d->handleException();
261 QScriptValue result = d->m_engine->evaluate(code);
262 if( d->m_engine->hasUncaughtException() ) {
263 d->handleException();
266 return result.toVariant();
274 #include "script.moc"
virtual QStringList functionNames()
virtual void execute()
Executes the script.
Base class for interpreter dependent functionality each script provides.
QHash< QString, Options > objectOptions() const
virtual QVariant callFunction(const QString &name, const QVariantList &args=QVariantList())
Execute a function.
const char * name(StandardAction id)
static void init(Action *th, const QString &name, int options=0)
QHash< QString, QObject * > objects() const
Interface for managing Object collections.
Base class for interpreter implementations.
void krosswarning(const QString &s)
Warning function.
virtual ~EcmaScript()
Destructor.
virtual QVariant evaluate(const QByteArray &code)
Evaluate some scripting code.
QObject * object(const QString &name) const
auto connect signals with scripting functions.
static Manager & self()
Return the Manager instance.
void setError(const QString &errormessage, const QString &tracemessage=QString(), long lineno=-1)
Set the error message.
The Action class is an abstract container to deal with scripts like a single standalone script file...
The EcmaScript class implements a Kross::Script to handle a single script.
void krossdebug(const QString &s)
Debugging function.
EcmaScript(Kross::Interpreter *interpreter, Kross::Action *action)
Constructor.