Generated on Mon Aug 25 11:35:32 2008 for Gecode by doxygen 1.5.6

javascript.cc

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Guido Tack <tack@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Guido Tack, 2007
00008  *
00009  *  Last modified:
00010  *     $Date: 2008-08-22 15:36:14 +0200 (Fri, 22 Aug 2008) $ by $Author: tack $
00011  *     $Revision: 7683 $
00012  *
00013  *  This file is part of Gecode, the generic constraint
00014  *  development environment:
00015  *     http://www.gecode.org
00016  *
00017  *  Permission is hereby granted, free of charge, to any person obtaining
00018  *  a copy of this software and associated documentation files (the
00019  *  "Software"), to deal in the Software without restriction, including
00020  *  without limitation the rights to use, copy, modify, merge, publish,
00021  *  distribute, sublicense, and/or sell copies of the Software, and to
00022  *  permit persons to whom the Software is furnished to do so, subject to
00023  *  the following conditions:
00024  *
00025  *  The above copyright notice and this permission notice shall be
00026  *  included in all copies or substantial portions of the Software.
00027  *
00028  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00029  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00030  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00031  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00032  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00033  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00034  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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       // std::cerr << "Error in script execution: "
00335       //           << ret.toString().toStdString() << " at line "
00336       //           << engine.uncaughtExceptionLineNumber() << std::endl;
00337     }
00338   }
00339 
00340 #endif  
00341 }
00342 
00343 // STATISTICS: serialization-any