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 #include "../include/PCMSqVM.h"
00030
00031 #include "../include/PCMScriptRegistration.h"
00032
00033
00034
00035
00036
00037 #include <stdarg.h>
00038
00039 namespace ParCompMark
00040 {
00041
00042
00043
00044
00045
00046 const std::string SqVM::NOMAINMETHOD = "null";
00047 const u32 SqVM::mStringBufferSize = 32768;
00048
00049
00050
00051
00052
00053 SqVM::Pointer SqVM::mCurrentVM;
00054 Mutex SqVM::mCurrentVMLock;
00055 SqVM::ScriptOutput SqVM::mScriptOutput = SqVM::LOG;
00056 char SqVM::mStringBuffer[32768] = "";
00057
00058
00059
00060
00061
00062 SqVM::SqVM(const std::string & name):
00063
00064 Name(name
00065 ),
00066
00067 mThis(this
00068 , false
00069 )
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 {
00081
00082
00083 mSquirrelVMSys = 0;
00084
00085 mScripts = new Container < SqVM::Script, Mutex >;
00086
00087 mError = false;
00088 mInitialized = false;
00089
00090 Logger::getInstance()->log(Logger::NOTICE, "Squirrel virtual machine `" + mName + "\' has been created.");
00091 }
00092
00093
00094
00095 SqVM::~SqVM()
00096 {
00097 if(mInitialized)
00098 finalize();
00099
00100 Logger::getInstance()->log(Logger::NOTICE, "Squirrel virtual machine `" + mName + "\' has been destroyed.");
00101 }
00102
00103
00104
00105
00106
00107
00108
00109 void SqVM::printFunction(::HSQUIRRELVM sqVM, const SQChar * s, ...)
00110 {
00111 va_list arglist;
00112
00113 va_start(arglist, s);
00114 #ifdef SQUNICODE
00115 vwsprintf(mStringBuffer, s, arglist);
00116 #else
00117 vsprintf(mStringBuffer, s, arglist);
00118 #endif
00119 va_end(arglist);
00120
00121 if(mCurrentVM->mError || strcasestr(mStringBuffer, " error "))
00122 {
00123 switch (mScriptOutput)
00124 {
00125 case SqVM::LOG:
00126 Logger::getInstance()->logMultiLine(Logger::ERROR,
00127 "Squirrel error on VM(" + mCurrentVM->getName() + ") : " +
00128 mStringBuffer);
00129 break;
00130 case SqVM::STD:
00131 std::cerr << mStringBuffer;
00132 break;
00133 }
00134
00135
00136 mCurrentVM->mError = true;
00137 } else
00138 switch (mScriptOutput)
00139 {
00140 case SqVM::LOG:
00141 Logger::getInstance()->logMultiLine(Logger::NOTICE,
00142 "Squirrel message on VM(" + mCurrentVM->getName() + ") : " +
00143 mStringBuffer);
00144 break;
00145 case SqVM::STD:
00146 std::cout << mStringBuffer;
00147 break;
00148 }
00149 }
00150
00151
00152
00153
00154
00155
00156
00157 std::string SqVM::runScriptFromFile(const std::string & filename, const std::string & mainMethod,
00158 const std::list < std::string > ¶meters, const bool & hasReturn)
00159 {
00160 activate();
00161
00162
00163 SqVM::Script::Pointer script = findOrAddScript(filename, false, mainMethod, hasReturn);
00164
00165
00166 setParameters(script, parameters);
00167
00168
00169 compileAndExecuteScript(script);
00170
00171
00172 std::string returnValue = script->returnValue;
00173
00174
00175 script.unlock();
00176
00177 deactivate();
00178
00179 return returnValue;
00180 }
00181
00182
00183
00184 std::string SqVM::runScriptFromString(const std::string & scriptString, const std::string & scriptName,
00185 const std::string & mainMethod,
00186 const std::list < std::string > ¶meters,
00187 const bool & hasReturn)
00188 {
00189 SqVM::Script::Pointer script;
00190
00191 try
00192 {
00193 activate();
00194
00195
00196 if(scriptName.size())
00197 script = findOrAddScript(scriptName, true, mainMethod, hasReturn);
00198
00199
00200 else
00201 script = createScript("", true, mainMethod, hasReturn);
00202
00203
00204 script->scriptString = scriptString;
00205
00206
00207 setParameters(script, parameters);
00208
00209
00210 compileAndExecuteScript(script);
00211
00212
00213 std::string returnValue = script->returnValue;
00214
00215
00216 script.unlock();
00217
00218 deactivate();
00219
00220 return returnValue;
00221 }
00222 catch(const Exception & e)
00223 {
00224
00225 if(script.getLocked())
00226 script.unlock();
00227
00228 deactivate();
00229
00230
00231 throw Exception(e);
00232 }
00233
00234 return "";
00235 }
00236
00237
00238
00239 std::string SqVM::runScriptByName(const std::string & scriptName,
00240 const std::list < std::string > ¶meters)
00241 {
00242 activate();
00243
00244 SqVM::Script::Pointer script = findScript(scriptName);
00245
00246
00247 compileAndExecuteScript(script);
00248
00249
00250 std::string returnValue = script->returnValue;
00251
00252
00253 script.unlock();
00254
00255 deactivate();
00256
00257 return returnValue;
00258 }
00259
00260
00261
00262 void SqVM::finalize()
00263 {
00264
00265 Assert(mInitialized, INVALID_OPERATION_ERROR, "SqVM::finalize()");
00266
00267 activate();
00268
00269
00270 SquirrelVM::Shutdown();
00271 delete mSquirrelVMSys;
00272
00273 mSquirrelVMSys = 0;
00274
00275 deactivate();
00276
00277 mInitialized = false;
00278
00279 Logger::getInstance()->log(Logger::DEBUG, "Squirrel virtual machine `" + mName + "\' has been finalized.");
00280 }
00281
00282
00283
00284 void SqVM::activate()
00285 {
00286
00287 mCurrentVMLock.lock();
00288 mCurrentVM = mThis;
00289
00290
00291
00292
00293 if(!mInitialized)
00294 initialize();
00295
00296
00297 if(mSquirrelVMSys)
00298 SquirrelVM::SetVMSys(*mSquirrelVMSys);
00299 }
00300
00301
00302
00303 void SqVM::deactivate()
00304 {
00305
00306
00307
00308
00309 mCurrentVM = 0;
00310
00311 mCurrentVMLock.unlock();
00312 }
00313
00314
00315
00316 void SqVM::initialize()
00317 {
00318 Assert(!mInitialized, INVALID_OPERATION_ERROR, "SqVM::initialize()");
00319
00320
00321
00322 SquirrelVM::Init();
00323 mSquirrelVMSys = new SquirrelVMSys();
00324 SquirrelVM::GetVMSys(*mSquirrelVMSys);
00325
00326
00327
00328 sq_setprintfunc(mSquirrelVMSys->_VM, SqVM::printFunction);
00329
00330 mInitialized = true;
00331
00332
00333 squirrelClassBindings();
00334
00335 Logger::getInstance()->log(Logger::DEBUG, "Squirrel virtual machine `" + mName + "\' has been initialized.");
00336 }
00337
00338
00339
00340 SqVM::Script::Pointer SqVM::createScript(const std::string & scriptName, const bool & dynamic,
00341 const std::string & mainMethod, const bool & hasReturn)
00342 {
00343 SqVM::Script::Pointer script(new SqVM::Script());
00344 script->compiled = false;
00345 script->name = scriptName;
00346 script->dynamic = dynamic;
00347 script->mainMethod = mainMethod;
00348 script->scriptString = "";
00349 script->hasReturn = hasReturn;
00350 script.lock();
00351
00352 return script;
00353 }
00354
00355
00356
00357 SqVM::Script::Pointer SqVM::findScript(const std::string & scriptName)
00358 {
00359 SqVM::Script::Pointer script;
00360
00361
00362 mScripts.lock();
00363
00364 if(!mScripts->has(scriptName))
00365 {
00366 mScripts.unlock();
00367 deactivate();
00368 Except(INVALID_NAME_ERROR, "SqVM::findScript()", "The script `" + scriptName + "\' is not found.");
00369 }
00370
00371 script = mScripts->get(scriptName);
00372 script.lock();
00373 mScripts.unlock();
00374
00375 return script;
00376 }
00377
00378
00379
00380 SqVM::Script::Pointer SqVM::findOrAddScript(const std::string & scriptName, const bool & dynamic,
00381 const std::string & mainMethod, const bool & hasReturn)
00382 {
00383 SqVM::Script::Pointer script;
00384
00385
00386 mScripts.lock();
00387 if(mScripts->has(scriptName))
00388 {
00389
00390
00391 script = mScripts->get(scriptName);
00392 script.lock();
00393
00394
00395 if(script->mainMethod != mainMethod)
00396 {
00397 script.unlock();
00398 mScripts.unlock();
00399 deactivate();
00400 Except(INVALID_NAME_ERROR, "SqVM::findOrAddScript()",
00401 "The script `" + scriptName + "\' is already exists but with another entry point.");
00402 }
00403
00404 else if(script->dynamic != dynamic)
00405 {
00406 script.unlock();
00407 mScripts.unlock();
00408 deactivate();
00409 Except(INVALID_VALUE_ERROR, "SqVM::findOrAddScript()",
00410 "The script `" + scriptName + "\' is already exists but with different dynamic flag.");
00411 }
00412
00413 else if(script->hasReturn != hasReturn)
00414 {
00415 script.unlock();
00416 mScripts.unlock();
00417 deactivate();
00418 Except(INVALID_VALUE_ERROR, "SqVM::findOrAddScript()",
00419 "The script `" + scriptName + "\' is already exists but with different return flag.");
00420 }
00421
00422 } else
00423 {
00424
00425 script = createScript(scriptName, dynamic, mainMethod, hasReturn);
00426
00427 mScripts->add(scriptName, script);
00428 }
00429
00430 mScripts.unlock();
00431
00432 return script;
00433 }
00434
00435
00436
00437 void SqVM::compileAndExecuteScript(SqVM::Script::Pointer & script)
00438 {
00439
00440 ScriptState scriptState = UNCOMPILED;
00441
00442
00443 std::string scriptName = script->name.size()? script->name : "(unnamed)";
00444 scriptName = script->dynamic ? "(dynamic) script `" + scriptName + "\'" : "script `" + scriptName + "\'";
00445
00446 try
00447 {
00448
00449
00450 if(!script->compiled)
00451 {
00452
00453 if(script->dynamic)
00454 script->scriptObject = SquirrelVM::CompileBuffer(_SC(script->scriptString.c_str()));
00455 else
00456 script->scriptObject = SquirrelVM::CompileScript(_SC(script->name.c_str()));
00457
00458
00459 SquirrelVM::RunScript(script->scriptObject);
00460 script->compiled = true;
00461 Logger::getInstance()->log(Logger::NOTICE, "Squirrel script `" + script->name + "\' compiled.");
00462 }
00463
00464 scriptState = COMPILED;
00465
00466
00467 if(script->mainMethod != SqVM::NOMAINMETHOD)
00468 {
00469 switch (script->hasReturn)
00470 {
00471 case true:
00472 switch (script->parameterCount)
00473 {
00474 case 0:
00475 script->returnValue =::SqPlus::SquirrelFunction <
00476 const SQChar * >(_T(script->mainMethod.c_str()))();
00477 break;
00478 case 1:
00479 script->returnValue =::SqPlus::SquirrelFunction <
00480 const SQChar * >(_T(script->mainMethod.c_str()))(script->parameters[0]);
00481 break;
00482 case 2:
00483 script->returnValue =::SqPlus::SquirrelFunction <
00484 const SQChar * >(_T(script->mainMethod.c_str()))(script->parameters[0],
00485 script->parameters[1]);
00486 break;
00487 case 3:
00488 script->returnValue =::SqPlus::SquirrelFunction <
00489 const SQChar * >(_T(script->mainMethod.c_str()))(script->parameters[0],
00490 script->parameters[1],
00491 script->parameters[2]);
00492 break;
00493 case 4:
00494 script->returnValue =::SqPlus::SquirrelFunction <
00495 const SQChar * >(_T(script->mainMethod.c_str()))(script->parameters[0],
00496 script->parameters[1],
00497 script->parameters[2],
00498 script->parameters[3]);
00499 break;
00500 case 5:
00501 script->returnValue =::SqPlus::SquirrelFunction <
00502 const SQChar * >(_T(script->mainMethod.c_str()))(script->parameters[0],
00503 script->parameters[1],
00504 script->parameters[2],
00505 script->parameters[3],
00506 script->parameters[4]);
00507 break;
00508 case 6:
00509 script->returnValue =::SqPlus::SquirrelFunction <
00510 const SQChar * >(_T(script->mainMethod.c_str()))(script->parameters[0],
00511 script->parameters[1],
00512 script->parameters[2],
00513 script->parameters[3],
00514 script->parameters[4],
00515 script->parameters[5]);
00516 break;
00517 default:
00518 Except(SCRIPT_ERROR, "SqVM::compileAndExecuteScript",
00519 "Too many parameters passed to `" + script->mainMethod + "\' in script `" +
00520 scriptName + "\'");
00521 }
00522 break;
00523 case false:
00524 switch (script->parameterCount)
00525 {
00526 case 0:
00527 ::SqPlus::SquirrelFunction < void >(_T(script->mainMethod.c_str())) ();
00528
00529 break;
00530 case 1:
00531 ::SqPlus::SquirrelFunction <
00532 void >(_T(script->mainMethod.c_str())) (script->parameters[0]);
00533 break;
00534 case 2:
00535 ::SqPlus::SquirrelFunction <
00536 void >(_T(script->mainMethod.c_str())) (script->parameters[0],
00537 script->parameters[1]);
00538 break;
00539 case 3:
00540 ::SqPlus::SquirrelFunction <
00541 void >(_T(script->mainMethod.c_str())) (script->parameters[0],
00542 script->parameters[1],
00543 script->parameters[2]);
00544 break;
00545 case 4:
00546 ::SqPlus::SquirrelFunction <
00547 void >(_T(script->mainMethod.c_str())) (script->parameters[0],
00548 script->parameters[1],
00549 script->parameters[2],
00550 script->parameters[3]);
00551 break;
00552 case 5:
00553 ::SqPlus::SquirrelFunction <
00554 void >(_T(script->mainMethod.c_str())) (script->parameters[0],
00555 script->parameters[1],
00556 script->parameters[2],
00557 script->parameters[3],
00558 script->parameters[4]);
00559 break;
00560 case 6:
00561 ::SqPlus::SquirrelFunction <
00562 void >(_T(script->mainMethod.c_str())) (script->parameters[0],
00563 script->parameters[1],
00564 script->parameters[2],
00565 script->parameters[3],
00566 script->parameters[4],
00567 script->parameters[5]);
00568 break;
00569 default:
00570 Except(SCRIPT_ERROR, "SqVM::compileAndExecuteScript",
00571 "Too many parameters passed to `" + script->mainMethod + "\' in script `" +
00572 scriptName + "\'");
00573 }
00574 }
00575 }
00576
00577 scriptState = EXECUTED;
00578
00579 }
00580 catch(SquirrelError & e)
00581 {
00582
00583 mError = true;
00584
00585
00586 script.unlock();
00587
00588 deactivate();
00589
00590
00591 switch (scriptState)
00592 {
00593 case UNCOMPILED:
00594 if(script->dynamic)
00595 Logger::getInstance()->log(Logger::ERROR,
00596 "Squirrel " + scriptName +
00597 " cannot be compiled, since it has errors.");
00598 else
00599 Logger::getInstance()->log(Logger::ERROR,
00600 "Squirrel " + scriptName +
00601 " cannot be loaded or compiled, since it has errors or the file does not exist.");
00602 break;
00603 case COMPILED:
00604 Logger::getInstance()->log(Logger::ERROR,
00605 "An error occured after executing method `" + script->mainMethod +
00606 "\' of " + scriptName);
00607 break;
00608 case EXECUTED:
00609 Logger::getInstance()->log(Logger::FATAL,
00610 "Some internal error occured after the execution of " + scriptName +
00611 ". It should not be happened.");
00612 break;
00613 }
00614
00615
00616 if(script->dynamic)
00617 {
00618 Logger::getInstance()->logMultiLine(Logger::ERROR,
00619 "Here is the source of the dynamic script for debugging:\n ===[ code starts ] =========== \n"
00620 + script->scriptString + "\n ===[ code ends ] ============= ");
00621 }
00622
00623 Except(SCRIPT_ERROR, "SqVM::compileAndExecuteScript", "Squirrel error: `" + std::string(e.desc) + "\'");
00624 }
00625 }
00626
00627
00628
00629 void SqVM::setParameters(SqVM::Script::Pointer & script, const std::list < std::string > ¶meters)
00630 {
00631 u32 _i = 0;
00632
00633 for(std::list < std::string >::const_iterator i = parameters.begin(); i != parameters.end(); i++, _i++)
00634 script->parameters[_i] = (*i).c_str();
00635
00636 script->parameterCount = _i;
00637 }
00638
00639
00640
00641 }