gecode » serialization
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-02-14 15:40:16 +0100 (Thu, 14 Feb 2008) $ by $Author: tack $ 00011 * $Revision: 6163 $ 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 return Gecode::Reflection::Arg::newString( 00242 v.toString().toStdString().c_str()); 00243 } else { 00244 return NULL; 00245 } 00246 } 00247 00248 GJSSpace::GJSSpace(QScriptEngine* engine, Gecode::Space* s0) 00249 : varProto(engine->newObject()), pairProto(engine->newObject()), 00250 s(s0), d(s, vm) { 00251 s->getVars(vm, true); 00252 } 00253 00254 QScriptValue 00255 GJSSpace::variable(const QString& vti, QScriptValue args) { 00256 assert(args.isArray()); 00257 Support::Symbol vtiSymbol(vti.toStdString().c_str(), true); 00258 int size = static_cast<int>(args.property("length").toNumber()); 00259 if (size < 1 || size > 2) { 00260 throw Exception("Serialization", "Argument mismatch"); 00261 } 00262 int newVar = vm.size(); 00263 Gecode::Reflection::Arg* dom = 00264 scriptValToArg(args.property(size == 1 ? "0" : "1")); 00265 Reflection::VarSpec vs(vtiSymbol, dom); 00266 if (size == 2) { 00267 Support::Symbol nameSymbol( 00268 args.property("0").toString().toStdString().c_str(), true); 00269 vs.name(nameSymbol); 00270 } 00271 d.var(vs); 00272 QScriptValue object = engine()->newObject(); 00273 object.setPrototype(varProto); 00274 object.setProperty("no", QScriptValue(engine(), newVar)); 00275 return object; 00276 } 00277 00278 void 00279 GJSSpace::constraint(const QString& name, QScriptValue args) { 00280 Gecode::Support::Symbol nameSymbol(name.toStdString().c_str(), true); 00281 Gecode::Reflection::ActorSpec as(nameSymbol); 00282 assert(args.isArray()); 00283 QScriptValueIterator argsI(args); 00284 while (argsI.hasNext()) { 00285 argsI.next(); 00286 as << scriptValToArg(argsI.value()); 00287 } 00288 d.post(as); 00289 } 00290 00291 QScriptValue 00292 GJSSpace::pair(QScriptValue a, QScriptValue b) { 00293 QScriptValue object = engine()->newObject(); 00294 object.setPrototype(pairProto); 00295 object.setProperty("a", a); 00296 object.setProperty("b", b); 00297 return object; 00298 } 00299 00300 } 00301 00302 void fromJavaScript(Space* space, const std::string& model) { 00303 QScriptEngine engine; 00304 Serialization::GJSSpace gjsspace(&engine, space); 00305 QScriptValue spaceValue = engine.newQObject(&gjsspace); 00306 engine.globalObject().setProperty("Space", spaceValue); 00307 00308 QString prelude = 00309 "function constraint() {" 00310 " var name = arguments[0];" 00311 " var args = new Array;" 00312 " for (var i=1; i<arguments.length; i++) {" 00313 " args[i-1] = arguments[i];" 00314 " }" 00315 " Space.constraint(name, args);" 00316 "}" 00317 "function variable() {" 00318 " var vti = arguments[0];" 00319 " var args = new Array;" 00320 " for (var i=1; i<arguments.length; i++) {" 00321 " args[i-1] = arguments[i];" 00322 " }" 00323 " return Space.variable(vti, args);" 00324 "}" 00325 "function pair(a, b) { return Space.pair(a,b); }\n"; 00326 00327 QString program = prelude + QString(model.c_str()); 00328 QScriptValue ret = engine.evaluate(program,"",0); 00329 if (engine.hasUncaughtException()) { 00330 throw Exception("Serialization", "Error in JavaScript execution"); 00331 // std::cerr << "Error in script execution: " 00332 // << ret.toString().toStdString() << " at line " 00333 // << engine.uncaughtExceptionLineNumber() << std::endl; 00334 } 00335 } 00336 00337 #endif 00338 } 00339 00340 // STATISTICS: serialization-any