00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "gecode/kernel.hh"
00039 #include "gecode/serialization.hh"
00040
00041 #ifdef GECODE_HAS_QT
00042 #include "gecode/serialization/javascript.hh"
00043 #include "gecode/serialization.hh"
00044 #endif
00045
00046 namespace Gecode {
00047
00048 namespace {
00049
00050 void emitArg(std::ostream& os, Reflection::Arg* arg,
00051 Reflection::VarMap& vm) {
00052 using namespace std;
00053 if (arg->isInt()) {
00054 os << arg->toInt();
00055 return;
00056 }
00057 if (arg->isString()) {
00058 os << "\"" << arg->toString() << "\"";
00059 return;
00060 }
00061 if (arg->isVar()) {
00062 Reflection::VarSpec& s = vm.spec(arg->toVar());
00063 if (s.name().empty())
00064 os << "_v" << arg->toVar();
00065 else
00066 os << s.name();
00067 return;
00068 }
00069 if (arg->isIntArray()) {
00070 Reflection::IntArrayArg* a = arg->toIntArray();
00071 os << "[";
00072 for (int i=0; i<a->size(); i++) {
00073 os << (*a)[i];
00074 if (i<a->size()-1)
00075 os << ", ";
00076 }
00077 os << "]";
00078 return;
00079 }
00080 if (arg->isArray()) {
00081 Reflection::ArrayArg* a = arg->toArray();
00082 os << "[";
00083 for (int i=0; i<a->size(); i++) {
00084 emitArg(os, (*a)[i], vm);
00085 if (i<a->size()-1)
00086 os << ", ";
00087 }
00088 os << "]";
00089 return;
00090 }
00091 if (arg->isSharedReference()) {
00092 os << "_array" << arg->toSharedReference();
00093 return;
00094 }
00095 if (arg->isPair()) {
00096 os << "pair(";
00097 emitArg(os, arg->first(), vm);
00098 os << ", ";
00099 emitArg(os, arg->second(), vm);
00100 os << ")";
00101 return;
00102 }
00103 assert(!arg->isSharedObject());
00104 throw Exception("Serialization", "Specification not understood");
00105 }
00106
00107 void emitSharedObject(std::ostream& os, int soCount,
00108 Reflection::VarMap& vm,
00109 Reflection::Arg* arg0) {
00110 using namespace std;
00111 Reflection::Arg* arg = arg0->toSharedObject();
00112 os << "var _array" << soCount << " = ";
00113 emitArg(os, arg, vm);
00114 os << ";" << endl;
00115 }
00116
00117 }
00118
00119 void emitVarMap(std::ostream& os, int& varCount,
00120 Reflection::VarMapIter& vmi,
00121 Reflection::VarMap& vm) {
00122 using namespace std;
00123 for (; vmi(); ++vmi, ++varCount) {
00124 Reflection::VarSpec& vs = vmi.spec();
00125 os << "var ";
00126 if (!vs.name().empty()) {
00127 os << vs.name();
00128 } else {
00129 os << "_v" << varCount;
00130 }
00131 os << " = variable(\"" << vs.vti() << "\", ";
00132 if (!vs.name().empty()) {
00133 os << "\"" << vs.name() << "\", ";
00134 }
00135 emitArg(os, vs.dom(), vm);
00136 os << ");" << endl;
00137 }
00138 }
00139
00140 void emitJavaScript(Space* home, std::ostream& os) {
00141 using namespace std;
00142 Reflection::VarMap vm;
00143 home->getVars(vm, false);
00144 int rootSize = vm.size();
00145 Reflection::VarMapIter vmi(vm);
00146 int varCount = 0;
00147 int soCount = 0;
00148 emitVarMap(os,varCount,vmi,vm);
00149 for (Reflection::ActorSpecIter si(home, vm); si(); ++si) {
00150 Reflection::ActorSpec s = si.actor();
00151
00152 emitVarMap(os,varCount,vmi,vm);
00153
00154 int soBase = soCount;
00155 for (int i=0; i<s.noOfArgs(); i++) {
00156 if (s[i] && s[i]->isSharedObject())
00157 emitSharedObject(os, soBase++, vm, s[i]);
00158 }
00159
00160 os << "constraint(\"" << s.ati() << "\", ";
00161
00162 soBase = soCount;
00163 for (int i=0; i<s.noOfArgs(); i++) {
00164 if (s[i] == NULL)
00165 os << "[]";
00166 else if (s[i]->isSharedObject())
00167 os << "_array" << soBase++;
00168 else
00169 emitArg(os, s[i], vm);
00170 if (i<s.noOfArgs()-1)
00171 os << ", ";
00172 }
00173 os << ");" << endl;
00174 soCount = soBase;
00175 }
00176
00177 os << "[";
00178 bool first = true;
00179 for (int i=0; i<rootSize; i++) {
00180 if (first)
00181 first = false;
00182 else
00183 os << ", ";
00184 Support::Symbol name = vm.spec(i).name();
00185 if (name.empty())
00186 os << "_v" << i;
00187 else
00188 os << name;
00189 }
00190 os << "];" << endl;
00191 }
00192
00193 #ifdef GECODE_HAS_QT
00194
00195 namespace Serialization {
00196 Gecode::Reflection::Arg*
00197 GJSSpace::scriptValToArg(QScriptValue v) {
00198 if (v.isArray()) {
00199 bool isIntArray = true;
00200 int size = 0;
00201 QScriptValueIterator vi(v);
00202 while (vi.hasNext()) {
00203 vi.next();
00204 if (!vi.value().isNumber())
00205 isIntArray = false;
00206 size++;
00207 }
00208 if (isIntArray) {
00209 Gecode::Reflection::IntArrayArg* a =
00210 Gecode::Reflection::Arg::newIntArray(size);
00211 int count = 0;
00212 QScriptValueIterator vi(v);
00213 while (vi.hasNext()) {
00214 vi.next();
00215 (*a)[count++] = static_cast<int>(vi.value().toNumber());
00216 }
00217 return a;
00218 } else {
00219 Gecode::Reflection::ArrayArg* a =
00220 Gecode::Reflection::Arg::newArray(size);
00221 int count = 0;
00222 QScriptValueIterator vi(v);
00223 while (vi.hasNext()) {
00224 vi.next();
00225 Gecode::Reflection::Arg* ai = scriptValToArg(vi.value());
00226 (*a)[count++] = ai;
00227 }
00228 return a;
00229 }
00230 } else if (v.isNumber()) {
00231 return Gecode::Reflection::Arg::newInt(static_cast<int>(v.toNumber()));
00232 } else if (v.isBoolean()) {
00233 return Gecode::Reflection::Arg::newInt(v.toBoolean());
00234 } else if (v.isObject() && v.prototype().strictlyEquals(varProto)) {
00235 return Gecode::Reflection::Arg::newVar(static_cast<int>(v.property("no").toNumber()));
00236 } else if (v.isObject() && v.prototype().strictlyEquals(pairProto)) {
00237 Gecode::Reflection::Arg* a = scriptValToArg(v.property("a"));
00238 Gecode::Reflection::Arg* b = scriptValToArg(v.property("b"));
00239 return Gecode::Reflection::Arg::newPair(a,b);
00240 } else if (v.isString()) {
00241 QByteArray vba = v.toString().toLatin1();
00242 return Gecode::Reflection::Arg::newString(
00243 vba.data());
00244 } else {
00245 return NULL;
00246 }
00247 }
00248
00249 GJSSpace::GJSSpace(QScriptEngine* engine, Gecode::Space* s0)
00250 : varProto(engine->newObject()), pairProto(engine->newObject()),
00251 s(s0), d(s, vm) {
00252 s->getVars(vm, true);
00253 }
00254
00255 QScriptValue
00256 GJSSpace::variable(const QString& vti, QScriptValue args) {
00257 assert(args.isArray());
00258 QByteArray vtiba = vti.toLatin1();
00259 Support::Symbol vtiSymbol(vtiba.data(), true);
00260 int size = static_cast<int>(args.property("length").toNumber());
00261 if (size < 1 || size > 2) {
00262 throw Exception("Serialization", "Argument mismatch");
00263 }
00264 int newVar = vm.size();
00265 Gecode::Reflection::Arg* dom =
00266 scriptValToArg(args.property(size == 1 ? 0 : 1));
00267 Reflection::VarSpec vs(vtiSymbol, dom);
00268 if (size == 2) {
00269 assert(args.property(0).isString());
00270 QByteArray sba = args.property(0).toString().toLatin1();
00271 Support::Symbol nameSymbol(sba.data(), true);
00272 vs.name(nameSymbol);
00273 }
00274 d.var(vs);
00275 QScriptValue object = engine()->newObject();
00276 object.setPrototype(varProto);
00277 object.setProperty("no", QScriptValue(engine(), newVar));
00278 return object;
00279 }
00280
00281 void
00282 GJSSpace::constraint(const QString& name, QScriptValue args) {
00283 Gecode::Support::Symbol nameSymbol(name.toLatin1().data(), true);
00284 Gecode::Reflection::ActorSpec as(nameSymbol);
00285 assert(args.isArray());
00286 QScriptValueIterator argsI(args);
00287 while (argsI.hasNext()) {
00288 argsI.next();
00289 as << scriptValToArg(argsI.value());
00290 }
00291 d.post(as);
00292 }
00293
00294 QScriptValue
00295 GJSSpace::pair(QScriptValue a, QScriptValue b) {
00296 QScriptValue object = engine()->newObject();
00297 object.setPrototype(pairProto);
00298 object.setProperty("a", a);
00299 object.setProperty("b", b);
00300 return object;
00301 }
00302
00303 }
00304
00305 void fromJavaScript(Space* space, const std::string& model) {
00306 QScriptEngine engine;
00307 Serialization::GJSSpace* gjsspace = new Serialization::GJSSpace(&engine, space);
00308 QScriptValue spaceValue = engine.newQObject(gjsspace);
00309 engine.globalObject().setProperty("Space", spaceValue);
00310
00311 QString prelude =
00312 "function constraint() {"
00313 " var name = arguments[0];"
00314 " var args = new Array;"
00315 " for (var i=1; i<arguments.length; i++) {"
00316 " args[i-1] = arguments[i];"
00317 " }"
00318 " Space.constraint(name, args);"
00319 "}"
00320 "function variable() {"
00321 " var vti = arguments[0];"
00322 " var args = new Array;"
00323 " for (var i=1; i<arguments.length; i++) {"
00324 " args[i-1] = arguments[i];"
00325 " }"
00326 " return Space.variable(vti, args);"
00327 "}"
00328 "function pair(a, b) { return Space.pair(a,b); }\n";
00329
00330 QString program = prelude + QString(model.c_str());
00331 QScriptValue ret = engine.evaluate(program,"",0);
00332 if (engine.hasUncaughtException()) {
00333 throw Exception("Serialization", "Error in JavaScript execution");
00334
00335
00336
00337 }
00338 }
00339
00340 #endif
00341 }
00342
00343