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 }