- Avoid some expensive SDL_GetTicks() calls
authorMatthias Braun <matze@braunis.de>
Sun, 23 Apr 2006 13:08:57 +0000 (13:08 +0000)
committerMatthias Braun <matze@braunis.de>
Sun, 23 Apr 2006 13:08:57 +0000 (13:08 +0000)
- Update to squirrel 2.1
- Another rewrite of the scripting code
- A few bugfixes I can't remember
- Removed Sound object from scripting, replaced it with a global play_music and
  play_sound function

SVN-Revision: 3385

98 files changed:
configure.ac
data/levels/test/default.nut
data/levels/test/script.stl
data/levels/world1/27 - No More Mr Ice Guy.stl
data/levels/world1/default.nut [deleted file]
data/levels/world1/intro.nut
data/levels/world1/world.nut
src/audio/sound_manager.cpp
src/audio/stream_sound_source.cpp
src/audio/stream_sound_source.hpp
src/console.cpp
src/gameconfig.cpp
src/gameconfig.hpp
src/gui/menu.cpp
src/gui/menu.hpp
src/main.cpp
src/main.hpp
src/mainloop.cpp
src/mainloop.hpp
src/object/ambient_sound.cpp
src/object/camera.cpp
src/object/display_effect.cpp
src/object/player.cpp
src/object/scripted_object.cpp
src/object/text_object.cpp
src/script_manager.cpp [deleted file]
src/script_manager.hpp [deleted file]
src/scripting/functions.cpp
src/scripting/functions.hpp
src/scripting/sound.cpp [deleted file]
src/scripting/sound.hpp [deleted file]
src/scripting/squirrel_error.cpp
src/scripting/squirrel_util.cpp [new file with mode: 0644]
src/scripting/squirrel_util.hpp [new file with mode: 0644]
src/scripting/thread_queue.cpp [new file with mode: 0644]
src/scripting/thread_queue.hpp [new file with mode: 0644]
src/scripting/time_scheduler.cpp [new file with mode: 0644]
src/scripting/time_scheduler.hpp [new file with mode: 0644]
src/scripting/wrapper.cpp
src/scripting/wrapper.hpp
src/scripting/wrapper.interface.hpp
src/scripting/wrapper_util.cpp [deleted file]
src/scripting/wrapper_util.hpp [deleted file]
src/sector.cpp
src/sector.hpp
src/sprite/sprite.cpp
src/sprite/sprite.hpp
src/squirrel/include/sqstdio.h
src/squirrel/include/squirrel.h
src/squirrel/sqdbg/sqdbgserver.cpp
src/squirrel/sqstdlib/sqstdaux.cpp
src/squirrel/sqstdlib/sqstdblob.cpp
src/squirrel/sqstdlib/sqstdblobimpl.h
src/squirrel/sqstdlib/sqstdio.cpp
src/squirrel/sqstdlib/sqstdmath.cpp
src/squirrel/sqstdlib/sqstdrex.c [deleted file]
src/squirrel/sqstdlib/sqstdrex.cpp [new file with mode: 0644]
src/squirrel/sqstdlib/sqstdstream.cpp
src/squirrel/sqstdlib/sqstdstream.h
src/squirrel/sqstdlib/sqstdstring.cpp
src/squirrel/sqstdlib/sqstdsystem.cpp
src/squirrel/squirrel/sqapi.cpp
src/squirrel/squirrel/sqbaselib.cpp
src/squirrel/squirrel/sqclass.cpp
src/squirrel/squirrel/sqclass.h
src/squirrel/squirrel/sqclosure.h
src/squirrel/squirrel/sqcompiler.cpp
src/squirrel/squirrel/sqcompiler.h
src/squirrel/squirrel/sqdebug.cpp
src/squirrel/squirrel/sqfuncstate.cpp
src/squirrel/squirrel/sqfuncstate.h
src/squirrel/squirrel/sqlexer.cpp
src/squirrel/squirrel/sqlexer.h
src/squirrel/squirrel/sqobject.cpp
src/squirrel/squirrel/sqobject.h
src/squirrel/squirrel/sqopcodes.h
src/squirrel/squirrel/sqstate.cpp
src/squirrel/squirrel/sqstate.h
src/squirrel/squirrel/sqstring.h
src/squirrel/squirrel/sqtable.cpp
src/squirrel/squirrel/sqtable.h
src/squirrel/squirrel/sqvm.cpp
src/squirrel/squirrel/sqvm.h
src/timer.cpp
src/timer.hpp
src/title.cpp
src/video/glutil.hpp
src/world.cpp
src/world.hpp
src/worldmap/tux.cpp
src/worldmap/worldmap.cpp
src/worldmap/worldmap.hpp
tools/miniswig/create_docu.cpp
tools/miniswig/create_wrapper.cpp
tools/miniswig/lexer.ll
tools/miniswig/main.cpp
tools/miniswig/parser.yy
tools/miniswig/tree.cpp

index be44942..54ccbcf 100644 (file)
@@ -60,6 +60,12 @@ AC_CHECK_HEADERS(unistd.h)
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
 AC_C_BIGENDIAN
+AC_CHECK_SIZEOF([void *])
+AH_BOTTOM([
+#if SIZEOF_VOID_P == 8
+#define _SQ64
+#endif
+])
 
 dnl ===========================================================================
 dnl Give advanced users some options to play with
index 34e17f7..b159b10 100644 (file)
@@ -1,110 +1,6 @@
 /* Default functions for the whole levelset */
 print("default.nut loaded\n");
 
-function intro()
-{  
-  //initialize
-  SUPERTUX.set_action("stand-right");
-  RADIO.set_action("quiet");  
-  PENNY.set_action("stand-left");
-  NOLOK.set_visible(false);
-  logo <- FloatingImage("images/objects/logo/logo.sprite");
-  Tux.deactivate();
-  Tux.set_visible(false);
-  Effect.sixteen_to_nine(0);
-  
-  //begin scrolling sequence
-  Effect.fade_in(2);
-  Camera.scroll_to(0, 945, 15);
-  Sound.play("music/intro.ogg");
-  wait(3);
-  Text.set_text("Somewhere at the shores\nof Antarctica...");
-  Text.fade_in(2);
-  wait(3);
-  Text.fade_out(2);
-  wait(10);
-  SUPERTUX.set_velocity(50,0);
-  Camera.scroll_to(3100, 945, 18);
-  wait(10);
-  logo.set_anchor_point(ANCHOR_TOP);
-  logo.set_pos(0, 50);
-  logo.set_visible(true);
-  wait(5);
-  logo.set_visible(false);
-  wait(6);
-  
-  //begin conversation and Tux rap
-  SUPERTUX.set_velocity(0,0);
-  Sound.play("speech/tux_hello.ogg");
-  wait(3);
-  Sound.play("speech/penny_runt_01.ogg");
-  wait(1);
-  Sound.play("speech/tux_murp_01.ogg");
-  wait(1);
-  RADIO.set_action("loud");
-  Sound.play("speech/tux_rap.ogg");
-  wait(15);
-  shake_bush();
-  wait(2);
-  shake_bush();
-  wait(2);
-  shake_bush();
-  wait(1.3);
-  
-  //enter Nolok
-  NOLOK.set_velocity(-220, 600);
-  NOLOK.set_visible(true);
-  Effect.fade_out(1.3);
-  wait(3);
-
-  //darkness
-  NOLOK.set_visible(false);
-  PENNY.set_visible(false);
-  RADIO.set_action("quiet");
-  SUPERTUX.set_pos(3550, SUPERTUX.get_pos_y());
-
-  //wake up, Tux...
-  Effect.fade_in(4);
-  wait(4);
-  Sound.play("speech/tux_upset.ogg");
-  wait(3);
-  tux_upset();
-  wait(1);
-  tux_upset();
-  wait(4);
-  SUPERTUX.set_action("stand-right");
-  SUPERTUX.set_velocity(300,0);
-  wait(2);
-  
-  //end intro sequence
-  Effect.fade_out(2);
-  wait(3);
-  Level.finish(true);
-}
-
-function shake_bush()
-{
-  //Sound.play("sounds/rustle.wav");
-  local bushx = BUSH.get_pos_x();
-  local bushy = BUSH.get_pos_y();
-  for(local i = 0; i < 20; ++i) {
-    BUSH.set_pos(bushx + rand() % 6 - 3, bushy);
-    wait(0.05);
-  }
-}
-
-function tux_upset()
-{
-  SUPERTUX.set_action("stand-right");
-  SUPERTUX.set_velocity(200,0);
-  wait(0.3);
-  SUPERTUX.set_velocity(0,0);
-  wait(0.4);
-  SUPERTUX.set_action("stand-left");
-  SUPERTUX.set_velocity(-200,0);
-  wait(0.3);
-}
-
 function intro_scene2()
 {
   //initialize
@@ -115,7 +11,7 @@ function intro_scene2()
   Tux.deactivate();
   Tux.set_visible(false);
   Effect.sixteen_to_nine(0);
-  Sound.play("music/nolok.ogg");
+  play_sound("music/nolok.ogg");
   Effect.fade_in(5);
   wait(5);
   Camera.scroll_to(3100, 945, 8);
index 7c6846b..2020bc2 100644 (file)
@@ -11,15 +11,14 @@ logo.set_visible(true);
         
 Text.set_text(translate(\"The Crazy Nolok Dance\"));
 Text.fade_in(2);
-TUX.set_action(\"jump\");
+TUX.set_action(\"jump-left\");
 wait(4);
 Text.fade_out(1);
 wait(1);
-NOLOK.set_visible(true);
 tuxjumps <- 2;
 while(true) {
        wait(0.8);
-       Sound.play(\"sounds/jump.wav\");
+       play_sound(\"sounds/jump.wav\");
        if(tuxjumps >= 0) {
                TUX.set_velocity(50, 300);
        } else {
@@ -36,7 +35,7 @@ while(true) {
        } else if(PENNY.get_action() == \"jump\") {
                PENNY.set_action(\"dead\");
        } else {
-               Sound.play(\"sounds/grow.wav\");
+               play_sound(\"sounds/grow.wav\");
                PENNY.set_action(\"stand\");
                PENNY.set_velocity(0, 900);
        }
@@ -70,8 +69,8 @@ while(true) {
     (scriptedobject
       (name "TUX")
       (visible #t)
-      (physic-enabled #f)
-      (solid #f)
+      (physic-enabled #t)
+      (solid #t)
       (x 160)
       (y 448)
       (sprite "images/creatures/yeti/yeti.sprite")
@@ -79,21 +78,12 @@ while(true) {
     (scriptedobject
       (name "PENNY")
       (visible #t)
-      (physic-enabled #f)
-      (solid #f)
+      (physic-enabled #t)
+      (solid #t)
       (x 390)
       (y 448)
       (sprite "images/creatures/dummyguy/dummyguy.sprite")
     )
-    (scriptedobject
-      (name "NOLOK")
-      (visible #f)
-      (physic-enabled #f)
-      (solid #f)
-      (x 420)
-      (y 94)
-      (sprite "images/creatures/dummyguy/dummyguy.sprite")
-    )
     (ambient_sound
       (sample "phone")
       (distance_factor 0.01)
index b4814a9..8f17e27 100644 (file)
@@ -107,7 +107,7 @@ Effect.fade_in(1);
          (x 2)
          (y 177)
          (dead-script "
-Sound.play(\"sounds/yeti_finish.ogg\");
+play_sound(\"sounds/yeti_finish.ogg\");
 Text.set_text(\"You Made It!\");
 Text.set_font(\"big\");
 Text.fade_in(1.5);
diff --git a/data/levels/world1/default.nut b/data/levels/world1/default.nut
deleted file mode 100644 (file)
index e049a59..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-function intro()
-{
-  SUPERTUX.set_action("stand-right");
-  Tux.deactivate();
-  Tux.set_visible(false);
-  DisplayEffect.sixteen_to_nine(0);
-  DisplayEffect.fade_in(2);
-  wait(2);
-
-  Text.set_text(translate("Tux and Penny were out having a\n nice picnic on the\nice fields of Antarctica."));
-  Text.fade_in(1);
-// TODO play some tux sounds...
-  wait(1);
-
-  Sound.play("speech/tux_rap.ogg");
-  wait(5);
-  Text.fade_out(1);
-  wait(15);
-
-  Text.set_text(translate("Then suddenly..."));
-  Text.fade_in(1);
-
-  // let's shake the bush...
-  // Sound.play("sounds/rustle.wav");
-  local bushx = BUSH.get_pos_x();
-  local bushy = BUSH.get_pos_y();
-  for(local i = 0; i < 20; ++i) {
-    BUSH.set_pos(bushx + rand() % 6 - 3, bushy);
-    wait(0.1);
-  }
-  Text.fade_out(1);
-
-// NOLOK jumps out of the bush
-  wait(0.5);
-  print("jump");
-  NOLOK.set_velocity(70, 600);
-
-  wait(1)
-  NOLOK.set_velocity(-120, 700);
-  wait(1.2);
-  NOLOK.set_velocity(0, 0);
-  wait(1);
-
-// nolok casts his spell...
-  NOLOK.set_action("throw");
-  // TODO we really need fade to white here and some thunder sound...
-  DisplayEffect.fade_out(0.3);
-  wait(0.3);
-  DisplayEffect.fade_in(0);
-  wait(0.3);
-  DisplayEffect.fade_out(0.5);
-  wait(0.5);
-  DisplayEffect.fade_in(0);
-  wait(0.4);
-  DisplayEffect.fade_out(0.2);
-  wait(2.5);
-  NOLOK.set_visible(false);
-  PENNY.set_visible(false);
-  DisplayEffect.fade_in(1);
-  wait(1);
-
-  Text.set_text("Oh No!\nPenny has been captured");
-  Text.fade_in(1);
-  wait(3);
-  Text.fade_out(1);
-  
-  Text.set_text("Tux has to rescue her");
-  Text.fade_in(1);
-  wait(5);
-
-// fade out
-  DisplayEffect.fade_out(2);
-  wait(2);
-  Level.finish();
-}
index 3f33f6c..e418a7f 100644 (file)
@@ -13,7 +13,7 @@ function intro()
   //begin scrolling sequence
   Effect.fade_in(2);
   Camera.scroll_to(0, 945, 15);
-  Sound.play("music/intro.ogg");
+  play_sound("music/intro.ogg");
   wait(3);
   Text.set_text("Somewhere at the shores\nof Antarctica...");
   Text.fade_in(2);
@@ -32,14 +32,14 @@ function intro()
   
   //begin conversation and Tux rap
   SUPERTUX.set_velocity(0,0);
-  Sound.play("speech/tux_hello.ogg");
+  play_sound("speech/tux_hello.ogg");
   wait(3);
-  Sound.play("speech/penny_runt_01.ogg");
+  play_sound("speech/penny_runt_01.ogg");
   wait(1);
-  Sound.play("speech/tux_murp_01.ogg");
+  play_sound("speech/tux_murp_01.ogg");
   wait(1);
   RADIO.set_action("loud");
-  Sound.play("speech/tux_rap.ogg");
+  play_sound("speech/tux_rap.ogg");
   wait(15);
   shake_bush();
   wait(2);
@@ -63,7 +63,7 @@ function intro()
   //wake up, Tux...
   Effect.fade_in(4);
   wait(4);
-  Sound.play("speech/tux_upset.ogg");
+  play_sound("speech/tux_upset.ogg");
   wait(3);
   tux_upset();
   wait(1);
@@ -81,7 +81,7 @@ function intro()
 
 function shake_bush()
 {
-  //Sound.play("sounds/rustle.wav");
+  //play_sound("sounds/rustle.wav");
   local bushx = BUSH.get_pos_x();
   local bushy = BUSH.get_pos_y();
   for(local i = 0; i < 20; ++i) {
index c83bcc3..539cbd6 100644 (file)
@@ -1,10 +1,15 @@
 if(! ("intro_displayed" in state)) {
+       println("Display intro");
        load_level("levels/world1/intro.stl");
+       println("Wait for screenswitch");
        wait_for_screenswitch();
+       println("ok1");
        wait_for_screenswitch();
+       println("ok2");
        state.intro_displayed <- true;
        save_state();
 }
+
 if(! ("world" in state)) {
        println("No worldfound");
        state.world <- "levels/world1/worldmap.stwm";
@@ -13,7 +18,6 @@ if(! ("world" in state)) {
 
 // load worldmap and wait till it is displayed
 load_worldmap(state.world);
-fadeout_screen(0.5);
 wait_for_screenswitch();
 save_state();
 
index a05ca01..34e9a95 100644 (file)
@@ -28,6 +28,7 @@
 #include "sound_source.hpp"
 #include "stream_sound_source.hpp"
 #include "log.hpp"
+#include "timer.hpp"
 
 SoundManager* sound_manager = 0;
 
@@ -244,12 +245,11 @@ SoundManager::set_listener_velocity(const Vector& vel)
 void
 SoundManager::update()
 {
-  static Uint32 lastticks = 0;
+  static float lasttime = real_time;
 
-  Uint32 current_ticks = SDL_GetTicks();
-  if(current_ticks - lastticks < 300)
+  if(real_time - lasttime < 0.3)
     return;
-  lastticks = current_ticks;
+  lasttime = real_time;
 
   // update and check for finished sound sources
   for(SoundSources::iterator i = sources.begin(); i != sources.end(); ) {
index d278563..0cf75b2 100644 (file)
@@ -25,6 +25,7 @@
 #include "stream_sound_source.hpp"
 #include "sound_manager.hpp"
 #include "sound_file.hpp"
+#include "timer.hpp"
 #include "log.hpp"
 
 StreamSoundSource::StreamSoundSource()
@@ -80,8 +81,7 @@ StreamSoundSource::update()
   }
 
   if(fade_state == FadingOn) {
-    Uint32 ticks = SDL_GetTicks();
-    float time = (ticks - fade_start_ticks) / 1000.0;
+    float time = real_time - fade_start_time;
     if(time >= fade_time) {
       set_gain(1.0);
       fade_state = NoFading;
@@ -89,8 +89,7 @@ StreamSoundSource::update()
       set_gain(time / fade_time);
     }
   } else if(fade_state == FadingOff) {
-    Uint32 ticks = SDL_GetTicks();
-    float time = (ticks - fade_start_ticks) / 1000.0;
+    float time = real_time - fade_start_time;
     if(time >= fade_time) {
       stop();
       fade_state = NoFading;
@@ -105,7 +104,7 @@ StreamSoundSource::set_fading(FadeState state, float fade_time)
 {
   this->fade_state = state;
   this->fade_time = fade_time;
-  this->fade_start_ticks = SDL_GetTicks();
+  this->fade_start_time = real_time;
 }
 
 bool
index 25c8cd8..18b2dc9 100644 (file)
@@ -63,7 +63,7 @@ private:
   ALuint buffers[STREAMFRAGMENTS];
 
   FadeState fade_state;
-  Uint32 fade_start_ticks;
+  float fade_start_time;
   float fade_time;
   bool looping;
 };
index 9ac545c..1b5f01e 100644 (file)
 #include "video/drawing_context.hpp"
 #include "video/surface.hpp"
 #include "scripting/squirrel_error.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "physfs/physfs_stream.hpp"
 #include "player_status.hpp"
-#include "script_manager.hpp"
 #include "main.hpp"
 #include "log.hpp"
 #include "resources.hpp"
@@ -44,7 +43,7 @@ Console::Console()
 Console::~Console() 
 {
   if(vm != NULL) {
-    sq_release(ScriptManager::instance->get_vm(), &vm_object);
+    sq_release(Scripting::global_vm, &vm_object);
   }
 }
 
@@ -86,11 +85,10 @@ Console::execute_script(const std::string& command)
   using namespace Scripting;
 
   if(vm == NULL) {
-    vm = ScriptManager::instance->get_vm();
+    vm = Scripting::global_vm;
     HSQUIRRELVM new_vm = sq_newthread(vm, 16);
     if(new_vm == NULL)
-      throw Scripting::SquirrelError(ScriptManager::instance->get_vm(),
-          "Couldn't create new VM thread for console");
+      throw Scripting::SquirrelError(vm, "Couldn't create new VM thread for console");
 
     // store reference to thread
     sq_resetobject(&vm_object);
@@ -125,7 +123,7 @@ Console::execute_script(const std::string& command)
       throw SquirrelError(vm, "Couldn't compile command");
 
     sq_pushroottable(vm); 
-    if(SQ_FAILED(sq_call(vm, 1, SQTrue)))
+    if(SQ_FAILED(sq_call(vm, 1, SQTrue, SQTrue)))
       throw SquirrelError(vm, "Problem while executing command");
 
     if(sq_gettype(vm, -1) != OT_NULL)
index a3de325..416d104 100644 (file)
@@ -43,6 +43,8 @@ Config::Config()
 
   screenwidth = 800;
   screenheight = 600;
+
+  enable_script_debugger = false;
 }
 
 Config::~Config()
index ab639d8..109df1a 100644 (file)
@@ -45,6 +45,7 @@ public:
 
   /** this variable is set if supertux should start in a specific level */
   std::string start_level;
+  bool enable_script_debugger;
   std::string start_demo;
   std::string record_demo;
 };
index 7374ff7..c140804 100644 (file)
 #include "math/vector.hpp"
 #include "main.hpp"
 #include "resources.hpp"
+#include "timer.hpp"
 #include "control/joystickkeyboardcontroller.hpp"
 
-static const int MENU_REPEAT_INITIAL = 400;
-static const int MENU_REPEAT_RATE = 200;
-static const int FLICK_CURSOR_TIME = 500;
+static const float MENU_REPEAT_INITIAL = 0.4;
+static const float MENU_REPEAT_RATE = 0.2;
+static const float FLICK_CURSOR_TIME = 0.5;
 
 extern SDL_Surface* screen;
 
@@ -121,7 +122,7 @@ Menu::push_current(Menu* pmenu)
     last_menus.push_back(current_);
 
   current_ = pmenu;
-  current_->effect_ticks = SDL_GetTicks();
+  current_->effect_time = real_time;
 }
 
 void
@@ -129,7 +130,7 @@ Menu::pop_current()
 {
   if (last_menus.size() >= 1) {
     current_ = last_menus.back();
-    current_->effect_ticks = SDL_GetTicks();
+    current_->effect_time = real_time;
     last_menus.pop_back();
   } else {
     current_ = 0;
@@ -142,7 +143,7 @@ Menu::set_current(Menu* menu)
   last_menus.clear();
 
   if (menu)
-    menu->effect_ticks = SDL_GetTicks();
+    menu->effect_time = real_time;
 
   current_ = menu;
   // just to be sure...
@@ -174,7 +175,7 @@ std::string MenuItem::get_input_with_symbol(bool active_item)
   if(!active_item) {
     input_flickering = true;
   } else {
-    input_flickering = (SDL_GetTicks() / FLICK_CURSOR_TIME) % 2;
+    input_flickering = ((int) (real_time / FLICK_CURSOR_TIME)) % 2;
   }
 
   char str[1024];
@@ -193,6 +194,12 @@ Menu::~Menu()
   for(std::vector<MenuItem*>::iterator i = items.begin();
       i != items.end(); ++i)
     delete *i;
+#ifdef DEBUG
+  assert(current_ != this);
+#else
+  if(current_ == this)
+    current_ = NULL;
+#endif
 }
 
 Menu::Menu()
@@ -320,24 +327,23 @@ void
 Menu::update()
 {
   /** check main input controller... */
-  Uint32 ticks = SDL_GetTicks();
   if(main_controller->pressed(Controller::UP)) {
     menuaction = MENU_ACTION_UP;
-    menu_repeat_ticks = ticks + MENU_REPEAT_INITIAL;
+    menu_repeat_time = real_time + MENU_REPEAT_INITIAL;
   }
   if(main_controller->hold(Controller::UP) && 
-      menu_repeat_ticks != 0 && ticks > menu_repeat_ticks) {
+      menu_repeat_time != 0 && real_time > menu_repeat_time) {
     menuaction = MENU_ACTION_UP;
-    menu_repeat_ticks = ticks + MENU_REPEAT_RATE;
+    menu_repeat_time = real_time + MENU_REPEAT_RATE;
   } 
   if(main_controller->pressed(Controller::DOWN)) {
     menuaction = MENU_ACTION_DOWN;
-    menu_repeat_ticks = ticks + MENU_REPEAT_INITIAL;
+    menu_repeat_time = real_time + MENU_REPEAT_INITIAL;
   }
   if(main_controller->hold(Controller::DOWN) && 
-      menu_repeat_ticks != 0 && ticks > menu_repeat_ticks) {
+      menu_repeat_time != 0 && real_time > menu_repeat_time) {
     menuaction = MENU_ACTION_DOWN;
-    menu_repeat_ticks = ticks + MENU_REPEAT_RATE;
+    menu_repeat_time = real_time + MENU_REPEAT_RATE;
   }
   if(main_controller->pressed(Controller::JUMP)
      || main_controller->pressed(Controller::ACTION)
@@ -494,12 +500,12 @@ Menu::draw_item(DrawingContext& context, int index)
   MenuItem& pitem = *(items[index]);
 
   int effect_offset = 0;
-  if(effect_ticks != 0) {
-    if(SDL_GetTicks() - effect_ticks > 500) {
-      effect_ticks = 0;
+  if(effect_time != 0) {
+    if(real_time - effect_time > 0.5) {
+      effect_time = 0;
     } else {
-      Uint32 effect_time = (500 - (SDL_GetTicks() - effect_ticks)) / 4;
-      effect_offset = (index % 2) ? effect_time : -effect_time;
+      float effect_delta = (0.5 - (real_time - effect_time)) * 250;
+      effect_offset = (int) ((index % 2) ? effect_delta : -effect_delta);
     }
   }
 
@@ -761,7 +767,7 @@ Menu::is_toggled(int id) const
 void
 Menu::event(const SDL_Event& event)
 {
-  if(effect_ticks != 0)
+  if(effect_time != 0)
     return;
 
   switch(event.type) {
index 0357c03..55d97e2 100644 (file)
@@ -133,7 +133,7 @@ private:
   /* input implementation variables */
   int delete_character;
   char mn_input_char;
-  Uint32 menu_repeat_ticks;
+  float menu_repeat_time;
 
 public:
   static Font* default_font;
@@ -193,7 +193,7 @@ protected:
 private:
   void check_controlfield_change_event(const SDL_Event& event);  
   void draw_item(DrawingContext& context, int index);
-  Uint32 effect_ticks;
+  float effect_time;
   int arrange_left;
   int active_item;
 
index 5543ea3..c1bd127 100644 (file)
 #include "audio/sound_manager.hpp"
 #include "video/surface.hpp"
 #include "video/texture_manager.hpp"
+#include "video/glutil.hpp"
 #include "control/joystickkeyboardcontroller.hpp"
 #include "options_menu.hpp"
 #include "mainloop.hpp"
 #include "title.hpp"
 #include "game_session.hpp"
-#include "script_manager.hpp"
-#include "scripting/sound.hpp"
 #include "scripting/level.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "file_system.hpp"
 #include "physfs/physfs_sdl.hpp"
 
@@ -250,6 +249,8 @@ static bool parse_commandline(int argc, char** argv)
         throw std::runtime_error("Need to specify a demo filename");
       }
       config->record_demo = argv[++i];
+    } else if(arg == "-d") {
+      config->enable_script_debugger = true;
     } else if(arg == "--help") {
       print_usage(argv[0]);
       return true;
@@ -286,46 +287,6 @@ static void init_sdl()
       ;
 }
 
-static void check_gl_error()
-{
-  GLenum glerror = glGetError();
-  std::string errormsg;
-  
-  if(glerror != GL_NO_ERROR) {
-    switch(glerror) {
-      case GL_INVALID_ENUM:
-        errormsg = "Invalid enumeration value";
-        break;
-      case GL_INVALID_VALUE:
-        errormsg = "Numeric argzment out of range";
-        break;
-      case GL_INVALID_OPERATION:
-        errormsg = "Invalid operation";
-        break;
-      case GL_STACK_OVERFLOW:
-        errormsg = "stack overflow";
-        break;
-      case GL_STACK_UNDERFLOW:
-        errormsg = "stack underflow";
-        break;
-      case GL_OUT_OF_MEMORY:
-        errormsg = "out of memory";
-        break;
-#ifdef GL_TABLE_TOO_LARGE
-      case GL_TABLE_TOO_LARGE:
-        errormsg = "table too large";
-        break;
-#endif
-      default:
-        errormsg = "unknown error number";
-        break;
-    }
-    std::stringstream msg;
-    msg << "OpenGL Error: " << errormsg;
-    throw std::runtime_error(msg.str());
-  }
-}
-
 void init_video()
 {
   if(texture_manager != NULL)
@@ -382,7 +343,7 @@ void init_video()
   glLoadIdentity();
   glTranslatef(0, 0, 0);
 
-  check_gl_error();
+  check_gl_error("Setting up view matrices");
 
   if(texture_manager != NULL)
     texture_manager->reload_textures();
@@ -398,17 +359,6 @@ static void init_audio()
   sound_manager->enable_music(config->music_enabled);
 }
 
-static void init_scripting()
-{
-  ScriptManager::instance = new ScriptManager();
-
-  HSQUIRRELVM vm = ScriptManager::instance->get_vm();
-  sq_pushroottable(vm); 
-  expose_object(vm, -1, new Scripting::Sound(), "Sound", true);
-  expose_object(vm, -1, new Scripting::Level(), "Level", true);
-  sq_pop(vm, 1);
-}
-
 static void quit_audio()
 {
   if(sound_manager != NULL) {
@@ -503,8 +453,7 @@ int main(int argc, char** argv)
     init_video();
     Console::instance->init_graphics(); 
     timelog("scripting");
-    init_scripting();
-
+    Scripting::init_squirrel(config->enable_script_debugger);
     timelog("resources");
     load_shared(); 
     timelog(0);
@@ -550,8 +499,7 @@ int main(int argc, char** argv)
   main_controller = NULL;
   delete Console::instance;
   Console::instance = NULL;
-  delete ScriptManager::instance;
-  ScriptManager::instance = NULL; 
+  Scripting::exit_squirrel();
   delete texture_manager;
   texture_manager = NULL;
   SDL_Quit();
index 5f2ebbf..93c03d9 100644 (file)
@@ -23,7 +23,9 @@
 void init_video();
 void wait_for_event(float min_delay, float max_delay);
 
+/// The width of the display (this is a logical value, not the physical value)
 static const float SCREEN_WIDTH = 800;
+/// The height of the display (this is a logical value, not the physical value)
 static const float SCREEN_HEIGHT = 600;
 
 // global variables
index 65da30b..3f2f4c0 100644 (file)
 #include "control/joystickkeyboardcontroller.hpp"
 #include "gui/menu.hpp"
 #include "audio/sound_manager.hpp"
+#include "scripting/time_scheduler.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "gameconfig.hpp"
 #include "main.hpp"
 #include "resources.hpp"
-#include "script_manager.hpp"
 #include "screen.hpp"
 #include "screen_fade.hpp"
 #include "timer.hpp"
@@ -43,12 +44,18 @@ static const float LOGICAL_FPS = 64.0;
 MainLoop* main_loop = NULL;
 
 MainLoop::MainLoop()
-  : speed(1.0)
+  : speed(1.0), nextpop(false), nextpush(false)
 {
+  using namespace Scripting;
+  TimeScheduler::instance = new TimeScheduler();
 }
 
 MainLoop::~MainLoop()
 {
+  using namespace Scripting;
+  delete TimeScheduler::instance;
+  TimeScheduler::instance = NULL;
+
   for(std::vector<Screen*>::iterator i = screen_stack.begin();
       i != screen_stack.end(); ++i) {
     delete *i;
@@ -124,7 +131,7 @@ MainLoop::run()
   
   running = true;
   while(running) {
-    if( (next_screen.get() != NULL || nextpop == true) &&
+    while( (next_screen.get() != NULL || nextpop == true) &&
             (screen_fade.get() == NULL || screen_fade->done())) {
       if(current_screen.get() != NULL) {
         current_screen->leave();
@@ -137,22 +144,24 @@ MainLoop::run()
         }
         next_screen.reset(screen_stack.back());
         screen_stack.pop_back();
-        nextpop = false;
-        speed = 1.0;
       }
       if(nextpush && current_screen.get() != NULL) {
         screen_stack.push_back(current_screen.release());
       }
-      
-      next_screen->setup();
-      ScriptManager::instance->fire_wakeup_event(ScriptManager::SCREEN_SWITCHED);
+      nextpush = false;
+      nextpop = false;
+      speed = 1.0;
+      if(next_screen.get() != NULL)
+        next_screen->setup();
       current_screen.reset(next_screen.release());
-      next_screen.reset(NULL);
       screen_fade.reset(NULL);
+
+      waiting_threads.wakeup();
     }
 
-    if(current_screen.get() == NULL)
-        break;
+    if(!running || current_screen.get() == NULL)
+      break;
       
     float elapsed_time = 1.0 / LOGICAL_FPS;
     ticks = SDL_GetTicks();
@@ -206,10 +215,12 @@ MainLoop::run()
       }
     }
 
+    real_time += elapsed_time;
     elapsed_time *= speed;
-
     game_time += elapsed_time;
-    ScriptManager::instance->update();
+    
+    Scripting::update_debugger();
+    Scripting::TimeScheduler::instance->update(game_time);
     current_screen->update(elapsed_time);
     if(screen_fade.get() != NULL)
       screen_fade->update(elapsed_time);
index db961e0..47621f3 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <memory>
 #include <vector>
+#include "scripting/thread_queue.hpp"
 
 class Screen;
 class Console;
@@ -42,6 +43,9 @@ public:
   void push_screen(Screen* screen, ScreenFade* fade = NULL);
   void set_screen_fade(ScreenFade* fade);
 
+  /// threads that wait for a screenswitch
+  Scripting::ThreadQueue waiting_threads;
+
 private:
   void draw_fps(DrawingContext& context, float fps);
   
index f8d3eb9..6893054 100644 (file)
 
 AmbientSound::AmbientSound(const lisp::Lisp& lisp)
 {
-  position.x=0;
-  position.y=0;
+  position.x = 0;
+  position.y = 0;
 
-  dimension.x=0;
-  dimension.y=0;
+  dimension.x = 0;
+  dimension.y = 0;
 
-  distance_factor=0;
-  distance_bias=0;
-  maximumvolume=1;
-  sample="";
+  distance_factor = 0;
+  distance_bias = 0;
+  maximumvolume = 1;
+  sample = "";
+  currentvolume = 0;
 
   if (!(lisp.get("x", position.x)&&lisp.get("y", position.y))) {
     log_warning << "No Position in ambient_sound" << std::endl;
@@ -136,48 +137,40 @@ AmbientSound::start_playing()
     log_warning << "Couldn't play '" << sample << "': " << e.what() << "" << std::endl;
     delete sound_source;
     sound_source = 0;
+    remove_me();
   }
 }
 
 void
 AmbientSound::update(float deltat) 
-{
-  if (latency--<=0) {
-
+{ 
+  if (latency-- <= 0) {
     float px,py;
     float rx,ry;
 
     // Player position
-
     px=Sector::current()->player->get_pos().x;
     py=Sector::current()->player->get_pos().y;
 
     // Relate to which point in the area
-
     rx=px<position.x?position.x:
       (px<position.x+dimension.x?px:position.x+dimension.x);
     ry=py<position.y?position.y:
       (py<position.y+dimension.y?py:position.y+dimension.y);
 
     // calculate square of distance
-
     float sqrdistance=(px-rx)*(px-rx)+(py-ry)*(py-ry);
-    
     sqrdistance-=distance_bias;
 
     // inside the bias: full volume (distance 0)
-    
     if (sqrdistance<0)
       sqrdistance=0;
     
     // calculate target volume - will never become 0
-
     targetvolume=1/(1+sqrdistance*distance_factor);
-
     float rise=targetvolume/currentvolume;
 
     // rise/fall half life?
-
     currentvolume*=pow(rise,deltat*10);
     currentvolume += 1e-6; // volume is at least 1e-6 (0 would never rise)
 
index a4b9253..9edc020 100644 (file)
@@ -27,7 +27,7 @@
 #include "lisp/writer.hpp"
 #include "lisp/list_iterator.hpp"
 #include "scripting/camera.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "camera.hpp"
 #include "player.hpp"
 #include "tilemap.hpp"
index 1667315..62128b9 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <assert.h>
 #include "video/drawing_context.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "main.hpp"
 
 static const float BORDER_SIZE = 75;
index 1547ca7..35f874e 100644 (file)
@@ -16,7 +16,6 @@
 //  You should have received a copy of the GNU General Public License
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
 #include <config.h>
 
 #include <typeinfo>
@@ -41,7 +40,7 @@
 #include "object/bullet.hpp"
 #include "trigger/trigger_base.hpp"
 #include "control/joystickkeyboardcontroller.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "main.hpp"
 #include "platform.hpp"
 #include "badguy/badguy.hpp"
index f315174..07eebb3 100644 (file)
@@ -25,7 +25,7 @@
 #include "scripted_object.hpp"
 #include "video/drawing_context.hpp"
 #include "sprite/sprite_manager.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "resources.hpp"
 #include "object_factory.hpp"
 #include "math/vector.hpp"
index 5fbd47f..acf48dd 100644 (file)
@@ -24,7 +24,7 @@
 #include <iostream>
 #include "resources.hpp"
 #include "video/drawing_context.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "log.hpp"
 
 TextObject::TextObject()
diff --git a/src/script_manager.cpp b/src/script_manager.cpp
deleted file mode 100644 (file)
index da3f606..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-//  02111-1307, USA.
-#include <config.h>
-
-#include "script_manager.hpp"
-
-#include <stdarg.h>
-#include <stdexcept>
-#include <sstream>
-#include <fstream>
-#include <sqstdaux.h>
-#include <sqstdblob.h>
-#include <sqstdmath.h>
-#include <sqstdstring.h>
-
-#include "timer.hpp"
-#include "console.hpp"
-#include "log.hpp"
-#include "scripting/wrapper.hpp"
-#include "scripting/wrapper_util.hpp"
-#include "scripting/squirrel_error.hpp"
-#include "physfs/physfs_stream.hpp"
-
-using namespace Scripting;
-
-ScriptManager* ScriptManager::instance = NULL;
-
-static void printfunc(HSQUIRRELVM, const char* str, ...)
-{
-  char buf[4096];
-  va_list arglist; 
-  va_start(arglist, str); 
-  vsprintf(buf, str, arglist);
-  Console::output << (const char*) buf << std::flush;
-  va_end(arglist); 
-}
-
-ScriptManager::ScriptManager()
-  : parent(NULL)
-{
-  vm = sq_open(64);
-  if(vm == 0)
-    throw std::runtime_error("Couldn't initialize squirrel vm");
-  sq_setforeignptr(vm, (SQUserPointer) this);
-
-#ifdef ENABLE_SQDBG
-  debugger = NULL;
-  /*
-  debugger = sq_rdbg_init(vm, 1234, SQFalse);
-  if(debugger == NULL)
-    throw SquirrelError(vm, "Couldn't initialize suirrel remote debugger");
-
-  sq_enabledebuginfo(vm, SQTrue);
-  log_info << "Waiting for debug client..." << std::endl;
-  if(!SQ_SUCCEEDED(sq_rdbg_waitforconnections(debugger))) {
-    throw SquirrelError(vm, "Waiting for debug clients failed");
-  }
-  log_info << "debug client connected." << std::endl;
-  */
-#endif
-
-  // register squirrel libs
-  sq_pushroottable(vm);
-  if(sqstd_register_bloblib(vm) < 0)
-    throw SquirrelError(vm, "Couldn't register blob lib");
-  if(sqstd_register_mathlib(vm) < 0)
-    throw SquirrelError(vm, "Couldn't register math lib");
-  if(sqstd_register_stringlib(vm) < 0)
-    throw SquirrelError(vm, "Couldn't register string lib");
-  // register supertux API
-  register_supertux_wrapper(vm);
-  sq_pop(vm, 1);
-
-  // register print function
-  sq_setprintfunc(vm, printfunc);
-  // register default error handlers
-  sqstd_seterrorhandlers(vm); 
-
-  // try to load default script
-  try {
-    std::string filename = "scripts/default.nut";
-    IFileStream stream(filename);
-    Scripting::compile_and_run(vm, stream, filename);
-  } catch(std::exception& e) {
-    log_warning << "Couldn't load default.nut: " << e.what() << std::endl;
-  }
-}
-
-ScriptManager::ScriptManager(ScriptManager* parent)
-{
-#ifdef ENABLE_SQDBG
-  debugger = NULL;
-#endif
-  this->parent = parent;
-  vm = parent->vm;
-  parent->childs.push_back(this);
-}
-
-ScriptManager::~ScriptManager()
-{
-  for(SquirrelVMs::iterator i = squirrel_vms.begin();
-      i != squirrel_vms.end(); ++i)
-    sq_release(vm, &(i->vm_obj));
-
-  if(parent != NULL) {
-    parent->childs.erase(
-        std::remove(parent->childs.begin(), parent->childs.end(), this),
-        parent->childs.end());
-  } else {
-#ifdef ENABLE_SQDBG
-    sq_rdbg_shutdown(debugger);
-#endif
-    sq_close(vm);
-  }
-}
-
-HSQUIRRELVM
-ScriptManager::create_thread(bool leave_thread_on_stack)
-{
-  HSQUIRRELVM new_vm = sq_newthread(vm, 64);
-  if(new_vm == NULL)
-    throw SquirrelError(vm, "Couldn't create new VM");
-  sq_setforeignptr(new_vm, (SQUserPointer) this);
-
-  // retrieve reference to thread from stack and increase refcounter
-  HSQOBJECT vm_obj;
-  sq_resetobject(&vm_obj);
-  if(SQ_FAILED(sq_getstackobj(vm, -1, &vm_obj))) {
-    throw SquirrelError(vm, "Couldn't get coroutine vm from stack");
-  }
-  sq_addref(vm, &vm_obj);
-
-  if(!leave_thread_on_stack)
-    sq_pop(vm, 1);
-  
-  squirrel_vms.push_back(SquirrelVM(new_vm, vm_obj));
-
-  return new_vm;
-}
-
-void
-ScriptManager::update()
-{
-#ifdef ENABLE_SQDBG
-  if(debugger != NULL)
-    sq_rdbg_update(debugger);
-#endif
-
-  for(SquirrelVMs::iterator i = squirrel_vms.begin(); i != squirrel_vms.end(); ) {
-    SquirrelVM& squirrel_vm = *i;
-    int vm_state = sq_getvmstate(squirrel_vm.vm);
-    
-    if(vm_state == SQ_VMSTATE_SUSPENDED 
-            && squirrel_vm.wakeup_time > 0 
-            && game_time >= squirrel_vm.wakeup_time) {
-      squirrel_vm.waiting_for_events = WakeupData(NO_EVENT);
-      squirrel_vm.wakeup_time = 0;
-      
-      try {
-        if(SQ_FAILED(sq_wakeupvm(squirrel_vm.vm, false, false))) {
-          throw SquirrelError(squirrel_vm.vm, "Couldn't resume script");
-        }
-      } catch(std::exception& e) {
-        std::cerr << "Problem executing script: " << e.what() << "\n";
-        sq_release(vm, &squirrel_vm.vm_obj);
-        i = squirrel_vms.erase(i);
-        continue;
-      }
-    }
-       
-    if (vm_state != SQ_VMSTATE_SUSPENDED) {
-      sq_release(vm, &(squirrel_vm.vm_obj));
-      i = squirrel_vms.erase(i);
-    } else {
-      ++i;
-    }
-  }
-}
-
-void
-ScriptManager::set_wakeup_event(HSQUIRRELVM vm, WakeupData event, float timeout)
-{
-  assert(event.type >= 0 && event.type < WAKEUP_EVENT_COUNT);
-  // find the VM in the list and update it
-  for(SquirrelVMs::iterator i = squirrel_vms.begin();
-      i != squirrel_vms.end(); ++i) {
-    SquirrelVM& squirrel_vm = *i;
-    if(squirrel_vm.vm == vm) 
-      {
-        squirrel_vm.waiting_for_events = event;
-
-        if(timeout < 0) {
-          squirrel_vm.wakeup_time = -1;
-        } else {
-          squirrel_vm.wakeup_time = game_time + timeout;
-        }
-        return;
-      }
-  }
-}
-
-void
-ScriptManager::fire_wakeup_event(WakeupData  event)
-{
-  assert(event.type >= 0 && event.type < WAKEUP_EVENT_COUNT);
-  for(SquirrelVMs::iterator i = squirrel_vms.begin();
-      i != squirrel_vms.end(); ++i) {
-    SquirrelVM& vm = *i;
-    if(vm.waiting_for_events.type == event.type
-        && vm.waiting_for_events.type != NO_EVENT) {
-      vm.wakeup_time = game_time;
-      break;
-    }
-  }
-
-  for(std::vector<ScriptManager*>::iterator i = childs.begin();
-      i != childs.end(); ++i) {
-    ScriptManager* child = *i;
-    child->fire_wakeup_event(event);
-  }
-}
-
-void
-ScriptManager::set_wakeup_event(HSQUIRRELVM vm, WakeupEvent event, float timeout)
-{
-  set_wakeup_event(vm, WakeupData(event), timeout);
-}
-
-void
-ScriptManager::fire_wakeup_event(WakeupEvent event)
-{
-  fire_wakeup_event(WakeupData(event));
-}
-
-ScriptManager::SquirrelVM::SquirrelVM(HSQUIRRELVM arg_vm, HSQOBJECT arg_obj)
-  : vm(arg_vm), vm_obj(arg_obj)
-{
-  waiting_for_events = WakeupData(NO_EVENT);
-  wakeup_time        = 0;
-}
-
diff --git a/src/script_manager.hpp b/src/script_manager.hpp
deleted file mode 100644 (file)
index e0f2978..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-//  02111-1307, USA.
-#ifndef __SCRIPT_MANAGER_H__
-#define __SCRIPT_MANAGER_H__
-
-#include <vector>
-#include <list>
-#include <squirrel.h>
-#include <iostream>
-#include "timer.hpp"
-#ifdef ENABLE_SQDBG
-#include <sqdbg/sqrdbg.h>
-#endif
-
-class GameObject;
-
-/**
- * This class is responsible for managing all running squirrel threads
- * (they are cooperative threads or coroutines)
- * It keeps a list of suspended scripts and receives wakeup events for them
- */
-class ScriptManager
-{
-public:
-  ScriptManager();
-  ScriptManager(ScriptManager* parent);
-  ~ScriptManager();
-
-  void update();
-
-  /**
-   * Creates a new thread and registers it with the script manager
-   * (so it can suspend and register for wakeup events)
-   */
-  HSQUIRRELVM create_thread(bool leave_thread_on_stack = false);
-
-  HSQUIRRELVM get_vm() const
-  {
-    return vm;
-  }
-
-  enum WakeupEvent {
-    NO_EVENT,
-    TIME,
-    SCREEN_SWITCHED,
-    WAKEUP_EVENT_COUNT
-  };
-
-  struct WakeupData {
-    explicit WakeupData() : type(NO_EVENT) {}
-    explicit WakeupData(WakeupEvent type_) : type(type_) {}
-
-    WakeupEvent type;
-    
-    union {
-      // GAMEOBJECT_DONE
-      GameObject* game_object;
-    };
-  };
-
-  void set_wakeup_event(HSQUIRRELVM vm, WakeupEvent event, float timeout = -1);
-  void set_wakeup_event(HSQUIRRELVM vm, WakeupData  event, float timeout = -1);
-  void fire_wakeup_event(WakeupEvent event);
-  void fire_wakeup_event(WakeupData  event);
-
-  // global (root) instance of the ScriptManager
-  static ScriptManager* instance;
-  
-private:
-  class SquirrelVM
-  {
-  public:
-    SquirrelVM(HSQUIRRELVM arg_vm, HSQOBJECT arg_obj);
-
-    HSQUIRRELVM vm;
-    HSQOBJECT   vm_obj;
-    float       wakeup_time;
-    WakeupData  waiting_for_events;
-  };
-  
-  typedef std::list<SquirrelVM> SquirrelVMs;
-  SquirrelVMs squirrel_vms;
-
-  HSQUIRRELVM vm;
-  ScriptManager* parent;
-  std::vector<ScriptManager*> childs;
-#ifdef ENABLE_SQDBG
-  HSQREMOTEDBG debugger;
-#endif
-};
-
-#endif
-
index fc946db..1285da6 100644 (file)
@@ -29,7 +29,6 @@
 #include "game_session.hpp"
 #include "tinygettext/tinygettext.hpp"
 #include "physfs/physfs_stream.hpp"
-#include "script_manager.hpp"
 #include "resources.hpp"
 #include "gettext.hpp"
 #include "log.hpp"
 #include "shrinkfade.hpp"
 #include "object/camera.hpp"
 #include "flip_level_transformer.hpp"
+#include "audio/sound_manager.hpp"
 
 #include "squirrel_error.hpp"
-#include "wrapper_util.hpp"
+#include "squirrel_util.hpp"
+#include "time_scheduler.hpp"
 
 namespace Scripting
 {
@@ -65,27 +66,18 @@ void print_stacktrace(HSQUIRRELVM vm)
 
 int get_current_thread(HSQUIRRELVM vm)
 {
-  SQObject object;
-  sq_resetobject(&object);
-  object._unVal.pThread = vm;
-  object._type = OT_THREAD;
-  sq_pushobject(vm, object);
-
+  sq_pushobject(vm, vm_to_object(vm));
   return 1;
 }
 
 void wait(HSQUIRRELVM vm, float seconds)
 {
-  SQUserPointer ptr = sq_getforeignptr(vm);
-  ScriptManager* script_manager = reinterpret_cast<ScriptManager*> (ptr);
-  script_manager->set_wakeup_event(vm, ScriptManager::TIME, seconds);
+  TimeScheduler::instance->schedule_thread(vm, game_time + seconds);
 }
 
 void wait_for_screenswitch(HSQUIRRELVM vm)
 {
-  SQUserPointer ptr = sq_getforeignptr(vm);
-  ScriptManager* script_manager = reinterpret_cast<ScriptManager*> (ptr);
-  script_manager->set_wakeup_event(vm, ScriptManager::SCREEN_SWITCHED);
+  main_loop->waiting_threads.add(vm);
 }
 
 void exit_screen()
@@ -144,7 +136,7 @@ void import(HSQUIRRELVM vm, const std::string& filename)
     throw SquirrelError(vm, "Couldn't parse script");
     
   sq_pushroottable(vm);
-  if(SQ_FAILED(sq_call(vm, 1, SQFalse))) {
+  if(SQ_FAILED(sq_call(vm, 1, SQFalse, SQTrue))) {
     sq_pop(vm, 1);
     throw SquirrelError(vm, "Couldn't execute script");
   }
@@ -201,6 +193,16 @@ bool validate_sector_player()
   return true;
 }
 
+void play_music(const std::string& filename)
+{
+  sound_manager->play_music(filename);
+}
+
+void play_sound(const std::string& filename)
+{
+  sound_manager->play(filename);
+}
+
 void grease()
 {
   if (!validate_sector_player()) return;
index 2b69063..250fa7b 100644 (file)
@@ -132,6 +132,16 @@ void debug_draw_fps(bool enable);
 void debug_draw_solids_only(bool enable);
 
 /**
+ * Changes music to musicfile
+ */
+void play_music(const std::string& musicfile);
+
+/**
+ * Plays a soundfile
+ */
+void play_sound(const std::string& soundfile);
+
+/**
  * speeds Tux up
  */
 void grease();
diff --git a/src/scripting/sound.cpp b/src/scripting/sound.cpp
deleted file mode 100644 (file)
index 5dca877..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#include <config.h>
-
-#include <string>
-#include <stdio.h>
-#include "sound.hpp"
-#include "resources.hpp"
-#include "audio/sound_manager.hpp"
-
-namespace Scripting
-{
-
-  Sound::Sound()
-  {}
-
-  Sound::~Sound() 
-  {}
-
-  void
-  Sound::play_music(const std::string& filename)
-  {
-    sound_manager->play_music(filename);
-  }
-
-  void
-  Sound::play(const std::string& name)
-  {
-    sound_manager->play(name);
-  }
-}
diff --git a/src/scripting/sound.hpp b/src/scripting/sound.hpp
deleted file mode 100644 (file)
index e7bf1ce..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#ifndef __SOUND_H__
-#define __SOUND_H__
-
-namespace Scripting
-{
-
-/**
- * This class allows manipulating the sound output of the game
- */
-class Sound
-{
-public:
-  void play_music(const std::string& musicfile);
-  /**
-   * Play a sound effect. The name should be without path or .wav extension
-   */
-  void play(const std::string& soundfile);
-
-  ~Sound();
-
-#ifndef SCRIPTING_API
-  Sound();
-#endif
-};
-
-}
-
-#endif
-
index f7d45e4..2c28273 100644 (file)
@@ -16,7 +16,6 @@
 //  You should have received a copy of the GNU General Public License
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
 #include <config.h>
 
 #include "squirrel_error.hpp"
@@ -39,8 +38,8 @@ SquirrelError::SquirrelError(HSQUIRRELVM v, const std::string& message) throw()
   {
     sq_getstring(v, -1, &lasterr);
   }
-  sq_pop(v, 1);
   msg << lasterr << ")";
+  sq_pop(v, 1);
   this->message = msg.str();
 }
 
diff --git a/src/scripting/squirrel_util.cpp b/src/scripting/squirrel_util.cpp
new file mode 100644 (file)
index 0000000..f9cb648
--- /dev/null
@@ -0,0 +1,381 @@
+//  $Id$
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#include <stdexcept>
+#include <sstream>
+#include <stdarg.h>
+#include <squirrel.h>
+#include <sqstdmath.h>
+#include <sqstdblob.h>
+#include <sqstdstring.h>
+#include <sqstdaux.h>
+#include <sqstdio.h>
+#include "squirrel_util.hpp"
+#include "log.hpp"
+#include "level.hpp"
+#include "physfs/physfs_stream.hpp"
+
+#ifdef ENABLE_SQDBG
+#include <sqdbg/sqrdbg.h>
+
+static HSQREMOTEDBG debugger = NULL;
+#endif
+
+namespace Scripting
+{
+
+HSQUIRRELVM global_vm = NULL;
+
+static void printfunc(HSQUIRRELVM, const char* str, ...)
+{
+  char buf[4096];
+  va_list arglist;
+  va_start(arglist, str);
+  vsprintf(buf, str, arglist);
+  Console::output << (const char*) buf << std::flush;
+  va_end(arglist);
+}
+
+void init_squirrel(bool enable_debugger)
+{
+  global_vm = sq_open(64);
+  if(global_vm == NULL)
+    throw std::runtime_error("Couldn't initialize squirrel vm");
+
+#ifdef ENABLE_SQDBG
+  if(enable_debugger) {
+    sq_enabledebuginfo(global_vm, SQTrue);
+    debugger = sq_rdbg_init(global_vm, 1234, SQFalse);
+    if(debugger == NULL)
+      throw SquirrelError(global_vm, "Couldn't initialize squirrel debugger");
+  
+    sq_enabledebuginfo(global_vm, SQTrue);
+    log_info << "Waiting for debug client..." << std::endl;
+    if(SQ_FAILED(sq_rdbg_waitforconnections(debugger)))
+      throw SquirrelError(global_vm, "Waiting for debug clients failed");
+    log_info << "debug client connected." << std::endl;
+  }
+#endif
+
+  sq_pushroottable(global_vm);
+  if(sqstd_register_bloblib(global_vm) < 0)
+    throw SquirrelError(global_vm, "Couldn't register blob lib");
+  if(sqstd_register_mathlib(global_vm) < 0)
+    throw SquirrelError(global_vm, "Couldn't register math lib");
+  if(sqstd_register_stringlib(global_vm) < 0)
+    throw SquirrelError(global_vm, "Couldn't register string lib");
+  // register supertux API
+  register_supertux_wrapper(global_vm);
+
+  // TODO remove this at some point... it shoud just be functions not an object
+  expose_object(global_vm, -1, new Scripting::Level(), "Level", true);
+  
+  sq_pop(global_vm, 1);
+
+  // register print function
+  sq_setprintfunc(global_vm, printfunc);
+  // register default error handlers
+  sqstd_seterrorhandlers(global_vm);
+
+  // try to load default script
+  try {
+    std::string filename = "scripts/default.nut";
+    IFileStream stream(filename);
+    Scripting::compile_and_run(global_vm, stream, filename);
+  } catch(std::exception& e) {
+    log_warning << "Couldn't load default.nut: " << e.what() << std::endl;
+  }
+}
+
+void exit_squirrel()
+{
+#ifdef ENABLE_SQDBG
+  if(debugger != NULL) {
+    sq_rdbg_shutdown(debugger);
+    debugger = NULL;
+  }
+#endif
+  sq_close(global_vm);
+  global_vm = NULL;
+}
+
+void update_debugger()
+{
+#ifdef ENABLE_SQDBG
+  if(debugger != NULL)
+    sq_rdbg_update(debugger);
+#endif
+}
+
+std::string squirrel2string(HSQUIRRELVM v, int i)
+{
+  std::ostringstream os;
+  switch(sq_gettype(v, i))
+    {
+    case OT_NULL:
+      os << "<null>";        
+      break;
+    case OT_BOOL: {
+      SQBool p;
+      sq_getbool(v, i, &p);
+      if (p) 
+        os << "true";
+      else
+        os << "false";
+      break;
+    }
+    case OT_INTEGER: {
+      int val;
+      sq_getinteger(v, i, &val);
+      os << val;
+      break;
+    }
+    case OT_FLOAT: {
+      float val;
+      sq_getfloat(v, i, &val);
+      os << val;
+      break;
+    }
+    case OT_STRING: {
+      const char* val;
+      sq_getstring(v, i, &val);
+      os << "\"" << val << "\"";
+      break;    
+    }
+    case OT_TABLE: {
+      bool first = true;
+      os << "{";
+      sq_pushnull(v);  //null iterator
+      while(SQ_SUCCEEDED(sq_next(v,i-1)))
+        {
+          if (!first) {
+            os << ", ";
+          }
+          first = false;
+
+          //here -1 is the value and -2 is the key
+          os << squirrel2string(v, -2) << " => " 
+             << squirrel2string(v, -1);
+                              
+          sq_pop(v,2); //pops key and val before the nex iteration
+        }
+      sq_pop(v, 1);
+      os << "}";
+      break;
+    }
+    case OT_ARRAY: {
+      bool first = true;
+      os << "[";
+      sq_pushnull(v);  //null iterator
+      while(SQ_SUCCEEDED(sq_next(v,i-1)))
+        {
+          if (!first) {
+            os << ", ";
+          }
+          first = false;
+
+          //here -1 is the value and -2 is the key
+          // we ignore the key, since that is just the index in an array
+          os << squirrel2string(v, -1);
+                              
+          sq_pop(v,2); //pops key and val before the nex iteration
+        }
+      sq_pop(v, 1);
+      os << "]";
+      break;
+    }
+    case OT_USERDATA:
+      os << "<userdata>";
+      break;
+    case OT_CLOSURE:        
+      os << "<closure>";
+      break;
+    case OT_NATIVECLOSURE:
+      os << "<native closure>";
+      break;
+    case OT_GENERATOR:
+      os << "<generator>";
+      break;
+    case OT_USERPOINTER:
+      os << "userpointer";
+      break;
+    case OT_THREAD:
+      os << "<thread>";
+      break;
+    case OT_CLASS:
+      os << "<class>";
+      break;
+    case OT_INSTANCE:
+      os << "<instance>";
+      break;
+    case OT_WEAKREF:
+      os << "<weakref>";
+      break;
+    default:
+      os << "<unknown>";
+      break;
+    }
+  return os.str();
+}
+
+void print_squirrel_stack(HSQUIRRELVM v)
+{
+    printf("--------------------------------------------------------------\n");
+    int count = sq_gettop(v);
+    for(int i = 1; i <= count; ++i) {
+        printf("%d: ",i);
+        switch(sq_gettype(v, i))
+        {
+            case OT_NULL:
+                printf("null");        
+                break;
+            case OT_INTEGER: {
+                int val;
+                sq_getinteger(v, i, &val);
+                printf("integer (%d)", val);
+                break;
+            }
+            case OT_FLOAT: {
+                float val;
+                sq_getfloat(v, i, &val);
+                printf("float (%f)", val);
+                break;
+            }
+            case OT_STRING: {
+                const char* val;
+                sq_getstring(v, i, &val);
+                printf("string (%s)", val);
+                break;    
+            }
+            case OT_TABLE:
+                printf("table");
+                break;
+            case OT_ARRAY:
+                printf("array");
+                break;
+            case OT_USERDATA:
+                printf("userdata");
+                break;
+            case OT_CLOSURE:        
+                printf("closure(function)");    
+                break;
+            case OT_NATIVECLOSURE:
+                printf("native closure(C function)");
+                break;
+            case OT_GENERATOR:
+                printf("generator");
+                break;
+            case OT_USERPOINTER:
+                printf("userpointer");
+                break;
+            case OT_THREAD:
+                printf("thread");
+                break;
+            case OT_CLASS:
+                printf("class");
+                break;
+            case OT_INSTANCE:
+                printf("instance");
+                break;
+            case OT_WEAKREF:
+                printf("weakref");
+                break;
+            default:
+                printf("unknown?!?");
+                break;
+        }
+        printf("\n");
+    }
+    printf("--------------------------------------------------------------\n");
+}
+
+static SQInteger squirrel_read_char(SQUserPointer file)
+{
+  std::istream* in = reinterpret_cast<std::istream*> (file);
+  char c = in->get();
+  if(in->eof())
+    return 0;
+  return c;
+}
+
+void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
+{
+  if(SQ_FAILED(sq_compile(vm, squirrel_read_char, &in, sourcename.c_str(), true)))
+    throw SquirrelError(vm, "Couldn't parse script");  
+}
+
+void compile_and_run(HSQUIRRELVM vm, std::istream& in,
+                     const std::string& sourcename)
+{
+  compile_script(vm, in, sourcename);
+  
+  int oldtop = sq_gettop(vm);
+
+  try {
+    sq_pushroottable(vm);
+    if(SQ_FAILED(sq_call(vm, 1, SQFalse, SQTrue)))
+      throw SquirrelError(vm, "Couldn't start script");
+  } catch(...) {
+    sq_settop(vm, oldtop);
+    throw;
+  }
+
+  // we can remove the closure in case the script was not suspended
+  if(sq_getvmstate(vm) != SQ_VMSTATE_SUSPENDED) {
+    sq_settop(vm, oldtop-1);
+  }
+}
+
+HSQOBJECT create_thread(HSQUIRRELVM vm)
+{
+  HSQUIRRELVM new_vm = sq_newthread(vm, 64);
+  if(new_vm == NULL)
+    throw SquirrelError(vm, "Couldn't create new VM");
+
+  HSQOBJECT vm_object;
+  sq_resetobject(&vm_object);
+  if(SQ_FAILED(sq_getstackobj(vm, -1, &vm_object)))
+    throw SquirrelError(vm, "Couldn't get squirrel thread from stack");
+  sq_addref(vm, &vm_object);
+  
+  sq_pop(vm, 1);
+
+  return vm_object;
+}
+
+HSQOBJECT vm_to_object(HSQUIRRELVM vm)
+{
+  HSQOBJECT object;
+  sq_resetobject(&object);
+  object._unVal.pThread = vm;
+  object._type = OT_THREAD;
+
+  return object;
+}
+
+HSQUIRRELVM object_to_vm(HSQOBJECT object)
+{
+  if(object._type != OT_THREAD)
+    return NULL;
+
+  return object._unVal.pThread;
+}
+
+}
diff --git a/src/scripting/squirrel_util.hpp b/src/scripting/squirrel_util.hpp
new file mode 100644 (file)
index 0000000..f7cbf65
--- /dev/null
@@ -0,0 +1,85 @@
+//  $Id$
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef __SQUIRREL_UTIL_HPP__
+#define __SQUIRREL_UTIL_HPP__
+
+#include <squirrel.h>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include "wrapper.hpp"
+#include "squirrel_error.hpp"
+
+namespace Scripting
+{
+
+  extern HSQUIRRELVM global_vm;
+
+  void init_squirrel(bool enable_debugger);
+  void exit_squirrel();
+  void update_debugger();
+
+  std::string squirrel2string(HSQUIRRELVM vm, int i);
+  void print_squirrel_stack(HSQUIRRELVM vm);
+
+  HSQOBJECT create_thread(HSQUIRRELVM vm);
+  SQObject vm_to_object(HSQUIRRELVM vm); 
+  HSQUIRRELVM object_to_vm(HSQOBJECT object);
+
+  void compile_script(HSQUIRRELVM vm, std::istream& in,
+                      const std::string& sourcename);
+  void compile_and_run(HSQUIRRELVM vm, std::istream& in,
+                       const std::string& sourcename);
+
+  template<typename T>
+  void expose_object(HSQUIRRELVM v, int table_idx, T* object,
+                     const std::string& name, bool free = false)
+  {
+    sq_pushstring(v, name.c_str(), -1);
+    Scripting::create_squirrel_instance(v, object, free);
+
+    if(table_idx < 0)
+      table_idx -= 2;
+
+    // register instance in root table
+    if(SQ_FAILED(sq_createslot(v, table_idx))) {
+      std::ostringstream msg;
+      msg << "Couldn't register object '" << name << "' in squirrel table";
+      throw Scripting::SquirrelError(v, msg.str());
+    }
+  }
+
+  static inline void unexpose_object(HSQUIRRELVM v, int table_idx,
+                                     const std::string& name)
+  {
+    sq_pushstring(v, name.c_str(), name.length());
+    
+    if(table_idx < 0)
+      table_idx -= 1;
+    
+    if(SQ_FAILED(sq_deleteslot(v, table_idx, SQFalse))) {
+      std::ostringstream msg;
+      msg << "Couldn't unregister object '" << name << "' in squirrel root table";
+      throw Scripting::SquirrelError(v, msg.str());
+    }
+  }
+
+}
+
+#endif
diff --git a/src/scripting/thread_queue.cpp b/src/scripting/thread_queue.cpp
new file mode 100644 (file)
index 0000000..100db79
--- /dev/null
@@ -0,0 +1,87 @@
+//  $Id: wrapper_util.cpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#include "thread_queue.hpp"
+#include "squirrel_util.hpp"
+#include "log.hpp"
+
+namespace Scripting
+{
+
+ThreadQueue::ThreadQueue()
+{
+}
+
+ThreadQueue::~ThreadQueue()
+{
+}
+
+void
+ThreadQueue::add(HSQUIRRELVM vm)
+{
+  // create a weakref to the VM
+  HSQOBJECT vm_obj = vm_to_object(vm);
+  sq_pushobject(global_vm, vm_obj);
+  sq_weakref(global_vm, -1);
+
+  HSQOBJECT object;
+  if(SQ_FAILED(sq_getstackobj(global_vm, -1, &object))) {
+    sq_pop(global_vm, 2);
+    throw SquirrelError(global_vm, "Couldn't get thread weakref from vm");
+  }
+  sq_addref(global_vm, &object); 
+  threads.push_back(object);
+
+  sq_pop(global_vm, 2);                  
+}
+
+void
+ThreadQueue::wakeup()
+{
+  // we traverse the list in reverse orders and use indices. This should be
+  // robust for scripts that add new entries to the list while we're traversing
+  // it
+  size_t i = threads.size() - 1;
+  size_t end = (size_t) 0 - 1;
+  size_t size_begin = threads.size();
+  while(i != end) {
+    HSQOBJECT object = threads[i];
+    
+    sq_pushobject(global_vm, object);
+    sq_getweakrefval(global_vm, -1);
+
+    HSQUIRRELVM scheduled_vm;
+    if(sq_gettype(global_vm, -1) == OT_THREAD &&
+            SQ_SUCCEEDED(sq_getthread(global_vm, -1, &scheduled_vm))) {
+      if(SQ_FAILED(sq_wakeupvm(scheduled_vm, SQFalse, SQFalse, SQTrue))) {
+        log_warning << "Couldn't wakeup scheduled squirrel VM" << std::endl;
+      }
+    }
+  
+    sq_release(global_vm, &object);
+    sq_pop(global_vm, 1);
+    i--;
+  }
+
+  threads.erase(threads.begin(), threads.begin() + size_begin);
+}
+
+}
+
diff --git a/src/scripting/thread_queue.hpp b/src/scripting/thread_queue.hpp
new file mode 100644 (file)
index 0000000..f336cd3
--- /dev/null
@@ -0,0 +1,50 @@
+//  $Id: wrapper_util.cpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef __THREAD_QUEUE_HPP__
+#define __THREAD_QUEUE_HPP__
+
+#include <vector>
+#include <squirrel.h>
+
+namespace Scripting
+{
+
+/**
+ * Keeps a list of SquirrelThreads that wait for a wakeup event
+ */
+class ThreadQueue
+{
+public:
+  ThreadQueue();
+  virtual ~ThreadQueue();
+
+  /// adds a thread (actually a weakref to the thread)
+  void add(HSQUIRRELVM vm);
+  /// wakes up threads in the list
+  void wakeup();
+
+private:
+  typedef std::vector<HSQOBJECT> ThreadList;
+  ThreadList threads;
+};
+
+}
+
+#endif
+
diff --git a/src/scripting/time_scheduler.cpp b/src/scripting/time_scheduler.cpp
new file mode 100644 (file)
index 0000000..8310abc
--- /dev/null
@@ -0,0 +1,101 @@
+//  $Id: script_manager.hpp 3379 2006-04-20 18:44:10Z matzebraun $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+//  02111-1307, USA.
+#include <config.h>
+
+#include <algorithm>
+
+#include "time_scheduler.hpp"
+#include "squirrel_util.hpp"
+#include "squirrel_error.hpp"
+#include "log.hpp"
+
+namespace Scripting
+{
+
+TimeScheduler* TimeScheduler::instance = NULL;
+
+TimeScheduler::TimeScheduler()
+{
+}
+
+TimeScheduler::~TimeScheduler()
+{
+}
+
+void
+TimeScheduler::update(float time)
+{
+  while(!schedule.empty() && schedule.front().wakeup_time < time) {
+    HSQOBJECT thread_ref = schedule.front().thread_ref;
+
+    sq_pushobject(global_vm, thread_ref);
+    sq_getweakrefval(global_vm, -1);
+
+    HSQUIRRELVM scheduled_vm;
+    if(sq_gettype(global_vm, -1) == OT_THREAD &&
+        SQ_SUCCEEDED(sq_getthread(global_vm, -1, &scheduled_vm))) {
+      if(SQ_FAILED(sq_wakeupvm(scheduled_vm, SQFalse, SQFalse, SQTrue))) {
+        std::ostringstream msg;
+        msg << "Couldn't wakeup scheduled squirrel VM: ";
+        sq_getlasterror(scheduled_vm);
+        if(sq_gettype(scheduled_vm, -1) != OT_STRING) {
+            msg << "(no info)";
+        } else {
+            const char* lasterr;
+            sq_getstring(scheduled_vm, -1, &lasterr);
+            msg << lasterr;
+        }
+        log_warning << msg.str() << std::endl;
+        sq_pop(scheduled_vm, 1);
+      }
+    }
+
+    sq_release(global_vm, &thread_ref);
+    sq_pop(global_vm, 2);
+
+    pop_heap(schedule.begin(), schedule.end());
+    schedule.pop_back();
+  }
+}
+
+void
+TimeScheduler::schedule_thread(HSQUIRRELVM scheduled_vm, float time)
+{
+  // create a weakref to the VM
+  SQObject vm_obj = vm_to_object(scheduled_vm);
+  sq_pushobject(global_vm, vm_obj);
+  sq_weakref(global_vm, -1);
+
+  ScheduleEntry entry;
+  if(SQ_FAILED(sq_getstackobj(global_vm, -1, & entry.thread_ref))) {
+    sq_pop(global_vm, 2);
+    throw SquirrelError(global_vm, "Couldn't get thread weakref from vm");
+  }
+  entry.wakeup_time = time;
+
+  sq_addref(global_vm, & entry.thread_ref);
+  sq_pop(global_vm, 2);
+
+  schedule.push_back(entry);
+  std::push_heap(schedule.begin(), schedule.end());
+}
+
+}
+
diff --git a/src/scripting/time_scheduler.hpp b/src/scripting/time_scheduler.hpp
new file mode 100644 (file)
index 0000000..05c6569
--- /dev/null
@@ -0,0 +1,65 @@
+//  $Id: script_manager.hpp 3379 2006-04-20 18:44:10Z matzebraun $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+//  02111-1307, USA.
+#ifndef __TIME_SCHEDULER_HPP__
+#define __TIME_SCHEDULER_HPP__
+
+#include <vector>
+#include <squirrel.h>
+
+namespace Scripting
+{
+
+/**
+ * This class keeps a list of squirrel threads that are scheduled for a certain
+ * time. (the typical result of a wait() command in a squirrel script)
+ */
+class TimeScheduler
+{
+public:
+  TimeScheduler();
+  virtual ~TimeScheduler();
+
+  void update(float time);
+  void schedule_thread(HSQUIRRELVM vm, float time);
+
+  static TimeScheduler* instance;
+
+private:
+  struct ScheduleEntry {
+    /// weak reference to the squirrel vm object
+    HSQOBJECT thread_ref;
+    /// time when the thread should be woken up
+    float wakeup_time;
+
+    bool operator<(const ScheduleEntry& other) const
+    {
+      // we need the smallest value on top
+      return wakeup_time > other.wakeup_time;
+    }
+  };
+  
+  typedef std::vector<ScheduleEntry> ScheduleHeap;
+  ScheduleHeap schedule;
+};
+
+}
+
+#endif
+
index 910d6bc..d28de47 100644 (file)
@@ -754,69 +754,6 @@ static int ScriptedObject_get_name_wrapper(HSQUIRRELVM vm)
   
 }
 
-static int Sound_release_hook(SQUserPointer ptr, int )
-{
-  Scripting::Sound* _this = reinterpret_cast<Scripting::Sound*> (ptr);
-  delete _this;
-  return 0;
-}
-
-static int Sound_play_music_wrapper(HSQUIRRELVM vm)
-{
-  Scripting::Sound* _this;
-  if(SQ_FAILED(sq_getinstanceup(vm, 1, reinterpret_cast<SQUserPointer*> (&_this), 0))) {
-    sq_throwerror(vm, _SC("'play_music' called without instance"));
-    return SQ_ERROR;
-  }
-  const char* arg0;
-  if(SQ_FAILED(sq_getstring(vm, 2, &arg0))) {
-    sq_throwerror(vm, _SC("Argument 1 not a string"));
-    return SQ_ERROR;
-  }
-  
-  try {
-    _this->play_music(arg0);
-  
-    return 0;
-  
-  } catch(std::exception& e) {
-    sq_throwerror(vm, e.what());
-    return SQ_ERROR;
-  } catch(...) {
-    sq_throwerror(vm, _SC("Unexpected exception while executing function 'play_music'"));
-    return SQ_ERROR;
-  }
-  
-}
-
-static int Sound_play_wrapper(HSQUIRRELVM vm)
-{
-  Scripting::Sound* _this;
-  if(SQ_FAILED(sq_getinstanceup(vm, 1, reinterpret_cast<SQUserPointer*> (&_this), 0))) {
-    sq_throwerror(vm, _SC("'play' called without instance"));
-    return SQ_ERROR;
-  }
-  const char* arg0;
-  if(SQ_FAILED(sq_getstring(vm, 2, &arg0))) {
-    sq_throwerror(vm, _SC("Argument 1 not a string"));
-    return SQ_ERROR;
-  }
-  
-  try {
-    _this->play(arg0);
-  
-    return 0;
-  
-  } catch(std::exception& e) {
-    sq_throwerror(vm, e.what());
-    return SQ_ERROR;
-  } catch(...) {
-    sq_throwerror(vm, _SC("Unexpected exception while executing function 'play'"));
-    return SQ_ERROR;
-  }
-  
-}
-
 static int Text_release_hook(SQUserPointer ptr, int )
 {
   Scripting::Text* _this = reinterpret_cast<Scripting::Text*> (ptr);
@@ -1851,6 +1788,52 @@ static int debug_draw_solids_only_wrapper(HSQUIRRELVM vm)
   
 }
 
+static int play_music_wrapper(HSQUIRRELVM vm)
+{
+  const char* arg0;
+  if(SQ_FAILED(sq_getstring(vm, 2, &arg0))) {
+    sq_throwerror(vm, _SC("Argument 1 not a string"));
+    return SQ_ERROR;
+  }
+  
+  try {
+    Scripting::play_music(arg0);
+  
+    return 0;
+  
+  } catch(std::exception& e) {
+    sq_throwerror(vm, e.what());
+    return SQ_ERROR;
+  } catch(...) {
+    sq_throwerror(vm, _SC("Unexpected exception while executing function 'play_music'"));
+    return SQ_ERROR;
+  }
+  
+}
+
+static int play_sound_wrapper(HSQUIRRELVM vm)
+{
+  const char* arg0;
+  if(SQ_FAILED(sq_getstring(vm, 2, &arg0))) {
+    sq_throwerror(vm, _SC("Argument 1 not a string"));
+    return SQ_ERROR;
+  }
+  
+  try {
+    Scripting::play_sound(arg0);
+  
+    return 0;
+  
+  } catch(std::exception& e) {
+    sq_throwerror(vm, e.what());
+    return SQ_ERROR;
+  } catch(...) {
+    sq_throwerror(vm, _SC("Unexpected exception while executing function 'play_sound'"));
+    return SQ_ERROR;
+  }
+  
+}
+
 static int grease_wrapper(HSQUIRRELVM vm)
 {
   (void) vm;
@@ -2147,32 +2130,6 @@ void create_squirrel_instance(HSQUIRRELVM v, Scripting::ScriptedObject* object,
   sq_remove(v, -2); // remove root table
 }
 
-void create_squirrel_instance(HSQUIRRELVM v, Scripting::Sound* object, bool setup_releasehook)
-{
-  using namespace Wrapper;
-
-  sq_pushroottable(v);
-  sq_pushstring(v, "Sound", -1);
-  if(SQ_FAILED(sq_get(v, -2))) {
-    std::ostringstream msg;
-    msg << "Couldn't resolved squirrel type 'Sound'";
-    throw SquirrelError(v, msg.str());
-  }
-
-  if(SQ_FAILED(sq_createinstance(v, -1)) || SQ_FAILED(sq_setinstanceup(v, -1, object))) {
-    std::ostringstream msg;
-    msg << "Couldn't setup squirrel instance for object of type 'Sound'";
-    throw SquirrelError(v, msg.str());
-  }
-  sq_remove(v, -2); // remove object name
-
-  if(setup_releasehook) {
-    sq_setreleasehook(v, -1, Sound_release_hook);
-  }
-
-  sq_remove(v, -2); // remove root table
-}
-
 void create_squirrel_instance(HSQUIRRELVM v, Scripting::Text* object, bool setup_releasehook)
 {
   using namespace Wrapper;
@@ -2447,6 +2404,18 @@ void register_supertux_wrapper(HSQUIRRELVM v)
     throw SquirrelError(v, "Couldn't register function 'debug_draw_solids_only'");
   }
 
+  sq_pushstring(v, "play_music", -1);
+  sq_newclosure(v, &play_music_wrapper, 0);
+  if(SQ_FAILED(sq_createslot(v, -3))) {
+    throw SquirrelError(v, "Couldn't register function 'play_music'");
+  }
+
+  sq_pushstring(v, "play_sound", -1);
+  sq_newclosure(v, &play_sound_wrapper, 0);
+  if(SQ_FAILED(sq_createslot(v, -3))) {
+    throw SquirrelError(v, "Couldn't register function 'play_sound'");
+  }
+
   sq_pushstring(v, "grease", -1);
   sq_newclosure(v, &grease_wrapper, 0);
   if(SQ_FAILED(sq_createslot(v, -3))) {
@@ -2701,29 +2670,6 @@ void register_supertux_wrapper(HSQUIRRELVM v)
     throw SquirrelError(v, "Couldn't register class 'ScriptedObject'");
   }
 
-  // Register class Sound
-  sq_pushstring(v, "Sound", -1);
-  if(sq_newclass(v, SQFalse) < 0) {
-    std::ostringstream msg;
-    msg << "Couldn't create new class 'Sound'";
-    throw SquirrelError(v, msg.str());
-  }
-  sq_pushstring(v, "play_music", -1);
-  sq_newclosure(v, &Sound_play_music_wrapper, 0);
-  if(SQ_FAILED(sq_createslot(v, -3))) {
-    throw SquirrelError(v, "Couldn't register function 'play_music'");
-  }
-
-  sq_pushstring(v, "play", -1);
-  sq_newclosure(v, &Sound_play_wrapper, 0);
-  if(SQ_FAILED(sq_createslot(v, -3))) {
-    throw SquirrelError(v, "Couldn't register function 'play'");
-  }
-
-  if(SQ_FAILED(sq_createslot(v, -3))) {
-    throw SquirrelError(v, "Couldn't register class 'Sound'");
-  }
-
   // Register class Text
   sq_pushstring(v, "Text", -1);
   if(sq_newclass(v, SQFalse) < 0) {
index d0b969a..8f55ffc 100644 (file)
@@ -18,7 +18,6 @@ void create_squirrel_instance(HSQUIRRELVM v, Scripting::DisplayEffect* object, b
 void create_squirrel_instance(HSQUIRRELVM v, Scripting::Camera* object, bool setup_releasehook = false);
 void create_squirrel_instance(HSQUIRRELVM v, Scripting::Level* object, bool setup_releasehook = false);
 void create_squirrel_instance(HSQUIRRELVM v, Scripting::ScriptedObject* object, bool setup_releasehook = false);
-void create_squirrel_instance(HSQUIRRELVM v, Scripting::Sound* object, bool setup_releasehook = false);
 void create_squirrel_instance(HSQUIRRELVM v, Scripting::Text* object, bool setup_releasehook = false);
 void create_squirrel_instance(HSQUIRRELVM v, Scripting::Player* object, bool setup_releasehook = false);
 void create_squirrel_instance(HSQUIRRELVM v, Scripting::FloatingImage* object, bool setup_releasehook = false);
index 823db49..14135a8 100644 (file)
@@ -3,7 +3,6 @@
 #include "camera.hpp"
 #include "level.hpp"
 #include "scripted_object.hpp"
-#include "sound.hpp"
 #include "text.hpp"
 #include "functions.hpp"
 #include "player.hpp"
diff --git a/src/scripting/wrapper_util.cpp b/src/scripting/wrapper_util.cpp
deleted file mode 100644 (file)
index a24a5ac..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#include <config.h>
-
-#include <stdexcept>
-#include <sstream>
-#include "wrapper_util.hpp"
-
-namespace Scripting
-{
-
-std::string squirrel2string(HSQUIRRELVM v, int i)
-{
-  std::ostringstream os;
-  switch(sq_gettype(v, i))
-    {
-    case OT_NULL:
-      os << "<null>";        
-      break;
-    case OT_BOOL: {
-      SQBool p;
-      sq_getbool(v, i, &p);
-      if (p) 
-        os << "true";
-      else
-        os << "false";
-      break;
-    }
-    case OT_INTEGER: {
-      int val;
-      sq_getinteger(v, i, &val);
-      os << val;
-      break;
-    }
-    case OT_FLOAT: {
-      float val;
-      sq_getfloat(v, i, &val);
-      os << val;
-      break;
-    }
-    case OT_STRING: {
-      const char* val;
-      sq_getstring(v, i, &val);
-      os << "\"" << val << "\"";
-      break;    
-    }
-    case OT_TABLE: {
-      bool first = true;
-      os << "{";
-      sq_pushnull(v);  //null iterator
-      while(SQ_SUCCEEDED(sq_next(v,i-1)))
-        {
-          if (!first) {
-            os << ", ";
-          }
-          first = false;
-
-          //here -1 is the value and -2 is the key
-          os << squirrel2string(v, -2) << " => " 
-             << squirrel2string(v, -1);
-                              
-          sq_pop(v,2); //pops key and val before the nex iteration
-        }
-      sq_pop(v, 1);
-      os << "}";
-      break;
-    }
-    case OT_ARRAY: {
-      bool first = true;
-      os << "[";
-      sq_pushnull(v);  //null iterator
-      while(SQ_SUCCEEDED(sq_next(v,i-1)))
-        {
-          if (!first) {
-            os << ", ";
-          }
-          first = false;
-
-          //here -1 is the value and -2 is the key
-          // we ignore the key, since that is just the index in an array
-          os << squirrel2string(v, -1);
-                              
-          sq_pop(v,2); //pops key and val before the nex iteration
-        }
-      sq_pop(v, 1);
-      os << "]";
-      break;
-    }
-    case OT_USERDATA:
-      os << "<userdata>";
-      break;
-    case OT_CLOSURE:        
-      os << "<closure (function)>";
-      break;
-    case OT_NATIVECLOSURE:
-      os << "<native closure (C function)>";
-      break;
-    case OT_GENERATOR:
-      os << "<generator>";
-      break;
-    case OT_USERPOINTER:
-      os << "userpointer";
-      break;
-    case OT_THREAD:
-      os << "<thread>";
-      break;
-    case OT_CLASS:
-      os << "<class>";
-      break;
-    case OT_INSTANCE:
-      os << "<instance>";
-      break;
-    default:
-      os << "<unknown>";
-      break;
-    }
-  return os.str();
-}
-
-void print_squirrel_stack(HSQUIRRELVM v)
-{
-    printf("--------------------------------------------------------------\n");
-    int count = sq_gettop(v);
-    for(int i = 1; i <= count; ++i) {
-        printf("%d: ",i);
-        switch(sq_gettype(v, i))
-        {
-            case OT_NULL:
-                printf("null");        
-                break;
-            case OT_INTEGER: {
-                int val;
-                sq_getinteger(v, i, &val);
-                printf("integer (%d)", val);
-                break;
-            }
-            case OT_FLOAT: {
-                float val;
-                sq_getfloat(v, i, &val);
-                printf("float (%f)", val);
-                break;
-            }
-            case OT_STRING: {
-                const char* val;
-                sq_getstring(v, i, &val);
-                printf("string (%s)", val);
-                break;    
-            }
-            case OT_TABLE:
-                printf("table");
-                break;
-            case OT_ARRAY:
-                printf("array");
-                break;
-            case OT_USERDATA:
-                printf("userdata");
-                break;
-            case OT_CLOSURE:        
-                printf("closure(function)");    
-                break;
-            case OT_NATIVECLOSURE:
-                printf("native closure(C function)");
-                break;
-            case OT_GENERATOR:
-                printf("generator");
-                break;
-            case OT_USERPOINTER:
-                printf("userpointer");
-                break;
-            case OT_THREAD:
-                printf("thread");
-                break;
-            case OT_CLASS:
-                printf("class");
-                break;
-            case OT_INSTANCE:
-                printf("instance");
-                break;
-            default:
-                printf("unknown?!?");
-                break;
-        }
-        printf("\n");
-    }
-    printf("--------------------------------------------------------------\n");
-}
-
-static SQInteger squirrel_read_char(SQUserPointer file)
-{
-  std::istream* in = reinterpret_cast<std::istream*> (file);
-  char c = in->get();
-  if(in->eof())
-    return 0;
-  return c;
-}
-
-void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
-{
-  if(SQ_FAILED(sq_compile(vm, squirrel_read_char, &in, sourcename.c_str(), true)))
-    throw SquirrelError(vm, "Couldn't parse script");  
-}
-
-void compile_and_run(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
-{
-  compile_script(vm, in, sourcename);
-  
-  int oldtop = sq_gettop(vm);
-
-  try {
-    sq_pushroottable(vm);
-    if(SQ_FAILED(sq_call(vm, 1, false)))
-      throw SquirrelError(vm, "Couldn't start script");
-  } catch(...) {
-    sq_settop(vm, oldtop);
-    throw;
-  }
-
-  sq_settop(vm, oldtop);
-}
-
-}
diff --git a/src/scripting/wrapper_util.hpp b/src/scripting/wrapper_util.hpp
deleted file mode 100644 (file)
index 2d7d1d9..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#ifndef __WRAPPERUTIL_HPP__
-#define __WRAPPERUTIL_HPP__
-
-#include <squirrel.h>
-#include <sstream>
-#include <stdexcept>
-#include <string>
-#include "wrapper.hpp"
-#include "squirrel_error.hpp"
-
-namespace Scripting
-{
-
-std::string squirrel2string(HSQUIRRELVM vm, int i);
-void print_squirrel_stack(HSQUIRRELVM vm);
-void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename);
-void compile_and_run(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename);
-
-template<typename T>
-void expose_object(HSQUIRRELVM v, int table_idx, T* object,
-                   const std::string& name, bool free = false)
-{
-  sq_pushstring(v, name.c_str(), -1);
-  Scripting::create_squirrel_instance(v, object, free);
-
-  if(table_idx < 0)
-    table_idx -= 2;
-
-  // register instance in root table
-  if(SQ_FAILED(sq_createslot(v, table_idx))) {
-    std::ostringstream msg;
-    msg << "Couldn't register object '" << name << "' in squirrel table";
-    throw Scripting::SquirrelError(v, msg.str());
-  }
-}
-
-static inline void unexpose_object(HSQUIRRELVM v, int table_idx, const std::string& name)
-{
-  sq_pushstring(v, name.c_str(), name.length());
-  
-  if(table_idx < 0)
-    table_idx -= 1;
-  
-  if(SQ_FAILED(sq_deleteslot(v, table_idx, SQFalse))) {
-    std::ostringstream msg;
-    msg << "Couldn't unregister object '" << name << "' in squirrel root table";
-    throw Scripting::SquirrelError(v, msg.str());
-  }
-}
-
-}
-
-#endif
index 1fbbbb0..3a0e229 100644 (file)
@@ -60,8 +60,7 @@
 #include "badguy/jumpy.hpp"
 #include "trigger/sequence_trigger.hpp"
 #include "player_status.hpp"
-#include "script_manager.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "script_interface.hpp"
 #include "log.hpp"
 
@@ -82,29 +81,33 @@ Sector::Sector(Level* parent)
   grid.reset(new CollisionGrid(32000, 32000));
 #endif
 
-  script_manager.reset(new ScriptManager(ScriptManager::instance));
-
   // create a new squirrel table for the sector
-  HSQUIRRELVM vm = ScriptManager::instance->get_vm();
-  
-  sq_newtable(vm);
-  sq_pushroottable(vm);
-  if(SQ_FAILED(sq_setdelegate(vm, -2)))
-    throw Scripting::SquirrelError(vm, "Couldn't set sector_table delegate");
+  using namespace Scripting;
+
+  sq_newtable(global_vm);
+  sq_pushroottable(global_vm);
+  if(SQ_FAILED(sq_setdelegate(global_vm, -2)))
+    throw Scripting::SquirrelError(global_vm, "Couldn't set sector_table delegate");
 
   sq_resetobject(&sector_table);
-  if(SQ_FAILED(sq_getstackobj(vm, -1, &sector_table)))
-    throw Scripting::SquirrelError(vm, "Couldn't get sector table");
-  sq_addref(vm, &sector_table);
-  sq_pop(vm, 1);
+  if(SQ_FAILED(sq_getstackobj(global_vm, -1, &sector_table)))
+    throw Scripting::SquirrelError(global_vm, "Couldn't get sector table");
+  sq_addref(global_vm, &sector_table);
+  sq_pop(global_vm, 1);
 }
 
 Sector::~Sector()
 {
-  deactivate();
+  using namespace Scripting;
   
-  script_manager.reset(NULL);
-  sq_release(ScriptManager::instance->get_vm(), &sector_table);
+  deactivate();
+
+  for(ScriptList::iterator i = scripts.begin();
+      i != scripts.end(); ++i) {
+    HSQOBJECT& object = *i;
+    sq_release(global_vm, &object);
+  }
+  sq_release(global_vm, &sector_table);
  
   update_game_objects();
   assert(gameobjects_new.size() == 0);
@@ -398,14 +401,33 @@ Sector::write(lisp::Writer& writer)
 HSQUIRRELVM
 Sector::run_script(std::istream& in, const std::string& sourcename)
 {
-  // create new thread and keep a weakref
-  HSQUIRRELVM vm = script_manager->create_thread();
+  using namespace Scripting;
+
+  // garbage collect thread list
+  for(ScriptList::iterator i = scripts.begin();
+      i != scripts.end(); ) {
+    HSQOBJECT& object = *i;
+    HSQUIRRELVM vm = object_to_vm(object);
+
+    if(sq_getvmstate(vm) != SQ_VMSTATE_SUSPENDED) {
+      sq_release(global_vm, &object);
+      i = scripts.erase(i);
+      continue;
+    }
+    
+    ++i;
+  }
+  
+  HSQOBJECT object = create_thread(global_vm);
+  scripts.push_back(object);
+
+  HSQUIRRELVM vm = object_to_vm(object);
 
   // set sector_table as roottable for the thread
   sq_pushobject(vm, sector_table);
   sq_setroottable(vm);
 
-  Scripting::compile_and_run(vm, in, sourcename);
+  compile_and_run(vm, in, sourcename);
 
   return vm;
 }
@@ -464,7 +486,7 @@ Sector::activate(const Vector& player_pos)
     _current = this;
 
     // register sectortable as current_sector in scripting
-    HSQUIRRELVM vm = ScriptManager::instance->get_vm();
+    HSQUIRRELVM vm = Scripting::global_vm;
     sq_pushroottable(vm);
     sq_pushstring(vm, "sector", -1);
     sq_pushobject(vm, sector_table);
@@ -498,7 +520,7 @@ Sector::deactivate()
     return;
 
   // remove sector entry from global vm
-  HSQUIRRELVM vm = ScriptManager::instance->get_vm();
+  HSQUIRRELVM vm = Scripting::global_vm;
   sq_pushroottable(vm);
   sq_pushstring(vm, "sector", -1);
   if(SQ_FAILED(sq_deleteslot(vm, -2, SQFalse)))
@@ -526,8 +548,6 @@ Sector::get_active_region()
 void
 Sector::update(float elapsed_time)
 {
-  script_manager->update();
-
   player->check_bounds(camera);
 
 #if 0
@@ -665,7 +685,7 @@ Sector::try_expose(GameObject* object)
 {
   ScriptInterface* interface = dynamic_cast<ScriptInterface*> (object);
   if(interface != NULL) {
-    HSQUIRRELVM vm = script_manager->get_vm();
+    HSQUIRRELVM vm = Scripting::global_vm;
     sq_pushobject(vm, sector_table);
     interface->expose(vm, -1);
     sq_pop(vm, 1);
@@ -684,7 +704,7 @@ Sector::try_unexpose(GameObject* object)
 {
   ScriptInterface* interface = dynamic_cast<ScriptInterface*> (object);
   if(interface != NULL) {
-    HSQUIRRELVM vm = script_manager->get_vm();
+    HSQUIRRELVM vm = Scripting::global_vm;
     int oldtop = sq_gettop(vm);
     sq_pushobject(vm, sector_table);
     try {
index d291c0a..7a97396 100644 (file)
@@ -25,7 +25,6 @@
 #include <squirrel.h>
 
 #include "direction.hpp"
-#include "script_manager.hpp"
 #include "math/vector.hpp"
 #include "video/drawing_context.hpp"
 
@@ -186,7 +185,8 @@ private:
 
   HSQOBJECT sector_table;
   /// sector scripts
-  std::auto_ptr<ScriptManager> script_manager;
+  typedef std::vector<HSQOBJECT> ScriptList;
+  ScriptList scripts;
 
 public: // TODO make this private again
   /// show collision rectangles of moving objects (for debugging)
index 6c7cedb..4d68980 100644 (file)
@@ -27,6 +27,7 @@
 #include "sprite.hpp"
 #include "video/drawing_context.hpp"
 #include "log.hpp"
+#include "timer.hpp"
 
 Sprite::Sprite(SpriteData& newdata)
   : data(newdata), frame(0), animation_loops(-1)
@@ -34,7 +35,7 @@ Sprite::Sprite(SpriteData& newdata)
   action = data.get_action("normal");
   if(!action)
     action = data.actions.begin()->second;
-  last_ticks = SDL_GetTicks();
+  last_ticks = real_time;
 }
 
 Sprite::Sprite(const Sprite& other)
@@ -42,7 +43,7 @@ Sprite::Sprite(const Sprite& other)
     animation_loops(other.animation_loops),
     action(other.action)
 {
-  last_ticks = SDL_GetTicks();
+  last_ticks = real_time;
 }
 
 Sprite::~Sprite()
@@ -78,9 +79,8 @@ Sprite::update()
   if(animation_done())
     return;
 
-  Uint32 ticks = SDL_GetTicks();
-  float frame_inc = action->fps * float(ticks - last_ticks)/1000.0;
-  last_ticks = ticks;
+  float frame_inc = action->fps * (real_time - last_ticks);
+  last_ticks = real_time;
 
   frame += frame_inc;
 
index c8f6cb2..e86a58b 100644 (file)
@@ -91,7 +91,7 @@ private:
 
   float frame;
   int animation_loops;
-  Uint32 last_ticks;
+  float last_ticks;
 
   SpriteData::Action* action;
 };
index 864b4f1..1174201 100644 (file)
@@ -7,7 +7,6 @@
 #define SQSTD_STREAM_TYPE_TAG 0x80000000\r
 \r
 struct SQStream {\r
-       virtual ~SQStream() {}\r
        virtual SQInteger Read(void *buffer, SQInteger size) = 0;\r
        virtual SQInteger Write(void *buffer, SQInteger size) = 0;\r
        virtual SQInteger Flush() = 0;\r
index d301f83..12fb4d5 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-Copyright (c) 2003-2005 Alberto Demichelis\r
+Copyright (c) 2003-2006 Alberto Demichelis\r
 \r
 This software is provided 'as-is', without any \r
 express or implied warranty. In no event will the \r
@@ -39,12 +39,26 @@ extern "C" {
 #define SQUIRREL_API extern\r
 #endif\r
 \r
-typedef float SQFloat;\r
+#ifdef _SQ64\r
+#ifdef _MSC_VER\r
+typedef __int64 SQInteger;\r
+typedef unsigned __int64 SQUnsignedInteger;\r
+typedef unsigned __int64 SQHash; /*should be the same size of a pointer*/\r
+#else\r
+typedef long SQInteger;\r
+typedef unsigned long SQUnsignedInteger;\r
+typedef unsigned long SQHash; /*should be the same size of a pointer*/\r
+#endif\r
+typedef int SQInt32; \r
+#else \r
 typedef int SQInteger;\r
-typedef int SQInt32; //must be 32 bits(also on 64bits processors)\r
-typedef void* SQUserPointer;\r
+typedef int SQInt32; /*must be 32 bits(also on 64bits processors)*/\r
 typedef unsigned int SQUnsignedInteger;\r
-typedef unsigned int SQHash; //should be the same size of a pointer\r
+typedef unsigned int SQHash; /*should be the same size of a pointer*/\r
+#endif\r
+\r
+typedef float SQFloat;\r
+typedef void* SQUserPointer;\r
 typedef SQUnsignedInteger SQBool;\r
 typedef SQInteger SQRESULT;\r
 \r
@@ -71,7 +85,10 @@ struct SQDelegable;
 #endif\r
 \r
 #ifdef SQUNICODE\r
-typedef unsigned short SQChar;\r
+#if defined(wchar_t) //this is if the compiler considers wchar_t as native type\r
+#define wchar_t unsigned short\r
+#endif\r
+typedef wchar_t SQChar;\r
 #define _SC(a) L##a\r
 #define        scstrcmp        wcscmp\r
 #define scsprintf      swprintf\r
@@ -84,6 +101,7 @@ typedef unsigned short SQChar;
 #define scstrstr       wcsstr\r
 #define scisspace      iswspace\r
 #define scisdigit      iswdigit\r
+#define scisxdigit     iswxdigit\r
 #define scisalpha      iswalpha\r
 #define sciscntrl      iswcntrl\r
 #define scisalnum      iswalnum\r
@@ -103,6 +121,7 @@ typedef char SQChar;
 #define scstrstr       strstr\r
 #define scisspace      isspace\r
 #define scisdigit      isdigit\r
+#define scisxdigit     isxdigit\r
 #define sciscntrl      iscntrl\r
 #define scisalpha      isalpha\r
 #define scisalnum      isalnum\r
@@ -110,8 +129,8 @@ typedef char SQChar;
 #define MAX_CHAR 0xFF\r
 #endif\r
 \r
-#define SQUIRREL_VERSION       _SC("Squirrel 2.0.5 stable")\r
-#define SQUIRREL_COPYRIGHT     _SC("Copyright (C) 2003-2005 Alberto Demichelis")\r
+#define SQUIRREL_VERSION       _SC("Squirrel 2.1 stable")\r
+#define SQUIRREL_COPYRIGHT     _SC("Copyright (C) 2003-2006 Alberto Demichelis")\r
 #define SQUIRREL_AUTHOR                _SC("Alberto Demichelis")\r
 \r
 #define SQ_VMSTATE_IDLE                        0\r
@@ -149,7 +168,7 @@ typedef char SQChar;
 #define _RT_INSTANCE           0x00008000\r
 #define _RT_WEAKREF                    0x00010000\r
 \r
-typedef enum {\r
+typedef enum tagSQObjectType{\r
        OT_NULL =                       (_RT_NULL|SQOBJECT_CANBEFALSE),\r
        OT_INTEGER =            (_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE),\r
        OT_FLOAT =                      (_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE),\r
@@ -235,13 +254,14 @@ SQUIRREL_API SQUserPointer sq_getforeignptr(HSQUIRRELVM v);
 SQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc);\r
 SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v);\r
 SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v);\r
-SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval);\r
+SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool raiseerror);\r
 SQUIRREL_API SQInteger sq_getvmstate(HSQUIRRELVM v);\r
 \r
 /*compiler*/\r
 SQUIRREL_API SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror);\r
 SQUIRREL_API SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror);\r
-SQUIRREL_API void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo);\r
+SQUIRREL_API void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable);\r
+SQUIRREL_API void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable);\r
 SQUIRREL_API void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f);\r
 \r
 /*stack operations*/\r
@@ -261,6 +281,7 @@ SQUIRREL_API void sq_newtable(HSQUIRRELVM v);
 SQUIRREL_API void sq_newarray(HSQUIRRELVM v,SQInteger size);\r
 SQUIRREL_API void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars);\r
 SQUIRREL_API SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask);\r
+SQUIRREL_API SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx);\r
 SQUIRREL_API void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len);\r
 SQUIRREL_API void sq_pushfloat(HSQUIRRELVM v,SQFloat f);\r
 SQUIRREL_API void sq_pushinteger(HSQUIRRELVM v,SQInteger n);\r
@@ -269,7 +290,10 @@ SQUIRREL_API void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p);
 SQUIRREL_API void sq_pushnull(HSQUIRRELVM v);\r
 SQUIRREL_API SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx);\r
 SQUIRREL_API SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx);\r
+SQUIRREL_API SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx);\r
+SQUIRREL_API SQBool sq_instanceof(HSQUIRRELVM v);\r
 SQUIRREL_API void sq_tostring(HSQUIRRELVM v,SQInteger idx);\r
+SQUIRREL_API void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b);\r
 SQUIRREL_API SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c);\r
 SQUIRREL_API SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i);\r
 SQUIRREL_API SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f);\r
@@ -291,12 +315,14 @@ SQUIRREL_API SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx);
 SQUIRREL_API SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx);\r
 SQUIRREL_API SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx);\r
 SQUIRREL_API void sq_weakref(HSQUIRRELVM v,SQInteger idx);\r
+SQUIRREL_API SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t);\r
 \r
 /*object manipulation*/\r
 SQUIRREL_API void sq_pushroottable(HSQUIRRELVM v);\r
 SQUIRREL_API void sq_pushregistrytable(HSQUIRRELVM v);\r
 SQUIRREL_API SQRESULT sq_setroottable(HSQUIRRELVM v);\r
-SQUIRREL_API SQRESULT sq_createslot(HSQUIRRELVM v,SQInteger idx);\r
+/*SQUIRREL_API SQRESULT sq_createslot(HSQUIRRELVM v,SQInteger idx);*/\r
+SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic);\r
 SQUIRREL_API SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval);\r
 SQUIRREL_API SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx);\r
 SQUIRREL_API SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx);\r
@@ -315,8 +341,8 @@ SQUIRREL_API SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx);
 SQUIRREL_API SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx);\r
 \r
 /*calls*/\r
-SQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval);\r
-SQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval);\r
+SQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror);\r
+SQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror);\r
 SQUIRREL_API const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx);\r
 SQUIRREL_API const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval);\r
 SQUIRREL_API SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err);\r
@@ -333,6 +359,7 @@ SQUIRREL_API const SQChar *sq_objtostring(HSQOBJECT *o);
 SQUIRREL_API SQBool sq_objtobool(HSQOBJECT *o);\r
 SQUIRREL_API SQInteger sq_objtointeger(HSQOBJECT *o);\r
 SQUIRREL_API SQFloat sq_objtofloat(HSQOBJECT *o);\r
+SQUIRREL_API SQRESULT sq_getobjtypetag(HSQOBJECT *o,SQUserPointer * typetag);\r
 \r
 /*GC*/\r
 SQUIRREL_API SQInteger sq_collectgarbage(HSQUIRRELVM v);\r
@@ -371,6 +398,9 @@ SQUIRREL_API void sq_setdebughook(HSQUIRRELVM v);
 #define sq_isweakref(o) ((o)._type==OT_WEAKREF)\r
 #define sq_type(o) ((o)._type)\r
 \r
+/* deprecated */\r
+#define sq_createslot(v,n) sq_newslot(v,n,SQFalse)\r
+\r
 #define SQ_OK (0)\r
 #define SQ_ERROR (-1)\r
 \r
index 7cdbe99..c76ff0b 100644 (file)
@@ -537,7 +537,7 @@ void SQDbgServer::SerializeState()
                sq_createslot(_v,-3);\r
        }\r
        sq_rawset(_v,-3);\r
-       if(SQ_SUCCEEDED(sq_call(_v,1,SQTrue))){\r
+       if(SQ_SUCCEEDED(sq_call(_v,1,SQTrue,SQTrue))){\r
                if(SQ_SUCCEEDED(sqstd_getblob(_v,-1,(SQUserPointer*)&sz)))\r
                        SendChunk(sz);\r
        }\r
index 30808ed..ddfac08 100644 (file)
@@ -1,6 +1,7 @@
 /* see copyright notice in squirrel.h */\r
 #include <squirrel.h>\r
 #include <sqstdaux.h>\r
+#include <assert.h>\r
 \r
 void sqstd_printcallstack(HSQUIRRELVM v)\r
 {\r
@@ -28,7 +29,7 @@ void sqstd_printcallstack(HSQUIRRELVM v)
 \r
                for(level=0;level<10;level++){\r
                        seq=0;\r
-                       while(name=sq_getlocal(v,level,seq))\r
+                       while((name = sq_getlocal(v,level,seq)))\r
                        {\r
                                seq++;\r
                                switch(sq_gettype(v,-1))\r
@@ -63,6 +64,9 @@ void sqstd_printcallstack(HSQUIRRELVM v)
                                case OT_NATIVECLOSURE:\r
                                        pf(v,_SC("[%s] NATIVECLOSURE\n"),name);\r
                                        break;\r
+                               case OT_GENERATOR:\r
+                                       pf(v,_SC("[%s] NATIVECLOSURE\n"),name);\r
+                                       break;\r
                                case OT_USERDATA:\r
                                        pf(v,_SC("[%s] USERDATA\n"),name);\r
                                        break;\r
@@ -75,6 +79,15 @@ void sqstd_printcallstack(HSQUIRRELVM v)
                                case OT_INSTANCE:\r
                                        pf(v,_SC("[%s] INSTANCE\n"),name);\r
                                        break;\r
+                               case OT_WEAKREF:\r
+                                       pf(v,_SC("[%s] INSTANCE\n"),name);\r
+                                       break;\r
+                               case OT_BOOL:{\r
+                                       sq_getinteger(v,-1,&i);\r
+                                       pf(v,_SC("[%s] %s\n"),name,i?_SC("true"):_SC("false"));\r
+                                                        }\r
+                                       break;\r
+                               default: assert(0); break;\r
                                }\r
                                sq_pop(v,1);\r
                        }\r
index 9b0fe59..5036db1 100644 (file)
@@ -30,7 +30,7 @@ static SQInteger _blob_resize(HSQUIRRELVM v)
 \r
 static void __swap_dword(unsigned int *n)\r
 {\r
-       *n=(SQUnsignedInteger)(((*n&0xFF000000)>>24)  |\r
+       *n=(unsigned int)(((*n&0xFF000000)>>24)  |\r
                        ((*n&0x00FF0000)>>8)  |\r
                        ((*n&0x0000FF00)<<8)  |\r
                        ((*n&0x000000FF)<<24));\r
@@ -182,8 +182,9 @@ static SQInteger _g_blob_swap4(HSQUIRRELVM v)
 {\r
        SQInteger i;\r
        sq_getinteger(v,2,&i);\r
-       __swap_dword((SQUnsignedInteger *)&i);\r
-       sq_pushinteger(v,i);\r
+       unsigned int t4 = (unsigned int)i;\r
+       __swap_dword(&t4);\r
+       sq_pushinteger(v,(SQInteger)t4);\r
        return 1;\r
 }\r
 \r
@@ -191,7 +192,7 @@ static SQInteger _g_blob_swapfloat(HSQUIRRELVM v)
 {\r
        SQFloat f;\r
        sq_getfloat(v,2,&f);\r
-       __swap_dword((SQUnsignedInteger *)&f);\r
+       __swap_dword((unsigned int *)&f);\r
        sq_pushfloat(v,f);\r
        return 1;\r
 }\r
@@ -233,7 +234,7 @@ SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size)
                sq_push(v,1); // push the this\r
                sq_pushinteger(v,size); //size\r
                SQBlob *blob = NULL;\r
-               if(SQ_SUCCEEDED(sq_call(v,2,SQTrue))\r
+               if(SQ_SUCCEEDED(sq_call(v,2,SQTrue,SQFalse))\r
                        && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) {\r
                        sq_remove(v,-2);\r
                        sq_remove(v,-2);\r
index b927e7c..b2291b7 100644 (file)
@@ -12,7 +12,7 @@ struct SQBlob : public SQStream
                _ptr = 0;\r
                _owns = true;\r
        }\r
-       ~SQBlob() {\r
+       virtual ~SQBlob() {\r
                sq_free(_buf, _allocated);\r
        }\r
        SQInteger Write(void *buffer, SQInteger size) {\r
index 396d222..306cf12 100644 (file)
@@ -35,7 +35,7 @@ SQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin)
                case SQ_SEEK_SET: realorigin = SEEK_SET; break;\r
                default: return -1; //failed\r
        }\r
-       return fseek((FILE *)file,offset,realorigin);\r
+       return fseek((FILE *)file,(long)offset,(int)realorigin);\r
 }\r
 \r
 SQInteger sqstd_ftell(SQFILE file)\r
@@ -62,10 +62,10 @@ SQInteger sqstd_feof(SQFILE file)
 struct SQFile : public SQStream {\r
        SQFile() { _handle = NULL; _owns = false;}\r
        SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;}\r
-       ~SQFile() { Close(); }\r
+       virtual ~SQFile() { Close(); }\r
        bool Open(const SQChar *filename ,const SQChar *mode) {\r
                Close();\r
-               if(_handle = sqstd_fopen(filename,mode)) {\r
+               if( (_handle = sqstd_fopen(filename,mode)) ) {\r
                        _owns = true;\r
                        return true;\r
                }\r
@@ -172,7 +172,7 @@ SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own)
                else{\r
                        sq_pushnull(v); //false\r
                }\r
-               if(SQ_SUCCEEDED( sq_call(v,3,SQTrue) )) {\r
+               if(SQ_SUCCEEDED( sq_call(v,3,SQTrue,SQFalse) )) {\r
                        sq_remove(v,-2);\r
                        return SQ_OK;\r
                }\r
@@ -326,8 +326,7 @@ SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool
 {\r
        if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) {\r
                sq_push(v,-2);\r
-               SQInteger ntop = sq_gettop(v);\r
-               if(SQ_SUCCEEDED(sq_call(v,1,retval))) {\r
+               if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) {\r
                        sq_remove(v,retval?-2:-1); //removes the closure\r
                        return 1;\r
                }\r
@@ -361,6 +360,15 @@ SQInteger _g_io_loadfile(HSQUIRRELVM v)
        return SQ_ERROR; //propagates the error\r
 }\r
 \r
+SQInteger _g_io_writeclosuretofile(HSQUIRRELVM v)\r
+{\r
+       const SQChar *filename;\r
+       sq_getstring(v,2,&filename);\r
+       if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,filename)))\r
+               return 1;\r
+       return SQ_ERROR; //propagates the error\r
+}\r
+\r
 SQInteger _g_io_dofile(HSQUIRRELVM v)\r
 {\r
        const SQChar *filename;\r
@@ -379,6 +387,7 @@ SQInteger _g_io_dofile(HSQUIRRELVM v)
 static SQRegFunction iolib_funcs[]={\r
        _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")),\r
        _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")),\r
+       _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(".sc")),\r
        {0,0}\r
 };\r
 \r
index 3d90ee9..ae1a219 100644 (file)
@@ -23,7 +23,7 @@ static SQInteger math_srand(HSQUIRRELVM v)
 {\r
        SQInteger i;\r
        if(!sq_getinteger(v,2,&i))return sq_throwerror(v,_SC("invalid param"));\r
-       srand(i);\r
+       srand((unsigned int)i);\r
        return 0;\r
 }\r
 \r
@@ -37,7 +37,7 @@ static SQInteger math_abs(HSQUIRRELVM v)
 {\r
        SQInteger n;\r
        sq_getinteger(v,2,&n);\r
-       sq_pushinteger(v,(SQInteger)abs(n)); \r
+       sq_pushinteger(v,(SQInteger)abs((int)n)); \r
        return 1; \r
 }\r
 \r
diff --git a/src/squirrel/sqstdlib/sqstdrex.c b/src/squirrel/sqstdlib/sqstdrex.c
deleted file mode 100644 (file)
index e37a58c..0000000
+++ /dev/null
@@ -1,586 +0,0 @@
-/* see copyright notice in squirrel.h */\r
-#include <squirrel.h>\r
-#include <string.h>\r
-#include <ctype.h>\r
-#include <setjmp.h>\r
-#include "sqstdstring.h"\r
-\r
-#ifdef _DEBUG\r
-#include <stdio.h>\r
-\r
-static const SQChar *g_nnames[] =\r
-{\r
-       _SC("NONE"),_SC("OP_GREEDY"),   _SC("OP_OR"),\r
-       _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"),       _SC("OP_CLASS"),\r
-       _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),\r
-       _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")\r
-};\r
-\r
-#endif\r
-\r
-#define OP_GREEDY              MAX_CHAR+1 // * + ? {n}\r
-#define OP_OR                  MAX_CHAR+2\r
-#define OP_EXPR                        MAX_CHAR+3 //parentesis ()\r
-#define OP_NOCAPEXPR   MAX_CHAR+4 //parentesis (?:)\r
-#define OP_DOT                 MAX_CHAR+5\r
-#define OP_CLASS               MAX_CHAR+6\r
-#define OP_CCLASS              MAX_CHAR+7\r
-#define OP_NCLASS              MAX_CHAR+8 //negates class the [^\r
-#define OP_RANGE               MAX_CHAR+9\r
-#define OP_CHAR                        MAX_CHAR+10\r
-#define OP_EOL                 MAX_CHAR+11\r
-#define OP_BOL                 MAX_CHAR+12\r
-#define OP_WB                  MAX_CHAR+13\r
-\r
-#define SQREX_SYMBOL_ANY_CHAR '.'\r
-#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE '+'\r
-#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE '*'\r
-#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE '?'\r
-#define SQREX_SYMBOL_BRANCH '|'\r
-#define SQREX_SYMBOL_END_OF_STRING '$'\r
-#define SQREX_SYMBOL_BEGINNING_OF_STRING '^'\r
-#define SQREX_SYMBOL_ESCAPE_CHAR '\\'\r
-\r
-\r
-typedef int SQRexNodeType;\r
-\r
-typedef struct tagSQRexNode{\r
-       SQRexNodeType type;\r
-       SQInteger left;\r
-       SQInteger right;\r
-       SQInteger next;\r
-}SQRexNode;\r
-\r
-struct SQRex{\r
-       const SQChar *_eol;\r
-       const SQChar *_bol;\r
-       const SQChar *_p;\r
-       SQInteger _first;\r
-       SQInteger _op;\r
-       SQRexNode *_nodes;\r
-       SQInteger _nallocated;\r
-       SQInteger _nsize;\r
-       SQInteger _nsubexpr;\r
-       SQRexMatch *_matches;\r
-       SQInteger _currsubexp;\r
-       void *_jmpbuf;\r
-       const SQChar **_error;\r
-};\r
-\r
-static SQInteger sqstd_rex_list(SQRex *exp);\r
-\r
-static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type)\r
-{\r
-       SQRexNode n;\r
-       n.type = type;\r
-       n.next = n.right = n.left = -1;\r
-       if(type == OP_EXPR)\r
-               n.right = exp->_nsubexpr++;\r
-       if(exp->_nallocated < (exp->_nsize + 1)) {\r
-               SQInteger oldsize = exp->_nallocated;\r
-               exp->_nallocated *= 2;\r
-               exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode));\r
-       }\r
-       exp->_nodes[exp->_nsize++] = n;\r
-       return (SQInteger)exp->_nsize - 1;\r
-}\r
-\r
-static void sqstd_rex_error(SQRex *exp,const SQChar *error)\r
-{\r
-       if(exp->_error) *exp->_error = error;\r
-       longjmp(*((jmp_buf*)exp->_jmpbuf),-1);\r
-}\r
-\r
-static void sqstd_rex_expect(SQRex *exp, SQInteger n){\r
-       if((*exp->_p) != n) \r
-               sqstd_rex_error(exp, _SC("expected paren"));\r
-       exp->_p++;\r
-}\r
-\r
-static SQBool sqstd_rex_ischar(SQChar c)\r
-{\r
-       switch(c) {\r
-       case SQREX_SYMBOL_BRANCH:case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE:\r
-       case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE:case SQREX_SYMBOL_GREEDY_ONE_OR_MORE:\r
-       case SQREX_SYMBOL_BEGINNING_OF_STRING:case SQREX_SYMBOL_END_OF_STRING:\r
-       case SQREX_SYMBOL_ANY_CHAR:case SQREX_SYMBOL_ESCAPE_CHAR:case '(':case ')':case '[':case '{': case '}':\r
-               return SQFalse;\r
-    }\r
-       return SQTrue;\r
-}\r
-\r
-static SQChar sqstd_rex_escapechar(SQRex *exp)\r
-{\r
-       if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){\r
-               exp->_p++;\r
-               switch(*exp->_p) {\r
-               case 'v': exp->_p++; return '\v';\r
-               case 'n': exp->_p++; return '\n';\r
-               case 't': exp->_p++; return '\t';\r
-               case 'r': exp->_p++; return '\r';\r
-               case 'f': exp->_p++; return '\f';\r
-               default: return (*exp->_p++);\r
-               }\r
-       } else if(!sqstd_rex_ischar(*exp->_p)) sqstd_rex_error(exp,_SC("letter expected"));\r
-       return (*exp->_p++);\r
-}\r
-\r
-static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid)\r
-{\r
-       SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS);\r
-       exp->_nodes[n].left = classid;\r
-       return n;\r
-}\r
-\r
-static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass)\r
-{\r
-       if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) {\r
-               exp->_p++;\r
-               switch(*exp->_p) {\r
-                       case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n');\r
-                       case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t');\r
-                       case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r');\r
-                       case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f');\r
-                       case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v');\r
-                       case 'a': case 'A': case 'w': case 'W': case 's': case 'S': \r
-                       case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': \r
-                       case 'p': case 'P': case 'l': case 'u': \r
-                               {\r
-                               SQChar t = *exp->_p;\r
-                               exp->_p++; \r
-                               return sqstd_rex_charclass(exp,t);\r
-                               }\r
-                       case 'b': \r
-                       case 'B':\r
-                               if(!isclass) {\r
-                                       SQInteger node = sqstd_rex_newnode(exp,OP_WB);\r
-                                       exp->_nodes[node].left = *exp->_p;\r
-                                       exp->_p++; \r
-                                       return node;\r
-                               } //else default\r
-                       default: return sqstd_rex_newnode(exp,(*exp->_p++));\r
-               }\r
-       }\r
-       else if(!sqstd_rex_ischar(*exp->_p)) {\r
-               \r
-               sqstd_rex_error(exp,_SC("letter expected"));\r
-       }\r
-       return sqstd_rex_newnode(exp,*exp->_p++);\r
-}\r
-static SQInteger sqstd_rex_class(SQRex *exp)\r
-{\r
-       SQInteger ret = -1;\r
-       SQInteger first = -1,chain;\r
-       if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){\r
-               ret = sqstd_rex_newnode(exp,OP_NCLASS);\r
-               exp->_p++;\r
-       }else ret = sqstd_rex_newnode(exp,OP_CLASS);\r
-       \r
-       if(*exp->_p == ']' || *exp->_p == '-'){\r
-               first = *exp->_p;\r
-               exp->_p++;\r
-       }\r
-       chain = ret;\r
-       while(*exp->_p != ']' && exp->_p != exp->_eol) {\r
-               if(*exp->_p == '-' && first != -1){ \r
-                       SQInteger r;\r
-                       if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range"));\r
-                       r = sqstd_rex_newnode(exp,OP_RANGE);\r
-                       if(first>*exp->_p) sqstd_rex_error(exp,_SC("invalid range"));\r
-                       if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC("cannot use character classes in ranges"));\r
-                       exp->_nodes[r].left = exp->_nodes[first].type;\r
-                       exp->_nodes[r].right = sqstd_rex_escapechar(exp);\r
-            exp->_nodes[chain].next = r;\r
-                       chain = r;\r
-                       first = -1;\r
-               }\r
-               else{\r
-                       if(first!=-1){\r
-                               SQInteger c = first;\r
-                               exp->_nodes[chain].next = c;\r
-                               chain = c;\r
-                               first = sqstd_rex_charnode(exp,SQTrue);\r
-                       }\r
-                       else{\r
-                               first = sqstd_rex_charnode(exp,SQTrue);\r
-                       }\r
-               }\r
-       }\r
-       if(first!=-1){\r
-               SQInteger c = first;\r
-               exp->_nodes[chain].next = c;\r
-               chain = c;\r
-               first = -1;\r
-       }\r
-       /* hack? */\r
-       exp->_nodes[ret].left = exp->_nodes[ret].next;\r
-       exp->_nodes[ret].next = -1;\r
-       return ret;\r
-}\r
-\r
-static SQInteger sqstd_rex_parsenumber(SQRex *exp)\r
-{\r
-       SQInteger ret = *exp->_p-'0';\r
-       SQInteger positions = 10;\r
-       exp->_p++;\r
-       while(isdigit(*exp->_p)) {\r
-               ret = ret*10+(*exp->_p++-'0');\r
-               if(positions==1000000000) sqstd_rex_error(exp,_SC("overflow in numeric constant"));\r
-               positions *= 10;\r
-       };\r
-       return ret;\r
-}\r
-\r
-static SQInteger sqstd_rex_element(SQRex *exp)\r
-{\r
-       SQInteger ret;\r
-       switch(*exp->_p)\r
-       {\r
-       case '(': {\r
-               SQInteger expr;\r
-               exp->_p++;\r
-               \r
-               \r
-               if(*exp->_p =='?') {\r
-                       exp->_p++;\r
-                       sqstd_rex_expect(exp,':');\r
-                       expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR);\r
-               }\r
-               else\r
-                       expr = sqstd_rex_newnode(exp,OP_EXPR);\r
-               exp->_nodes[expr].left = sqstd_rex_list(exp);\r
-               ret = expr;\r
-               sqstd_rex_expect(exp,')');\r
-       }\r
-               break;\r
-       case '[':\r
-               exp->_p++;\r
-               ret = sqstd_rex_class(exp);\r
-               sqstd_rex_expect(exp,']');\r
-               break;\r
-       case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break;\r
-       case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break;\r
-       default:\r
-               ret = sqstd_rex_charnode(exp,SQFalse);\r
-               break;\r
-       }\r
-       /* scope block */\r
-       {\r
-               SQInteger op;\r
-               unsigned short p0 = 0, p1 = 0;\r
-               switch(*exp->_p){\r
-               case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; goto __end;\r
-               case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; goto __end;\r
-               case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; goto __end;\r
-               case '{':{\r
-                       exp->_p++;\r
-                       if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC("number expected"));\r
-                       p0 = sqstd_rex_parsenumber(exp);\r
-                       switch(*exp->_p) {\r
-                       case '}':\r
-                               p1 = p0; exp->_p++;\r
-                               goto __end;\r
-                       case ',':\r
-                               exp->_p++;\r
-                               p1 = 0xFFFF;\r
-                               if(isdigit(*exp->_p)){\r
-                                       p1 = sqstd_rex_parsenumber(exp);\r
-                               }\r
-                               sqstd_rex_expect(exp,'}');\r
-                               goto __end;\r
-                       default:\r
-                               sqstd_rex_error(exp,_SC(", or } expected"));\r
-                       }\r
-               }\r
-               __end: {\r
-                               SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY);\r
-                               op = OP_GREEDY;\r
-                               exp->_nodes[nnode].left = ret;\r
-                               exp->_nodes[nnode].right = ((p0)<<16)|p1;\r
-                               ret = nnode;\r
-                       }\r
-               }\r
-       }\r
-       if(*exp->_p != SQREX_SYMBOL_BRANCH && *exp->_p != ')' && *exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE && *exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE && *exp->_p != '\0')\r
-               exp->_nodes[ret].next = sqstd_rex_element(exp);\r
-       return ret;\r
-}\r
-\r
-static SQInteger sqstd_rex_list(SQRex *exp)\r
-{\r
-       SQInteger ret=-1,e;\r
-       if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) {\r
-               exp->_p++;\r
-               ret = sqstd_rex_newnode(exp,OP_BOL);\r
-       }\r
-       e = sqstd_rex_element(exp);\r
-       if(ret != -1) {\r
-               exp->_nodes[ret].next = e;\r
-       }\r
-       else ret = e;\r
-\r
-       if(*exp->_p == SQREX_SYMBOL_BRANCH) {\r
-               SQInteger temp;\r
-               exp->_p++;\r
-               temp = sqstd_rex_newnode(exp,OP_OR);\r
-               exp->_nodes[temp].left = ret;\r
-               exp->_nodes[temp].right = sqstd_rex_list(exp);\r
-               ret = temp;\r
-       }\r
-       return ret;\r
-}\r
-\r
-static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c)\r
-{\r
-       switch(cclass) {\r
-       case 'a': return isalpha(c)?SQTrue:SQFalse;\r
-       case 'A': return !isalpha(c)?SQTrue:SQFalse;\r
-       case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse;\r
-       case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse;\r
-       case 's': return isspace(c)?SQTrue:SQFalse;\r
-       case 'S': return !isspace(c)?SQTrue:SQFalse;\r
-       case 'd': return isdigit(c)?SQTrue:SQFalse;\r
-       case 'D': return !isdigit(c)?SQTrue:SQFalse;\r
-       case 'x': return isxdigit(c)?SQTrue:SQFalse;\r
-       case 'X': return !isxdigit(c)?SQTrue:SQFalse;\r
-       case 'c': return iscntrl(c)?SQTrue:SQFalse;\r
-       case 'C': return !iscntrl(c)?SQTrue:SQFalse;\r
-       case 'p': return ispunct(c)?SQTrue:SQFalse;\r
-       case 'P': return !ispunct(c)?SQTrue:SQFalse;\r
-       case 'l': return islower(c)?SQTrue:SQFalse;\r
-       case 'u': return isupper(c)?SQTrue:SQFalse;\r
-       }\r
-       return SQFalse; /*cannot happen*/\r
-}\r
-\r
-static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQChar c)\r
-{\r
-       do {\r
-               switch(node->type) {\r
-                       case OP_RANGE:\r
-                               if(c >= node->left && c <= node->right) return SQTrue;\r
-                               break;\r
-                       case OP_CCLASS:\r
-                               if(sqstd_rex_matchcclass(node->left,c)) return SQTrue;\r
-                               break;\r
-                       default:\r
-                               if(c == node->type)return SQTrue;\r
-               }\r
-       } while((node->next != -1) && (node = &exp->_nodes[node->next]));\r
-       return SQFalse;\r
-}\r
-\r
-static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str)\r
-{\r
-       SQRexNodeType type = node->type;\r
-       switch(type) {\r
-       case OP_GREEDY: {\r
-               SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;\r
-               const SQChar *s=str, *good = str;\r
-               while((nmaches == 0xFFFF || nmaches < p1) \r
-                       && (s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s))) {\r
-                       good=s;\r
-                       nmaches++;\r
-                       if(s >= exp->_eol)\r
-                               break;\r
-               }\r
-               if(p0 == p1 && p0 == nmaches) return good;\r
-               else if(nmaches >= p0 && p1 == 0xFFFF) return good;\r
-               else if(nmaches >= p0 && nmaches <= p1) return good;\r
-               return NULL;\r
-       }\r
-       case OP_OR: {\r
-                       const SQChar *asd = str;\r
-                       SQRexNode *temp=&exp->_nodes[node->left];\r
-                       while(asd = sqstd_rex_matchnode(exp,temp,asd)) {\r
-                               if(temp->next != -1)\r
-                                       temp = &exp->_nodes[temp->next];\r
-                               else\r
-                                       return asd;\r
-                       }\r
-                       asd = str;\r
-                       temp = &exp->_nodes[node->right];\r
-                       while(asd = sqstd_rex_matchnode(exp,temp,asd)) {\r
-                               if(temp->next != -1)\r
-                                       temp = &exp->_nodes[temp->next];\r
-                               else\r
-                                       return asd;\r
-                       }\r
-                       return NULL;\r
-                       break;\r
-       }\r
-       case OP_EXPR:\r
-       case OP_NOCAPEXPR:{\r
-                       SQRexNode *n = &exp->_nodes[node->left];\r
-                       const SQChar *cur = str;\r
-                       SQInteger capture = -1;\r
-                       if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {\r
-                               capture = exp->_currsubexp;\r
-                               exp->_matches[capture].begin = cur;\r
-                               exp->_currsubexp++;\r
-                       }\r
-\r
-                       do {\r
-                               if(!(cur = sqstd_rex_matchnode(exp,n,cur))) {\r
-                                       if(capture != -1){\r
-                                               exp->_matches[capture].begin = 0;\r
-                                               exp->_matches[capture].len = 0;\r
-                                       }\r
-                                       return NULL;\r
-                               }\r
-                       } while((n->next != -1) && (n = &exp->_nodes[n->next]));\r
-\r
-                       if(capture != -1) \r
-                               exp->_matches[capture].len = cur - exp->_matches[capture].begin;\r
-                       return cur;\r
-       }                                \r
-       case OP_WB:\r
-               if(str == exp->_bol && !isspace(*str)\r
-                || (str == exp->_eol && !isspace(*(str-1)))\r
-                || (!isspace(*str) && isspace(*(str+1)))\r
-                || (isspace(*str) && !isspace(*(str+1))) ) {\r
-                       return (node->left == 'b')?str:NULL;\r
-               }\r
-               return (node->left == 'b')?NULL:str;\r
-       case OP_BOL:\r
-               if(str == exp->_bol) return str;\r
-               return NULL;\r
-       case OP_EOL:\r
-               if(str == exp->_eol) return str;\r
-               return NULL;\r
-       case OP_DOT:\r
-               *str++;\r
-               return str;\r
-       case OP_NCLASS:\r
-       case OP_CLASS:\r
-               if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) {\r
-                       *str++;\r
-                       return str;\r
-               }\r
-               return NULL;\r
-       case OP_CCLASS:\r
-               if(sqstd_rex_matchcclass(node->left,*str)) {\r
-                       *str++;\r
-                       return str;\r
-               }\r
-               return NULL;\r
-       default: /* char */\r
-               if(*str != node->type) return NULL;\r
-               *str++;\r
-               return str;\r
-       }\r
-       return NULL;\r
-}\r
-\r
-/* public api */\r
-SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error)\r
-{\r
-       SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex));\r
-       exp->_p = pattern;\r
-       exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar);\r
-       exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode));\r
-       exp->_nsize = 0;\r
-       exp->_matches = 0;\r
-       exp->_nsubexpr = 0;\r
-       exp->_first = sqstd_rex_newnode(exp,OP_EXPR);\r
-       exp->_error = error;\r
-       exp->_jmpbuf = sq_malloc(sizeof(jmp_buf));\r
-       if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {\r
-               exp->_nodes[exp->_first].left=sqstd_rex_list(exp);\r
-               if(*exp->_p!='\0')\r
-                       sqstd_rex_error(exp,_SC("unexpected character"));\r
-#ifdef _DEBUG\r
-               {\r
-                       SQInteger nsize,i;\r
-                       SQRexNode *t;\r
-                       nsize = exp->_nsize;\r
-                       t = &exp->_nodes[0];\r
-                       scprintf(_SC("\n"));\r
-                       for(i = 0;i < nsize; i++) {\r
-                               if(exp->_nodes[i].type>MAX_CHAR)\r
-                                       scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);\r
-                               else\r
-                                       scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);\r
-                               scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);\r
-                       }\r
-                       scprintf(_SC("\n"));\r
-               }\r
-#endif\r
-               exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch));\r
-               memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch));\r
-       }\r
-       else{\r
-               sqstd_rex_free(exp);\r
-               return NULL;\r
-       }\r
-       return exp;\r
-}\r
-\r
-void sqstd_rex_free(SQRex *exp)\r
-{\r
-       if(exp) {\r
-               if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode));\r
-               if(exp->_jmpbuf) sq_free(exp->_jmpbuf,sizeof(jmp_buf));\r
-               if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch));\r
-               sq_free(exp,sizeof(SQRex));\r
-       }\r
-}\r
-\r
-SQBool sqstd_rex_match(SQRex* exp,const SQChar* text)\r
-{\r
-       const SQChar* res = NULL;\r
-       exp->_bol = text;\r
-       exp->_eol = text + scstrlen(text);\r
-       exp->_currsubexp = 0;\r
-       res = sqstd_rex_matchnode(exp,exp->_nodes,text);\r
-       if(res == NULL || res != exp->_eol)\r
-               return SQFalse;\r
-       return SQTrue;\r
-}\r
-\r
-SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end)\r
-{\r
-       const SQChar *cur = NULL;\r
-       SQInteger node = exp->_first;\r
-       if(text_begin >= text_end) return SQFalse;\r
-       exp->_bol = text_begin;\r
-       exp->_eol = text_end;\r
-       do {\r
-               cur = text_begin;\r
-               while(node != -1) {\r
-                       exp->_currsubexp = 0;\r
-                       cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur);\r
-                       if(!cur)\r
-                               break;\r
-                       node = exp->_nodes[node].next;\r
-               }\r
-               *text_begin++;\r
-       } while(cur == NULL && text_begin != text_end);\r
-\r
-       if(cur == NULL)\r
-               return SQFalse;\r
-\r
-       --text_begin;\r
-\r
-       if(out_begin) *out_begin = text_begin;\r
-       if(out_end) *out_end = cur;\r
-       return SQTrue;\r
-}\r
-\r
-SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end)\r
-{\r
-       return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);\r
-}\r
-\r
-SQInteger sqstd_rex_getsubexpcount(SQRex* exp)\r
-{\r
-       return exp->_nsubexpr;\r
-}\r
-\r
-SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp)\r
-{\r
-       if( n<0 || n >= exp->_nsubexpr) return SQFalse;\r
-       *subexp = exp->_matches[n];\r
-       return SQTrue;\r
-}\r
-\r
diff --git a/src/squirrel/sqstdlib/sqstdrex.cpp b/src/squirrel/sqstdlib/sqstdrex.cpp
new file mode 100644 (file)
index 0000000..9c3c268
--- /dev/null
@@ -0,0 +1,633 @@
+/* see copyright notice in squirrel.h */\r
+#include <squirrel.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <setjmp.h>\r
+#include "sqstdstring.h"\r
+\r
+#ifdef _UINCODE\r
+#define scisprint iswprint\r
+#else\r
+#define scisprint isprint\r
+#endif\r
+\r
+#ifdef _DEBUG\r
+#include <stdio.h>\r
+\r
+static const SQChar *g_nnames[] =\r
+{\r
+       _SC("NONE"),_SC("OP_GREEDY"),   _SC("OP_OR"),\r
+       _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"),       _SC("OP_CLASS"),\r
+       _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),\r
+       _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")\r
+};\r
+\r
+#endif\r
+\r
+#define OP_GREEDY              MAX_CHAR+1 // * + ? {n}\r
+#define OP_OR                  MAX_CHAR+2\r
+#define OP_EXPR                        MAX_CHAR+3 //parentesis ()\r
+#define OP_NOCAPEXPR   MAX_CHAR+4 //parentesis (?:)\r
+#define OP_DOT                 MAX_CHAR+5\r
+#define OP_CLASS               MAX_CHAR+6\r
+#define OP_CCLASS              MAX_CHAR+7\r
+#define OP_NCLASS              MAX_CHAR+8 //negates class the [^\r
+#define OP_RANGE               MAX_CHAR+9\r
+#define OP_CHAR                        MAX_CHAR+10\r
+#define OP_EOL                 MAX_CHAR+11\r
+#define OP_BOL                 MAX_CHAR+12\r
+#define OP_WB                  MAX_CHAR+13\r
+\r
+#define SQREX_SYMBOL_ANY_CHAR '.'\r
+#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE '+'\r
+#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE '*'\r
+#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE '?'\r
+#define SQREX_SYMBOL_BRANCH '|'\r
+#define SQREX_SYMBOL_END_OF_STRING '$'\r
+#define SQREX_SYMBOL_BEGINNING_OF_STRING '^'\r
+#define SQREX_SYMBOL_ESCAPE_CHAR '\\'\r
+\r
+\r
+typedef int SQRexNodeType;\r
+\r
+typedef struct tagSQRexNode{\r
+       SQRexNodeType type;\r
+       SQInteger left;\r
+       SQInteger right;\r
+       SQInteger next;\r
+}SQRexNode;\r
+\r
+struct SQRex{\r
+       const SQChar *_eol;\r
+       const SQChar *_bol;\r
+       const SQChar *_p;\r
+       SQInteger _first;\r
+       SQInteger _op;\r
+       SQRexNode *_nodes;\r
+       SQInteger _nallocated;\r
+       SQInteger _nsize;\r
+       SQInteger _nsubexpr;\r
+       SQRexMatch *_matches;\r
+       SQInteger _currsubexp;\r
+       void *_jmpbuf;\r
+       const SQChar **_error;\r
+};\r
+\r
+static SQInteger sqstd_rex_list(SQRex *exp);\r
+\r
+static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type)\r
+{\r
+       SQRexNode n;\r
+       n.type = type;\r
+       n.next = n.right = n.left = -1;\r
+       if(type == OP_EXPR)\r
+               n.right = exp->_nsubexpr++;\r
+       if(exp->_nallocated < (exp->_nsize + 1)) {\r
+               SQInteger oldsize = exp->_nallocated;\r
+               exp->_nallocated *= 2;\r
+               exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode));\r
+       }\r
+       exp->_nodes[exp->_nsize++] = n;\r
+       return (SQInteger)exp->_nsize - 1;\r
+}\r
+\r
+static void sqstd_rex_error(SQRex *exp,const SQChar *error)\r
+{\r
+       if(exp->_error) *exp->_error = error;\r
+       longjmp(*((jmp_buf*)exp->_jmpbuf),-1);\r
+}\r
+\r
+static void sqstd_rex_expect(SQRex *exp, SQInteger n){\r
+       if((*exp->_p) != n) \r
+               sqstd_rex_error(exp, _SC("expected paren"));\r
+       exp->_p++;\r
+}\r
+\r
+/*static SQBool sqstd_rex_ischar(SQChar c)\r
+{\r
+       switch(c) {\r
+       case SQREX_SYMBOL_BRANCH:case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE:\r
+       case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE:case SQREX_SYMBOL_GREEDY_ONE_OR_MORE:\r
+       case SQREX_SYMBOL_BEGINNING_OF_STRING:case SQREX_SYMBOL_END_OF_STRING:\r
+       case SQREX_SYMBOL_ANY_CHAR:case SQREX_SYMBOL_ESCAPE_CHAR:case '(':case ')':case '[':case '{': case '}':\r
+               return SQFalse;\r
+    }\r
+       return SQTrue;\r
+}*/\r
+\r
+static SQChar sqstd_rex_escapechar(SQRex *exp)\r
+{\r
+       if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){\r
+               exp->_p++;\r
+               switch(*exp->_p) {\r
+               case 'v': exp->_p++; return '\v';\r
+               case 'n': exp->_p++; return '\n';\r
+               case 't': exp->_p++; return '\t';\r
+               case 'r': exp->_p++; return '\r';\r
+               case 'f': exp->_p++; return '\f';\r
+               default: return (*exp->_p++);\r
+               }\r
+       } else if(!scisprint(*exp->_p)) sqstd_rex_error(exp,_SC("letter expected"));\r
+       return (*exp->_p++);\r
+}\r
+\r
+static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid)\r
+{\r
+       SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS);\r
+       exp->_nodes[n].left = classid;\r
+       return n;\r
+}\r
+\r
+static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass)\r
+{\r
+       if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) {\r
+               exp->_p++;\r
+               switch(*exp->_p) {\r
+                       case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n');\r
+                       case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t');\r
+                       case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r');\r
+                       case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f');\r
+                       case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v');\r
+                       case 'a': case 'A': case 'w': case 'W': case 's': case 'S': \r
+                       case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': \r
+                       case 'p': case 'P': case 'l': case 'u': \r
+                               {\r
+                               SQChar t = *exp->_p;\r
+                               exp->_p++; \r
+                               return sqstd_rex_charclass(exp,t);\r
+                               }\r
+                       case 'b': \r
+                       case 'B':\r
+                               if(!isclass) {\r
+                                       SQInteger node = sqstd_rex_newnode(exp,OP_WB);\r
+                                       exp->_nodes[node].left = *exp->_p;\r
+                                       exp->_p++; \r
+                                       return node;\r
+                               } //else default\r
+                       default: return sqstd_rex_newnode(exp,(*exp->_p++));\r
+               }\r
+       }\r
+       else if(!scisprint(*exp->_p)) {\r
+               \r
+               sqstd_rex_error(exp,_SC("letter expected"));\r
+       }\r
+       return sqstd_rex_newnode(exp,*exp->_p++);\r
+}\r
+static SQInteger sqstd_rex_class(SQRex *exp)\r
+{\r
+       SQInteger ret = -1;\r
+       SQInteger first = -1,chain;\r
+       if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){\r
+               ret = sqstd_rex_newnode(exp,OP_NCLASS);\r
+               exp->_p++;\r
+       }else ret = sqstd_rex_newnode(exp,OP_CLASS);\r
+       \r
+       if(*exp->_p == ']') sqstd_rex_error(exp,_SC("empty class"));\r
+       chain = ret;\r
+       while(*exp->_p != ']' && exp->_p != exp->_eol) {\r
+               if(*exp->_p == '-' && first != -1){ \r
+                       SQInteger r;\r
+                       if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range"));\r
+                       r = sqstd_rex_newnode(exp,OP_RANGE);\r
+                       if(first>*exp->_p) sqstd_rex_error(exp,_SC("invalid range"));\r
+                       if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC("cannot use character classes in ranges"));\r
+                       exp->_nodes[r].left = exp->_nodes[first].type;\r
+                       exp->_nodes[r].right = sqstd_rex_escapechar(exp);\r
+            exp->_nodes[chain].next = r;\r
+                       chain = r;\r
+                       first = -1;\r
+               }\r
+               else{\r
+                       if(first!=-1){\r
+                               SQInteger c = first;\r
+                               exp->_nodes[chain].next = c;\r
+                               chain = c;\r
+                               first = sqstd_rex_charnode(exp,SQTrue);\r
+                       }\r
+                       else{\r
+                               first = sqstd_rex_charnode(exp,SQTrue);\r
+                       }\r
+               }\r
+       }\r
+       if(first!=-1){\r
+               SQInteger c = first;\r
+               exp->_nodes[chain].next = c;\r
+               chain = c;\r
+               first = -1;\r
+       }\r
+       /* hack? */\r
+       exp->_nodes[ret].left = exp->_nodes[ret].next;\r
+       exp->_nodes[ret].next = -1;\r
+       return ret;\r
+}\r
+\r
+static SQInteger sqstd_rex_parsenumber(SQRex *exp)\r
+{\r
+       SQInteger ret = *exp->_p-'0';\r
+       SQInteger positions = 10;\r
+       exp->_p++;\r
+       while(isdigit(*exp->_p)) {\r
+               ret = ret*10+(*exp->_p++-'0');\r
+               if(positions==1000000000) sqstd_rex_error(exp,_SC("overflow in numeric constant"));\r
+               positions *= 10;\r
+       };\r
+       return ret;\r
+}\r
+\r
+static SQInteger sqstd_rex_element(SQRex *exp)\r
+{\r
+       SQInteger ret;\r
+       switch(*exp->_p)\r
+       {\r
+       case '(': {\r
+               SQInteger expr;\r
+               exp->_p++;\r
+               \r
+               \r
+               if(*exp->_p =='?') {\r
+                       exp->_p++;\r
+                       sqstd_rex_expect(exp,':');\r
+                       expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR);\r
+               }\r
+               else\r
+                       expr = sqstd_rex_newnode(exp,OP_EXPR);\r
+               exp->_nodes[expr].left = sqstd_rex_list(exp);\r
+               ret = expr;\r
+               sqstd_rex_expect(exp,')');\r
+       }\r
+               break;\r
+       case '[':\r
+               exp->_p++;\r
+               ret = sqstd_rex_class(exp);\r
+               sqstd_rex_expect(exp,']');\r
+               break;\r
+       case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break;\r
+       case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break;\r
+       default:\r
+               ret = sqstd_rex_charnode(exp,SQFalse);\r
+               break;\r
+       }\r
+       /* scope block */\r
+       {\r
+               SQInteger op;\r
+               unsigned short p0 = 0, p1 = 0;\r
+               switch(*exp->_p){\r
+               case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; goto __end;\r
+               case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; goto __end;\r
+               case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; goto __end;\r
+               case '{':{\r
+                       exp->_p++;\r
+                       if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC("number expected"));\r
+                       p0 = (unsigned short)sqstd_rex_parsenumber(exp);\r
+                       switch(*exp->_p) {\r
+                       case '}':\r
+                               p1 = p0; exp->_p++;\r
+                               goto __end;\r
+                       case ',':\r
+                               exp->_p++;\r
+                               p1 = 0xFFFF;\r
+                               if(isdigit(*exp->_p)){\r
+                                       p1 = (unsigned short)sqstd_rex_parsenumber(exp);\r
+                               }\r
+                               sqstd_rex_expect(exp,'}');\r
+                               goto __end;\r
+                       default:\r
+                               sqstd_rex_error(exp,_SC(", or } expected"));\r
+                       }\r
+               }\r
+               __end: {\r
+                               SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY);\r
+                               op = OP_GREEDY;\r
+                               exp->_nodes[nnode].left = ret;\r
+                               exp->_nodes[nnode].right = ((p0)<<16)|p1;\r
+                               ret = nnode;\r
+                       }\r
+               }\r
+       }\r
+       if(*exp->_p != SQREX_SYMBOL_BRANCH && *exp->_p != ')' && *exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE && *exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE && *exp->_p != '\0')\r
+               exp->_nodes[ret].next = sqstd_rex_element(exp);\r
+       return ret;\r
+}\r
+\r
+static SQInteger sqstd_rex_list(SQRex *exp)\r
+{\r
+       SQInteger ret=-1,e;\r
+       if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) {\r
+               exp->_p++;\r
+               ret = sqstd_rex_newnode(exp,OP_BOL);\r
+       }\r
+       e = sqstd_rex_element(exp);\r
+       if(ret != -1) {\r
+               exp->_nodes[ret].next = e;\r
+       }\r
+       else ret = e;\r
+\r
+       if(*exp->_p == SQREX_SYMBOL_BRANCH) {\r
+               SQInteger temp;\r
+               exp->_p++;\r
+               temp = sqstd_rex_newnode(exp,OP_OR);\r
+               exp->_nodes[temp].left = ret;\r
+               exp->_nodes[temp].right = sqstd_rex_list(exp);\r
+               ret = temp;\r
+       }\r
+       return ret;\r
+}\r
+\r
+static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c)\r
+{\r
+       switch(cclass) {\r
+       case 'a': return isalpha(c)?SQTrue:SQFalse;\r
+       case 'A': return !isalpha(c)?SQTrue:SQFalse;\r
+       case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse;\r
+       case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse;\r
+       case 's': return isspace(c)?SQTrue:SQFalse;\r
+       case 'S': return !isspace(c)?SQTrue:SQFalse;\r
+       case 'd': return isdigit(c)?SQTrue:SQFalse;\r
+       case 'D': return !isdigit(c)?SQTrue:SQFalse;\r
+       case 'x': return isxdigit(c)?SQTrue:SQFalse;\r
+       case 'X': return !isxdigit(c)?SQTrue:SQFalse;\r
+       case 'c': return iscntrl(c)?SQTrue:SQFalse;\r
+       case 'C': return !iscntrl(c)?SQTrue:SQFalse;\r
+       case 'p': return ispunct(c)?SQTrue:SQFalse;\r
+       case 'P': return !ispunct(c)?SQTrue:SQFalse;\r
+       case 'l': return islower(c)?SQTrue:SQFalse;\r
+       case 'u': return isupper(c)?SQTrue:SQFalse;\r
+       }\r
+       return SQFalse; /*cannot happen*/\r
+}\r
+\r
+static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQChar c)\r
+{\r
+       do {\r
+               switch(node->type) {\r
+                       case OP_RANGE:\r
+                               if(c >= node->left && c <= node->right) return SQTrue;\r
+                               break;\r
+                       case OP_CCLASS:\r
+                               if(sqstd_rex_matchcclass(node->left,c)) return SQTrue;\r
+                               break;\r
+                       default:\r
+                               if(c == node->type)return SQTrue;\r
+               }\r
+       } while((node->next != -1) && (node = &exp->_nodes[node->next]));\r
+       return SQFalse;\r
+}\r
+\r
+static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str,SQRexNode *next)\r
+{\r
+       \r
+       SQRexNodeType type = node->type;\r
+       switch(type) {\r
+       case OP_GREEDY: {\r
+               //SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;\r
+               SQRexNode *greedystop = NULL;\r
+               SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;\r
+               const SQChar *s=str, *good = str;\r
+\r
+               if(node->next != -1) {\r
+                       greedystop = &exp->_nodes[node->next];\r
+               }\r
+               else {\r
+                       greedystop = next;\r
+               }\r
+\r
+               while((nmaches == 0xFFFF || nmaches < p1)) {\r
+\r
+                       const SQChar *stop;\r
+                       if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))\r
+                               break;\r
+                       nmaches++;\r
+                       good=s;\r
+                       if(greedystop) {\r
+                               //checks that 0 matches satisfy the expression(if so skips)\r
+                               //if not would always stop(for instance if is a '?')\r
+                               if(greedystop->type != OP_GREEDY ||\r
+                               (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))\r
+                               {\r
+                                       SQRexNode *gnext = NULL;\r
+                                       if(greedystop->next != -1) {\r
+                                               gnext = &exp->_nodes[greedystop->next];\r
+                                       }else if(next && next->next != -1){\r
+                                               gnext = &exp->_nodes[next->next];\r
+                                       }\r
+                                       stop = sqstd_rex_matchnode(exp,greedystop,s,gnext);\r
+                                       if(stop) {\r
+                                               //if satisfied stop it\r
+                                               if(p0 == p1 && p0 == nmaches) break;\r
+                                               else if(nmaches >= p0 && p1 == 0xFFFF) break;\r
+                                               else if(nmaches >= p0 && nmaches <= p1) break;\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       if(s >= exp->_eol)\r
+                               break;\r
+               }\r
+               if(p0 == p1 && p0 == nmaches) return good;\r
+               else if(nmaches >= p0 && p1 == 0xFFFF) return good;\r
+               else if(nmaches >= p0 && nmaches <= p1) return good;\r
+               return NULL;\r
+       }\r
+       case OP_OR: {\r
+                       const SQChar *asd = str;\r
+                       SQRexNode *temp=&exp->_nodes[node->left];\r
+                       while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {\r
+                               if(temp->next != -1)\r
+                                       temp = &exp->_nodes[temp->next];\r
+                               else\r
+                                       return asd;\r
+                       }\r
+                       asd = str;\r
+                       temp = &exp->_nodes[node->right];\r
+                       while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {\r
+                               if(temp->next != -1)\r
+                                       temp = &exp->_nodes[temp->next];\r
+                               else\r
+                                       return asd;\r
+                       }\r
+                       return NULL;\r
+                       break;\r
+       }\r
+       case OP_EXPR:\r
+       case OP_NOCAPEXPR:{\r
+                       SQRexNode *n = &exp->_nodes[node->left];\r
+                       const SQChar *cur = str;\r
+                       SQInteger capture = -1;\r
+                       if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {\r
+                               capture = exp->_currsubexp;\r
+                               exp->_matches[capture].begin = cur;\r
+                               exp->_currsubexp++;\r
+                       }\r
+                       \r
+                       do {\r
+                               SQRexNode *subnext = NULL;\r
+                               if(n->next != -1) {\r
+                                       subnext = &exp->_nodes[n->next];\r
+                               }else {\r
+                                       subnext = next;\r
+                               }\r
+                               if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) {\r
+                                       if(capture != -1){\r
+                                               exp->_matches[capture].begin = 0;\r
+                                               exp->_matches[capture].len = 0;\r
+                                       }\r
+                                       return NULL;\r
+                               }\r
+                       } while((n->next != -1) && (n = &exp->_nodes[n->next]));\r
+\r
+                       if(capture != -1) \r
+                               exp->_matches[capture].len = cur - exp->_matches[capture].begin;\r
+                       return cur;\r
+       }                                \r
+       case OP_WB:\r
+               if(str == exp->_bol && !isspace(*str)\r
+                || (str == exp->_eol && !isspace(*(str-1)))\r
+                || (!isspace(*str) && isspace(*(str+1)))\r
+                || (isspace(*str) && !isspace(*(str+1))) ) {\r
+                       return (node->left == 'b')?str:NULL;\r
+               }\r
+               return (node->left == 'b')?NULL:str;\r
+       case OP_BOL:\r
+               if(str == exp->_bol) return str;\r
+               return NULL;\r
+       case OP_EOL:\r
+               if(str == exp->_eol) return str;\r
+               return NULL;\r
+       case OP_DOT:{\r
+               *str++;\r
+                               }\r
+               return str;\r
+       case OP_NCLASS:\r
+       case OP_CLASS:\r
+               if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) {\r
+                       *str++;\r
+                       return str;\r
+               }\r
+               return NULL;\r
+       case OP_CCLASS:\r
+               if(sqstd_rex_matchcclass(node->left,*str)) {\r
+                       *str++;\r
+                       return str;\r
+               }\r
+               return NULL;\r
+       default: /* char */\r
+               if(*str != node->type) return NULL;\r
+               *str++;\r
+               return str;\r
+       }\r
+       return NULL;\r
+}\r
+\r
+/* public api */\r
+SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error)\r
+{\r
+       SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex));\r
+       exp->_eol = exp->_bol = NULL;\r
+       exp->_p = pattern;\r
+       exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar);\r
+       exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode));\r
+       exp->_nsize = 0;\r
+       exp->_matches = 0;\r
+       exp->_nsubexpr = 0;\r
+       exp->_first = sqstd_rex_newnode(exp,OP_EXPR);\r
+       exp->_error = error;\r
+       exp->_jmpbuf = sq_malloc(sizeof(jmp_buf));\r
+       if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {\r
+               exp->_nodes[exp->_first].left=sqstd_rex_list(exp);\r
+               if(*exp->_p!='\0')\r
+                       sqstd_rex_error(exp,_SC("unexpected character"));\r
+#ifdef _DEBUG\r
+               {\r
+                       SQInteger nsize,i;\r
+                       SQRexNode *t;\r
+                       nsize = exp->_nsize;\r
+                       t = &exp->_nodes[0];\r
+                       scprintf(_SC("\n"));\r
+                       for(i = 0;i < nsize; i++) {\r
+                               if(exp->_nodes[i].type>MAX_CHAR)\r
+                                       scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);\r
+                               else\r
+                                       scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);\r
+                               scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);\r
+                       }\r
+                       scprintf(_SC("\n"));\r
+               }\r
+#endif\r
+               exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch));\r
+               memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch));\r
+       }\r
+       else{\r
+               sqstd_rex_free(exp);\r
+               return NULL;\r
+       }\r
+       return exp;\r
+}\r
+\r
+void sqstd_rex_free(SQRex *exp)\r
+{\r
+       if(exp) {\r
+               if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode));\r
+               if(exp->_jmpbuf) sq_free(exp->_jmpbuf,sizeof(jmp_buf));\r
+               if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch));\r
+               sq_free(exp,sizeof(SQRex));\r
+       }\r
+}\r
+\r
+SQBool sqstd_rex_match(SQRex* exp,const SQChar* text)\r
+{\r
+       const SQChar* res = NULL;\r
+       exp->_bol = text;\r
+       exp->_eol = text + scstrlen(text);\r
+       exp->_currsubexp = 0;\r
+       res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL);\r
+       if(res == NULL || res != exp->_eol)\r
+               return SQFalse;\r
+       return SQTrue;\r
+}\r
+\r
+SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end)\r
+{\r
+       const SQChar *cur = NULL;\r
+       SQInteger node = exp->_first;\r
+       if(text_begin >= text_end) return SQFalse;\r
+       exp->_bol = text_begin;\r
+       exp->_eol = text_end;\r
+       do {\r
+               cur = text_begin;\r
+               while(node != -1) {\r
+                       exp->_currsubexp = 0;\r
+                       cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL);\r
+                       if(!cur)\r
+                               break;\r
+                       node = exp->_nodes[node].next;\r
+               }\r
+               *text_begin++;\r
+       } while(cur == NULL && text_begin != text_end);\r
+\r
+       if(cur == NULL)\r
+               return SQFalse;\r
+\r
+       --text_begin;\r
+\r
+       if(out_begin) *out_begin = text_begin;\r
+       if(out_end) *out_end = cur;\r
+       return SQTrue;\r
+}\r
+\r
+SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end)\r
+{\r
+       return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);\r
+}\r
+\r
+SQInteger sqstd_rex_getsubexpcount(SQRex* exp)\r
+{\r
+       return exp->_nsubexpr;\r
+}\r
+\r
+SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp)\r
+{\r
+       if( n<0 || n >= exp->_nsubexpr) return SQFalse;\r
+       *subexp = exp->_matches[n];\r
+       return SQTrue;\r
+}\r
+\r
index a02c022..669ca23 100644 (file)
        if(!self->IsValid())  \\r
                return sq_throwerror(v,_SC("the stream is invalid"));\r
 \r
-SQInteger _stream_readstr(HSQUIRRELVM v)\r
-{\r
-    SETUP_STREAM(v);\r
-       SQInteger type = _SC('a'), size = 0;\r
-       sq_getinteger(v, 2, &size);\r
-       if(size <= 0) return sq_throwerror(v,_SC("invalid size"));\r
-       if(sq_gettop(v) > 2)\r
-               sq_getinteger(v, 3, &type);\r
-       SQChar *dest = NULL;\r
-       switch(type) {\r
-       case _SC('a'): {\r
-               char *temp;\r
-               if(self->Read(sq_getscratchpad(v, size+1), size) != size)\r
-                       return sq_throwerror(v, _SC("io failure"));\r
-#ifdef _UNICODE\r
-               temp = (char*) sq_getscratchpad(v, size + (size * sizeof(SQChar)));\r
-               dest = (SQChar*) &temp[size];\r
-               size = (SQInteger)mbstowcs(dest, (const char*)temp, size);\r
-#else\r
-               temp = (char *) sq_getscratchpad(v, -1);\r
-               dest = temp;\r
-#endif\r
-                                  }\r
-               break;\r
-       case _SC('u'): {\r
-               wchar_t *temp;\r
-               if(self->Read(sq_getscratchpad(v, (size + 1) * sizeof(wchar_t)),size * sizeof(wchar_t)) != (size * sizeof(wchar_t)))\r
-                       return sq_throwerror(v, _SC("io failure"));\r
-               \r
-#ifdef _UNICODE\r
-               temp = (wchar_t*) sq_getscratchpad(v, -1);\r
-               dest = (SQChar*) temp;\r
-#else\r
-               temp = (wchar_t*) sq_getscratchpad(v,(size * 3) + (size * sizeof(wchar_t)));\r
-               dest = (char*) &temp[size];\r
-               size = (SQInteger)wcstombs(dest, (const wchar_t*)temp, size);\r
-#endif\r
-                                  }\r
-               break;\r
-       default:\r
-               return sq_throwerror(v, _SC("invalid coding"));\r
-       }\r
-\r
-       sq_pushstring(v, dest, size);\r
-       return 1;\r
-}\r
-\r
 SQInteger _stream_readblob(HSQUIRRELVM v)\r
 {\r
        SETUP_STREAM(v);\r
@@ -90,12 +43,18 @@ SQInteger _stream_readn(HSQUIRRELVM v)
        SQInteger format;\r
        sq_getinteger(v, 2, &format);\r
        switch(format) {\r
-       case 'i': {\r
+       case 'l': {\r
                SQInteger i;\r
                SAFE_READN(&i, sizeof(i));\r
                sq_pushinteger(v, i);\r
                          }\r
                break;\r
+       case 'i': {\r
+               SQInt32 i;\r
+               SAFE_READN(&i, sizeof(i));\r
+               sq_pushinteger(v, i);\r
+                         }\r
+               break;\r
        case 's': {\r
                short s;\r
                SAFE_READN(&s, sizeof(short));\r
@@ -138,42 +97,6 @@ SQInteger _stream_readn(HSQUIRRELVM v)
        return 1;\r
 }\r
 \r
-SQInteger _stream_writestr(HSQUIRRELVM v)\r
-{\r
-       SETUP_STREAM(v);\r
-       const SQChar *str,*res;\r
-       SQInteger trgformat = 'a',len = 0;\r
-       sq_getstring(v,2,&str);\r
-       len = sq_getsize(v,2);\r
-       if(sq_gettop(v)>2)\r
-               sq_getinteger(v,3,&trgformat);\r
-       switch(trgformat)\r
-       {\r
-       case 'a':\r
-#ifdef _UNICODE\r
-               res = sq_getscratchpad(v,len*3);\r
-               len = (SQInteger) wcstombs((char *)res, (const wchar_t*)str, len);\r
-#else\r
-               res = str;\r
-#endif\r
-               self->Write((void *)res,len);\r
-               break;\r
-       case 'u':\r
-#ifdef _UNICODE\r
-               res = str;\r
-#else\r
-               res = sq_getscratchpad(v,len*sizeof(wchar_t));\r
-               len = (SQInteger) mbstowcs((wchar_t*)res, str, len);\r
-#endif\r
-               self->Write((void *)res,len*sizeof(wchar_t));\r
-               break;\r
-       default:\r
-               return sq_throwerror(v,_SC("wrong encoding"));\r
-       }\r
-       \r
-       return 0;\r
-}\r
-\r
 SQInteger _stream_writeblob(HSQUIRRELVM v)\r
 {\r
        SQUserPointer data;\r
@@ -195,38 +118,45 @@ SQInteger _stream_writen(HSQUIRRELVM v)
        SQFloat tf;\r
        sq_getinteger(v, 3, &format);\r
        switch(format) {\r
-       case 'i': {\r
+       case 'l': {\r
                SQInteger i;\r
                sq_getinteger(v, 2, &ti);\r
                i = ti;\r
                self->Write(&i, sizeof(SQInteger));\r
                          }\r
                break;\r
+       case 'i': {\r
+               SQInt32 i;\r
+               sq_getinteger(v, 2, &ti);\r
+               i = (SQInt32)ti;\r
+               self->Write(&i, sizeof(SQInt32));\r
+                         }\r
+               break;\r
        case 's': {\r
                short s;\r
                sq_getinteger(v, 2, &ti);\r
-               s = ti;\r
+               s = (short)ti;\r
                self->Write(&s, sizeof(short));\r
                          }\r
                break;\r
        case 'w': {\r
                unsigned short w;\r
                sq_getinteger(v, 2, &ti);\r
-               w = ti;\r
+               w = (unsigned short)ti;\r
                self->Write(&w, sizeof(unsigned short));\r
                          }\r
                break;\r
        case 'c': {\r
                char c;\r
                sq_getinteger(v, 2, &ti);\r
-               c = ti;\r
+               c = (char)ti;\r
                self->Write(&c, sizeof(char));\r
                                  }\r
                break;\r
        case 'b': {\r
                unsigned char b;\r
                sq_getinteger(v, 2, &ti);\r
-               b = ti;\r
+               b = (unsigned char)ti;\r
                self->Write(&b, sizeof(unsigned char));\r
                          }\r
                break;\r
@@ -304,10 +234,8 @@ SQInteger _stream_eos(HSQUIRRELVM v)
 }\r
 \r
 static SQRegFunction _stream_methods[] = {\r
-       _DECL_STREAM_FUNC(readstr,-2,_SC("xnn")),\r
        _DECL_STREAM_FUNC(readblob,2,_SC("xn")),\r
        _DECL_STREAM_FUNC(readn,2,_SC("xn")),\r
-       _DECL_STREAM_FUNC(writestr,-2,_SC("xsn")),\r
        _DECL_STREAM_FUNC(writeblob,-2,_SC("xx")),\r
        _DECL_STREAM_FUNC(writen,3,_SC("xnn")),\r
        _DECL_STREAM_FUNC(seek,-2,_SC("xnn")),\r
@@ -336,6 +264,12 @@ void init_streamclass(HSQUIRRELVM v)
                        i++;\r
                }\r
                sq_createslot(v,-3);\r
+               sq_pushroottable(v);\r
+               sq_pushstring(v,_SC("stream"),-1);\r
+               sq_pushstring(v,_SC("std_stream"),-1);\r
+               sq_get(v,-4);\r
+               sq_createslot(v,-3);\r
+               sq_pop(v,1);\r
        }\r
        else {\r
                sq_pop(v,1); //result\r
index d08fc4c..6f562da 100644 (file)
@@ -2,11 +2,9 @@
 #ifndef _SQSTD_STREAM_H_\r
 #define _SQSTD_STREAM_H_\r
 \r
-SQInteger _stream_readstr(HSQUIRRELVM v);\r
 SQInteger _stream_readblob(HSQUIRRELVM v);\r
 SQInteger _stream_readline(HSQUIRRELVM v);\r
 SQInteger _stream_readn(HSQUIRRELVM v);\r
-SQInteger _stream_writestr(HSQUIRRELVM v);\r
 SQInteger _stream_writeblob(HSQUIRRELVM v);\r
 SQInteger _stream_writen(HSQUIRRELVM v);\r
 SQInteger _stream_seek(HSQUIRRELVM v);\r
index 81fc7c2..832f3aa 100644 (file)
 #define scstrchr wcschr\r
 #define scsnprintf wsnprintf\r
 #define scatoi _wtoi\r
+#define scstrtok wcstok\r
 #else\r
 #define scstrchr strchr\r
 #define scsnprintf snprintf\r
 #define scatoi atoi\r
+#define scstrtok strtok\r
 #endif\r
 #define MAX_FORMAT_LEN 20\r
 #define MAX_WFORMAT_LEN        3\r
@@ -71,7 +73,7 @@ static SQInteger _string_format(HSQUIRRELVM v)
        sq_getstring(v,2,&format);\r
        SQInteger allocated = (sq_getsize(v,2)+1)*sizeof(SQChar);\r
        dest = sq_getscratchpad(v,allocated);\r
-       SQInteger n = 0,i = 0, nparam = 3, w;\r
+       SQInteger n = 0,i = 0, nparam = 3, w = 0;\r
        while(format[n] != '\0') {\r
                if(format[n] != '%') {\r
                        assert(i < allocated);\r
@@ -116,8 +118,7 @@ static SQInteger _string_format(HSQUIRRELVM v)
                                return sq_throwerror(v,_SC("invalid format"));\r
                        }\r
                        n++;\r
-                       if((allocated-i) < addlen)\r
-                               allocated += addlen;\r
+                       allocated += addlen;\r
                        dest = sq_getscratchpad(v,allocated);\r
                        switch(valtype) {\r
                        case 's': i += scsprintf(&dest[i],fmt,ts); break;\r
@@ -131,6 +132,74 @@ static SQInteger _string_format(HSQUIRRELVM v)
        return 1;\r
 }\r
 \r
+static void __strip_l(const SQChar *str,const SQChar **start)\r
+{\r
+       const SQChar *t = str;\r
+       while(((*t) != '\0') && scisspace(*t)){ t++; }\r
+       *start = t;\r
+}\r
+\r
+static void __strip_r(const SQChar *str,SQInteger len,const SQChar **end)\r
+{\r
+       if(len == 0) {\r
+               *end = str;\r
+               return;\r
+       }\r
+       const SQChar *t = &str[len-1];\r
+       while(t != str && scisspace(*t)) { t--; }\r
+       *end = t+1;\r
+}\r
+\r
+static SQInteger _string_strip(HSQUIRRELVM v)\r
+{\r
+       const SQChar *str,*start,*end;\r
+       sq_getstring(v,2,&str);\r
+       SQInteger len = sq_getsize(v,2);\r
+       __strip_l(str,&start);\r
+       __strip_r(str,len,&end);\r
+       sq_pushstring(v,start,end - start);\r
+       return 1;\r
+}\r
+\r
+static SQInteger _string_lstrip(HSQUIRRELVM v)\r
+{\r
+       const SQChar *str,*start;\r
+       sq_getstring(v,2,&str);\r
+       __strip_l(str,&start);\r
+       sq_pushstring(v,start,-1);\r
+       return 1;\r
+}\r
+\r
+static SQInteger _string_rstrip(HSQUIRRELVM v)\r
+{\r
+       const SQChar *str,*end;\r
+       sq_getstring(v,2,&str);\r
+       SQInteger len = sq_getsize(v,2);\r
+       __strip_r(str,len,&end);\r
+       sq_pushstring(v,str,end - str);\r
+       return 1;\r
+}\r
+\r
+static SQInteger _string_split(HSQUIRRELVM v)\r
+{\r
+       const SQChar *str,*seps;\r
+       SQChar *stemp,*tok;\r
+       sq_getstring(v,2,&str);\r
+       sq_getstring(v,3,&seps);\r
+       if(sq_getsize(v,3) == 0) return sq_throwerror(v,_SC("empty separators string"));\r
+       SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar);\r
+       stemp = sq_getscratchpad(v,memsize);\r
+       memcpy(stemp,str,memsize);\r
+       tok = scstrtok(stemp,seps);\r
+       sq_newarray(v,0);\r
+       while( tok != NULL ) {\r
+               sq_pushstring(v,tok,-1);\r
+               sq_arrayappend(v,-2);\r
+               tok = scstrtok( NULL, seps );\r
+       }\r
+       return 1;\r
+}\r
+\r
 #define SETUP_REX(v) \\r
        SQRex *self = NULL; \\r
        sq_getinstanceup(v,1,(SQUserPointer *)&self,0); \r
@@ -149,10 +218,11 @@ static SQInteger _regexp_match(HSQUIRRELVM v)
        sq_getstring(v,2,&str);\r
        if(sqstd_rex_match(self,str) == SQTrue)\r
        {\r
-               sq_pushinteger(v,1);\r
+               sq_pushbool(v,SQTrue);\r
                return 1;\r
        }\r
-       return 0;\r
+       sq_pushbool(v,SQFalse);\r
+       return 1;\r
 }\r
 \r
 static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end)\r
@@ -242,6 +312,10 @@ static SQRegFunction rexobj_funcs[]={
 #define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask}\r
 static SQRegFunction stringlib_funcs[]={\r
        _DECL_FUNC(format,-2,_SC(".s")),\r
+       _DECL_FUNC(strip,2,_SC(".s")),\r
+       _DECL_FUNC(lstrip,2,_SC(".s")),\r
+       _DECL_FUNC(rstrip,2,_SC(".s")),\r
+       _DECL_FUNC(split,3,_SC(".ss")),\r
        {0,0}\r
 };\r
 \r
index b52f057..c7153a6 100644 (file)
@@ -85,9 +85,11 @@ static void _set_integer_slot(HSQUIRRELVM v,const SQChar *name,SQInteger val)
 static SQInteger _system_date(HSQUIRRELVM v)\r
 {\r
        time_t t;\r
+       SQInteger it;\r
        SQInteger format = 'l';\r
        if(sq_gettop(v) > 1) {\r
-               sq_getinteger(v,2,(SQInteger*)&t);\r
+               sq_getinteger(v,2,&it);\r
+               t = it;\r
                if(sq_gettop(v) > 2) {\r
                        sq_getinteger(v,3,(SQInteger*)&format);\r
                }\r
index 638280f..b17bab9 100644 (file)
@@ -124,40 +124,26 @@ SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQCha
        return SQ_ERROR;\r
 }\r
 \r
-void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo)\r
+void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable)\r
 {\r
-       _ss(v)->_debuginfo = debuginfo?true:false;\r
+       _ss(v)->_debuginfo = enable?true:false;\r
+}\r
+\r
+void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable)\r
+{\r
+       _ss(v)->_notifyallexceptions = enable?true:false;\r
 }\r
 \r
 void sq_addref(HSQUIRRELVM v,HSQOBJECT *po)\r
 {\r
-       SQObjectPtr refs;\r
        if(!ISREFCOUNTED(type(*po))) return;\r
-       if(_table(_ss(v)->_refs_table)->Get(*po, refs)) {\r
-               refs = _integer(refs) + 1;\r
-       }\r
-       else{\r
-               refs = 1;\r
-       }\r
-       _table(_ss(v)->_refs_table)->NewSlot(*po, refs);\r
+       _ss(v)->_refs_table.AddRef(*po);\r
 }\r
 \r
 SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po)\r
 {\r
-       SQObjectPtr refs;\r
        if(!ISREFCOUNTED(type(*po))) return SQTrue;\r
-       if(_table(_ss(v)->_refs_table)->Get(*po, refs)) {\r
-               SQInteger n = _integer(refs) - 1;\r
-               if(n <= 0) {\r
-                       _table(_ss(v)->_refs_table)->Remove(*po);\r
-                       sq_resetobject(po);\r
-               }\r
-               else {\r
-                       refs = n;_table(_ss(v)->_refs_table)->Set(*po, refs);\r
-                       return SQFalse;\r
-               }\r
-       }\r
-       return SQTrue;\r
+       return _ss(v)->_refs_table.Release(*po);\r
 }\r
 \r
 const SQChar *sq_objtostring(HSQOBJECT *o) \r
@@ -256,13 +242,13 @@ SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase)
        return SQ_OK;\r
 }\r
 \r
-SQInteger sq_instanceof(HSQUIRRELVM v)\r
+SQBool sq_instanceof(HSQUIRRELVM v)\r
 {\r
        SQObjectPtr &inst = stack_get(v,-1);\r
        SQObjectPtr &cl = stack_get(v,-2);\r
        if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS)\r
                return sq_throwerror(v,_SC("invalid param type"));\r
-       return _instance(inst)->InstanceOf(_class(cl))?1:0;\r
+       return _instance(inst)->InstanceOf(_class(cl))?SQTrue:SQFalse;\r
 }\r
 \r
 SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx)\r
@@ -377,6 +363,34 @@ SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *ty
        return SQ_OK;\r
 }\r
 \r
+SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx)\r
+{\r
+       SQObjectPtr &o = stack_get(v,idx);\r
+       if(!sq_isnativeclosure(o) &&\r
+               !sq_isclosure(o))\r
+               return sq_throwerror(v,_SC("the target is not a closure"));\r
+    SQObjectPtr &env = stack_get(v,-1);\r
+       if(!sq_istable(env) &&\r
+               !sq_isclass(env) &&\r
+               !sq_isinstance(env))\r
+               return sq_throwerror(v,_SC("invalid environment"));\r
+       SQObjectPtr w = _refcounted(env)->GetWeakRef(type(env));\r
+       SQObjectPtr ret;\r
+       if(sq_isclosure(o)) {\r
+               SQClosure *c = _closure(o)->Clone();\r
+               c->_env = w;\r
+               ret = c;\r
+       }\r
+       else { //then must be a native closure\r
+               SQNativeClosure *c = _nativeclosure(o)->Clone();\r
+               c->_env = w;\r
+               ret = c;\r
+       }\r
+       v->Pop();\r
+       v->Push(ret);\r
+       return SQ_OK;\r
+}\r
+\r
 void sq_pushroottable(HSQUIRRELVM v)\r
 {\r
        v->Push(v->_roottable);\r
@@ -426,6 +440,12 @@ void sq_tostring(HSQUIRRELVM v,SQInteger idx)
        v->Push(res);\r
 }\r
 \r
+void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b)\r
+{\r
+       SQObjectPtr &o = stack_get(v, idx);\r
+       *b = v->IsFalse(o)?SQFalse:SQTrue;\r
+}\r
+\r
 SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i)\r
 {\r
        SQObjectPtr &o = stack_get(v, idx);\r
@@ -608,19 +628,32 @@ SQInteger sq_cmp(HSQUIRRELVM v)
        return res;\r
 }\r
 \r
-SQRESULT sq_createslot(HSQUIRRELVM v, SQInteger idx)\r
+SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)\r
 {\r
        sq_aux_paramscheck(v, 3);\r
        SQObjectPtr &self = stack_get(v, idx);\r
        if(type(self) == OT_TABLE || type(self) == OT_CLASS) {\r
                SQObjectPtr &key = v->GetUp(-2);\r
                if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key"));\r
-               v->NewSlot(self, key, v->GetUp(-1));\r
+               v->NewSlot(self, key, v->GetUp(-1),bstatic?true:false);\r
                v->Pop(2);\r
        }\r
        return SQ_OK;\r
 }\r
 \r
+/*SQRESULT sq_createslot(HSQUIRRELVM v, SQInteger idx)\r
+{\r
+       sq_aux_paramscheck(v, 3);\r
+       SQObjectPtr &self = stack_get(v, idx);\r
+       if(type(self) == OT_TABLE || type(self) == OT_CLASS) {\r
+               SQObjectPtr &key = v->GetUp(-2);\r
+               if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key"));\r
+               v->NewSlot(self, key, v->GetUp(-1));\r
+               v->Pop(2);\r
+       }\r
+       return SQ_OK;\r
+}*/\r
+\r
 SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval)\r
 {\r
        sq_aux_paramscheck(v, 2);\r
@@ -658,7 +691,7 @@ SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx)
                return SQ_OK;\r
        break;\r
        case OT_CLASS:\r
-               _class(self)->NewSlot(v->GetUp(-2), v->GetUp(-1));\r
+               _class(self)->NewSlot(_ss(v), v->GetUp(-2), v->GetUp(-1),false);\r
                v->Pop(2);\r
                return SQ_OK;\r
        break;\r
@@ -732,15 +765,15 @@ SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx)
        case OT_TABLE:\r
                if(!_table(self)->_delegate)break;\r
                v->Push(SQObjectPtr(_table(self)->_delegate));\r
-               return SQ_OK;\r
                break;\r
        case OT_USERDATA:\r
                if(!_userdata(self)->_delegate)break;\r
                v->Push(SQObjectPtr(_userdata(self)->_delegate));\r
-               return SQ_OK;\r
                break;\r
+       default: return sq_throwerror(v,_SC("wrong type")); break;\r
        }\r
-       return sq_throwerror(v,_SC("wrong type"));\r
+       return SQ_OK;\r
+       \r
 }\r
 \r
 SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx)\r
@@ -801,7 +834,7 @@ const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedIntege
                        return NULL;\r
                SQClosure *c=_closure(ci._closure);\r
                SQFunctionProto *func=_funcproto(c->_function);\r
-               return func->GetLocal(v,stackbase,idx,(ci._ip-func->_instructions._vals)-1);\r
+               return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions._vals)-1);\r
        }\r
        return NULL;\r
 }\r
@@ -839,11 +872,11 @@ void sq_reservestack(HSQUIRRELVM v,SQInteger nsize)
        }\r
 }\r
 \r
-SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval)\r
+SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror)\r
 {\r
        if(type(v->GetUp(-1))==OT_GENERATOR){\r
                v->Push(_null_); //retval\r
-               if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),SQVM::ET_RESUME_GENERATOR))\r
+               if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),raiseerror,SQVM::ET_RESUME_GENERATOR))\r
                {v->Raise_Error(v->_lasterror); return SQ_ERROR;}\r
                if(!retval)\r
                        v->Pop();\r
@@ -852,10 +885,10 @@ SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval)
        return sq_throwerror(v,_SC("only generators can be resumed"));\r
 }\r
 \r
-SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval)\r
+SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror)\r
 {\r
        SQObjectPtr res;\r
-       if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res)){\r
+       if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false)){\r
                v->Pop(params);//pop closure and args\r
                if(retval){\r
                        v->Push(res); return SQ_OK;\r
@@ -876,7 +909,7 @@ SQRESULT sq_suspendvm(HSQUIRRELVM v)
        return v->Suspend();\r
 }\r
 \r
-SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval)\r
+SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval,SQBool raiseerror)\r
 {\r
        SQObjectPtr ret;\r
        if(!v->_suspended)\r
@@ -885,7 +918,7 @@ SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval)
                v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval\r
                v->Pop();\r
        } else v->GetAt(v->_stackbase+v->_suspended_target)=_null_;\r
-       if(!v->Execute(_null_,v->_top,-1,-1,ret,SQVM::ET_RESUME_VM))\r
+       if(!v->Execute(_null_,v->_top,-1,-1,ret,raiseerror,SQVM::ET_RESUME_VM))\r
                return SQ_ERROR;\r
        if(sq_getvmstate(v) == SQ_VMSTATE_IDLE) {\r
                while (v->_top > 1) v->_stack[--v->_top] = _null_;\r
@@ -900,12 +933,10 @@ void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook)
        if(sq_gettop(v) >= 1){\r
                SQObjectPtr &ud=stack_get(v,idx);\r
                switch( type(ud) ) {\r
-               case OT_USERDATA:\r
-                       _userdata(ud)->_hook = hook;\r
-                       break;\r
-               case OT_INSTANCE:\r
-                       _instance(ud)->_hook = hook;\r
-                       break;\r
+               case OT_USERDATA:       _userdata(ud)->_hook = hook;    break;\r
+               case OT_INSTANCE:       _instance(ud)->_hook = hook;    break;\r
+               case OT_CLASS:          _class(ud)->_hook = hook;               break;\r
+               default: break; //shutup compiler\r
                }\r
        }\r
 }\r
@@ -919,7 +950,6 @@ SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up)
 {\r
        SQObjectPtr *o = NULL;\r
        _GETSAFE_OBJ(v, -1, OT_CLOSURE,o);\r
-       SQClosure *c=_closure(*o);\r
        unsigned short tag = SQ_BYTECODE_STREAM_TAG;\r
        if(w(up,&tag,2) != 2)\r
                return sq_throwerror(v,_SC("io error"));\r
@@ -1027,7 +1057,7 @@ SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx)
        if(type(key) == OT_NULL) {\r
                attrs = _class(*o)->_attributes;\r
                v->Pop();\r
-               v->Push(attrs);\r
+               v->Push(attrs); \r
                return SQ_OK;\r
        }\r
        else if(_class(*o)->GetAttributes(key,attrs)) {\r
@@ -1038,6 +1068,17 @@ SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx)
        return sq_throwerror(v,_SC("wrong index"));\r
 }\r
 \r
+SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx)\r
+{\r
+       SQObjectPtr *o = NULL;\r
+       _GETSAFE_OBJ(v, idx, OT_CLASS,o);\r
+       if(_class(*o)->_base)\r
+               v->Push(SQObjectPtr(_class(*o)->_base));\r
+       else\r
+               v->Push(_null_);\r
+       return SQ_OK;\r
+}\r
+\r
 SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx)\r
 {\r
        SQObjectPtr *o = NULL;\r
@@ -1074,6 +1115,25 @@ SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx)
        return SQ_OK;\r
 }\r
 \r
+SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t)\r
+{\r
+       SQSharedState *ss = _ss(v);\r
+       switch(t) {\r
+       case OT_TABLE: v->Push(ss->_table_default_delegate); break;\r
+       case OT_ARRAY: v->Push(ss->_array_default_delegate); break;\r
+       case OT_STRING: v->Push(ss->_string_default_delegate); break;\r
+       case OT_INTEGER: case OT_FLOAT: v->Push(ss->_number_default_delegate); break;\r
+       case OT_GENERATOR: v->Push(ss->_generator_default_delegate); break;\r
+       case OT_CLOSURE: case OT_NATIVECLOSURE: v->Push(ss->_closure_default_delegate); break;\r
+       case OT_THREAD: v->Push(ss->_thread_default_delegate); break;\r
+       case OT_CLASS: v->Push(ss->_class_default_delegate); break;\r
+       case OT_INSTANCE: v->Push(ss->_instance_default_delegate); break;\r
+       case OT_WEAKREF: v->Push(ss->_weakref_default_delegate); break;\r
+       default: return sq_throwerror(v,_SC("the type doesn't have a default delegate"));\r
+       }\r
+       return SQ_OK;\r
+}\r
+\r
 SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx)\r
 {\r
        SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val;\r
index 674608f..b8d3421 100644 (file)
@@ -97,7 +97,7 @@ static SQInteger base_getstackinfos(HSQUIRRELVM v)
                sq_pushstring(v, _SC("locals"), -1);\r
                sq_newtable(v);\r
                seq=0;\r
-               while (name = sq_getlocal(v, level, seq)) {\r
+               while ((name = sq_getlocal(v, level, seq))) {\r
                        sq_pushstring(v, name, -1);\r
                        sq_push(v, -2);\r
                        sq_createslot(v, -4);\r
@@ -238,6 +238,9 @@ void sq_base_register(HSQUIRRELVM v)
        sq_pushstring(v,_SC("_charsize_"),-1);\r
        sq_pushinteger(v,sizeof(SQChar));\r
        sq_createslot(v,-3);\r
+       sq_pushstring(v,_SC("_intsize_"),-1);\r
+       sq_pushinteger(v,sizeof(SQInteger));\r
+       sq_createslot(v,-3);\r
        sq_pop(v,1);\r
 }\r
 \r
@@ -288,7 +291,7 @@ static SQInteger default_delegate_tointeger(HSQUIRRELVM v)
                v->Push(SQObjectPtr(tointeger(o)));\r
                break;\r
        case OT_BOOL:\r
-               v->Push(SQObjectPtr(_integer(o)?1:0));\r
+               v->Push(SQObjectPtr(_integer(o)?(SQInteger)1:(SQInteger)0));\r
                break;\r
        default:\r
                v->Push(_null_);\r
@@ -312,7 +315,7 @@ static SQInteger obj_delegate_weakref(HSQUIRRELVM v)
 static SQInteger number_delegate_tochar(HSQUIRRELVM v)\r
 {\r
        SQObject &o=stack_get(v,1);\r
-       SQChar c=tointeger(o);\r
+       SQChar c = (SQChar)tointeger(o);\r
        v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1));\r
        return 1;\r
 }\r
@@ -357,6 +360,7 @@ SQRegFunction SQSharedState::_table_default_delegate_funcz[]={
        {_SC("rawdelete"),table_rawdelete,2, _SC("t")},\r
        {_SC("rawin"),container_rawexists,2, _SC("t")},\r
        {_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+       {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
        {0,0}\r
 };\r
 \r
@@ -443,7 +447,7 @@ bool _qsort_compare(HSQUIRRELVM v,SQObjectPtr &arr,SQObjectPtr &a,SQObjectPtr &b
                sq_pushroottable(v);\r
                v->Push(a);\r
                v->Push(b);\r
-               if(SQ_FAILED(sq_call(v, 3, SQTrue))) {\r
+               if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) {\r
                        v->Raise_Error(_SC("compare func failed"));\r
                        return false;\r
                }\r
@@ -488,7 +492,6 @@ bool _qsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger f
 \r
 static SQInteger array_sort(HSQUIRRELVM v)\r
 {\r
-       //SQ_TRY {\r
        SQInteger func = -1;\r
        SQObjectPtr &o = stack_get(v,1);\r
        SQObject &funcobj = stack_get(v,2);\r
@@ -534,6 +537,7 @@ SQRegFunction SQSharedState::_array_default_delegate_funcz[]={
        {_SC("sort"),array_sort,-1, _SC("ac")},\r
        {_SC("slice"),array_slice,-1, _SC("ann")},\r
        {_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+       {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
        {0,0}\r
 };\r
 \r
@@ -588,7 +592,7 @@ SQRegFunction SQSharedState::_string_default_delegate_funcz[]={
        {_SC("len"),default_delegate_len,1, _SC("s")},\r
        {_SC("tointeger"),default_delegate_tointeger,1, _SC("s")},\r
        {_SC("tofloat"),default_delegate_tofloat,1, _SC("s")},\r
-       {_SC("tostring"),default_delegate_tostring,1, _SC("s")},\r
+       {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
        {_SC("slice"),string_slice,-1, _SC(" s n  n")},\r
        {_SC("find"),string_find,-2, _SC("s s n ")},\r
        {_SC("tolower"),string_tolower,1, _SC("s")},\r
@@ -601,31 +605,97 @@ SQRegFunction SQSharedState::_string_default_delegate_funcz[]={
 SQRegFunction SQSharedState::_number_default_delegate_funcz[]={\r
        {_SC("tointeger"),default_delegate_tointeger,1, _SC("n|b")},\r
        {_SC("tofloat"),default_delegate_tofloat,1, _SC("n|b")},\r
-       {_SC("tostring"),default_delegate_tostring,1, _SC("n|b")},\r
+       {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
        {_SC("tochar"),number_delegate_tochar,1, _SC("n|b")},\r
        {_SC("weakref"),obj_delegate_weakref,1, NULL },\r
        {0,0}\r
 };\r
 \r
 //CLOSURE DEFAULT DELEGATE//////////////////////////\r
+static SQInteger closure_pcall(HSQUIRRELVM v)\r
+{\r
+       return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR;\r
+}\r
+\r
 static SQInteger closure_call(HSQUIRRELVM v)\r
 {\r
-       return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue))?1:SQ_ERROR;\r
+       return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQTrue))?1:SQ_ERROR;\r
 }\r
 \r
-static SQInteger closure_acall(HSQUIRRELVM v)\r
+static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror)\r
 {\r
        SQArray *aparams=_array(stack_get(v,2));\r
        SQInteger nparams=aparams->Size();\r
        v->Push(stack_get(v,1));\r
        for(SQInteger i=0;i<nparams;i++)v->Push(aparams->_values[i]);\r
-       return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue))?1:SQ_ERROR;\r
+       return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue,raiseerror))?1:SQ_ERROR;\r
+}\r
+\r
+static SQInteger closure_acall(HSQUIRRELVM v)\r
+{\r
+       return _closure_acall(v,SQTrue);\r
+}\r
+\r
+static SQInteger closure_pacall(HSQUIRRELVM v)\r
+{\r
+       return _closure_acall(v,SQFalse);\r
+}\r
+\r
+static SQInteger closure_bindenv(HSQUIRRELVM v)\r
+{\r
+       if(SQ_FAILED(sq_bindenv(v,1)))\r
+               return SQ_ERROR;\r
+       return 1;\r
+}\r
+\r
+static SQInteger closure_getinfos(HSQUIRRELVM v) {\r
+       SQObject o = stack_get(v,1);\r
+       SQTable *res = SQTable::Create(_ss(v),4);\r
+       if(type(o) == OT_CLOSURE) {\r
+               SQFunctionProto *f = _funcproto(_closure(o)->_function);\r
+               SQInteger nparams = f->_parameters.size() + (f->_varparams?1:0);\r
+               SQObjectPtr params = SQArray::Create(_ss(v),nparams);\r
+               for(SQUnsignedInteger n = 0; n<f->_parameters.size(); n++) {\r
+                       _array(params)->Set((SQInteger)n,f->_parameters[n]);\r
+               }\r
+               if(f->_varparams) {\r
+                       _array(params)->Set(nparams-1,SQString::Create(_ss(v),_SC("..."),-1));\r
+               }\r
+               res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),false);\r
+               res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),f->_name);\r
+               res->NewSlot(SQString::Create(_ss(v),_SC("src"),-1),f->_sourcename);\r
+               res->NewSlot(SQString::Create(_ss(v),_SC("parameters"),-1),params);\r
+               res->NewSlot(SQString::Create(_ss(v),_SC("varargs"),-1),f->_varparams);\r
+       }\r
+       else { //OT_NATIVECLOSURE \r
+               SQNativeClosure *nc = _nativeclosure(o);\r
+               res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),true);\r
+               res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),nc->_name);\r
+               res->NewSlot(SQString::Create(_ss(v),_SC("paramscheck"),-1),nc->_nparamscheck);\r
+               SQObjectPtr typecheck;\r
+               if(nc->_typecheck.size() > 0) {\r
+                       typecheck =\r
+                               SQArray::Create(_ss(v), nc->_typecheck.size());\r
+                       for(SQUnsignedInteger n = 0; n<nc->_typecheck.size(); n++) {\r
+                                       _array(typecheck)->Set((SQInteger)n,nc->_typecheck[n]);\r
+                       }\r
+               }\r
+               res->NewSlot(SQString::Create(_ss(v),_SC("typecheck"),-1),typecheck);\r
+       }\r
+       v->Push(res);\r
+       return 1;\r
 }\r
 \r
+\r
 SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={\r
        {_SC("call"),closure_call,-1, _SC("c")},\r
+       {_SC("pcall"),closure_pcall,-1, _SC("c")},\r
        {_SC("acall"),closure_acall,2, _SC("ca")},\r
+       {_SC("pacall"),closure_pacall,2, _SC("ca")},\r
        {_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+       {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
+       {_SC("bindenv"),closure_bindenv,2, _SC("c x|y|t")},\r
+       {_SC("getinfos"),closure_getinfos,1, _SC("c")},\r
        {0,0}\r
 };\r
 \r
@@ -644,6 +714,7 @@ static SQInteger generator_getstatus(HSQUIRRELVM v)
 SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={\r
        {_SC("getstatus"),generator_getstatus,1, _SC("g")},\r
        {_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+       {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
        {0,0}\r
 };\r
 \r
@@ -657,7 +728,7 @@ static SQInteger thread_call(HSQUIRRELVM v)
                _thread(o)->Push(_thread(o)->_roottable);\r
                for(SQInteger i = 2; i<(nparams+1); i++)\r
                        sq_move(_thread(o),v,i);\r
-               if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue))) {\r
+               if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue,SQFalse))) {\r
                        sq_move(v,_thread(o),-1);\r
                        return 1;\r
                }\r
@@ -687,7 +758,7 @@ static SQInteger thread_wakeup(HSQUIRRELVM v)
                if(wakeupret) {\r
                        sq_move(thread,v,2);\r
                }\r
-               if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,1))) {\r
+               if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,1,SQFalse))) {\r
                        sq_move(v,thread,-1);\r
                        sq_pop(thread,1);\r
                        if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) {\r
@@ -724,6 +795,7 @@ SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = {
        {_SC("wakeup"), thread_wakeup, -1, _SC("v")},\r
        {_SC("getstatus"), thread_getstatus, 1, _SC("v")},\r
        {_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+       {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
        {0,0},\r
 };\r
 \r
@@ -741,11 +813,20 @@ static SQInteger class_setattributes(HSQUIRRELVM v)
        return SQ_ERROR;\r
 }\r
 \r
+static SQInteger class_instance(HSQUIRRELVM v)\r
+{\r
+       if(SQ_SUCCEEDED(sq_createinstance(v,-1)))\r
+               return 1;\r
+       return SQ_ERROR;\r
+}\r
+\r
 SQRegFunction SQSharedState::_class_default_delegate_funcz[] = {\r
        {_SC("getattributes"), class_getattributes, 2, _SC("y.")},\r
        {_SC("setattributes"), class_setattributes, 3, _SC("y..")},\r
        {_SC("rawin"),container_rawexists,2, _SC("y")},\r
        {_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+       {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
+       {_SC("instance"),class_instance,1, _SC("y")},\r
        {0,0}\r
 };\r
 \r
@@ -760,6 +841,7 @@ SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = {
        {_SC("getclass"), instance_getclass, 1, _SC("x")},\r
        {_SC("rawin"),container_rawexists,2, _SC("x")},\r
        {_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+       {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
        {0,0}\r
 };\r
 \r
@@ -773,6 +855,7 @@ static SQInteger weakref_ref(HSQUIRRELVM v)
 SQRegFunction SQSharedState::_weakref_default_delegate_funcz[] = {\r
        {_SC("ref"),weakref_ref,1, _SC("r")},\r
        {_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+       {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
        {0,0}\r
 };\r
 \r
index 21d6006..1672f7c 100644 (file)
@@ -11,6 +11,7 @@ SQClass::SQClass(SQSharedState *ss,SQClass *base)
 {\r
        _base = base;\r
        _typetag = 0;\r
+       _hook = NULL;\r
        _metamethods.resize(MT_LAST); //size it to max size\r
        if(_base) {\r
                _defaultvalues.copy(base->_defaultvalues);\r
@@ -42,7 +43,7 @@ SQClass::~SQClass()
        Finalize();\r
 }\r
 \r
-bool SQClass::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)\r
+bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)\r
 {\r
        SQObjectPtr temp;\r
        if(_locked) \r
@@ -52,9 +53,10 @@ bool SQClass::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)
                _defaultvalues[_member_idx(temp)].val = val;\r
                return true;\r
        }\r
-       if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) {\r
+       if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE || bstatic) {\r
                SQInteger mmidx;\r
-               if((mmidx = _sharedstate->GetMetaMethodIdxByName(key)) != -1) {\r
+               if((type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) && \r
+                       (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) {\r
                        _metamethods[mmidx] = val;\r
                } \r
                else {\r
@@ -169,7 +171,7 @@ SQInstance::~SQInstance()
        Finalize();\r
 }\r
 \r
-bool SQInstance::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res)\r
+bool SQInstance::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res)\r
 {\r
        if(type(_class->_metamethods[mm]) != OT_NULL) {\r
                res = _class->_metamethods[mm];\r
index 3ef4f19..460e591 100644 (file)
@@ -36,7 +36,7 @@ public:
                return newclass;\r
        }\r
        ~SQClass();\r
-       bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val);\r
+       bool NewSlot(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic);\r
        bool Get(const SQObjectPtr &key,SQObjectPtr &val) {\r
                if(_members->Get(key,val)) {\r
                        if(_isfield(val)) {\r
@@ -53,19 +53,24 @@ public:
        bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val);\r
        bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval);\r
        void Lock() { _locked = true; if(_base) _base->Lock(); }\r
-       void Release() { sq_delete(this, SQClass);      }\r
+       void Release() { \r
+               if (_hook) { _hook(_typetag,0);}\r
+               sq_delete(this, SQClass);       \r
+       }\r
        void Finalize();\r
+#ifndef NO_GARBAGE_COLLECTOR\r
        void Mark(SQCollectable ** );\r
+#endif\r
        SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);\r
        SQInstance *CreateInstance();\r
        SQTable *_members;\r
-       //SQTable *_properties;\r
        SQClass *_base;\r
        SQClassMemeberVec _defaultvalues;\r
        SQClassMemeberVec _methods;\r
        SQObjectPtrVec _metamethods;\r
        SQObjectPtr _attributes;\r
        SQUserPointer _typetag;\r
+       SQRELEASEHOOK _hook;\r
        bool _locked;\r
 };\r
 \r
@@ -120,9 +125,11 @@ public:
                SQ_FREE(this, size);\r
        }\r
        void Finalize();\r
+#ifndef NO_GARBAGE_COLLECTOR \r
        void Mark(SQCollectable ** );\r
+#endif\r
        bool InstanceOf(SQClass *trg);\r
-       bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res);\r
+       bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res);\r
 \r
        SQClass *_class;\r
        SQUserPointer _userpointer;\r
index 8565621..7a5df1b 100644 (file)
@@ -17,6 +17,13 @@ public:
        void Release(){\r
                sq_delete(this,SQClosure);\r
        }\r
+       SQClosure *Clone()\r
+       {\r
+               SQClosure * ret = SQClosure::Create(_opt_ss(this),_funcproto(_function));\r
+               ret->_env = _env;\r
+               ret->_outervalues.copy(_outervalues);\r
+               return ret;\r
+       }\r
        ~SQClosure()\r
        {\r
                REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\r
@@ -27,6 +34,7 @@ public:
        void Mark(SQCollectable **chain);\r
        void Finalize(){_outervalues.resize(0); }\r
 #endif\r
+       SQObjectPtr _env;\r
        SQObjectPtr _function;\r
        SQObjectPtrVec _outervalues;\r
 };\r
@@ -78,6 +86,16 @@ public:
                new (nc) SQNativeClosure(ss,func);\r
                return nc;\r
        }\r
+       SQNativeClosure *Clone()\r
+       {\r
+               SQNativeClosure * ret = SQNativeClosure::Create(_opt_ss(this),_function);\r
+               ret->_env = _env;\r
+               ret->_name = _name;\r
+               ret->_outervalues.copy(_outervalues);\r
+               ret->_typecheck = _typecheck;\r
+               ret->_nparamscheck = _nparamscheck;\r
+               return ret;\r
+       }\r
        ~SQNativeClosure()\r
        {\r
                REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\r
@@ -89,6 +107,7 @@ public:
        void Mark(SQCollectable **chain);\r
        void Finalize(){_outervalues.resize(0);}\r
 #endif\r
+       SQObjectPtr _env;\r
        SQFUNCTION _function;\r
        SQObjectPtr _name;\r
        SQObjectPtrVec _outervalues;\r
index ed99a73..464a0c0 100644 (file)
@@ -303,7 +303,8 @@ public:
                case TK_MULEQ: oper = '*'; break;\r
                case TK_DIVEQ: oper = '/'; break;\r
                case TK_MODEQ: oper = '%'; break;\r
-               default: assert(0); break;\r
+               default: oper = 0; //shut up compiler\r
+                       assert(0); break;\r
                };\r
                if(deref) {\r
                        SQInteger val = _fs->PopTarget();\r
@@ -636,9 +637,15 @@ public:
                        _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);\r
                        Lex();\r
                        break;\r
-               case TK_INTEGER: \r
-                       _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue));\r
+               case TK_INTEGER: {\r
+                       if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits?\r
+                               _fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue);\r
+                       }\r
+                       else {\r
+                               _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue));\r
+                       }\r
                        Lex();\r
+                                                }\r
                        break;\r
                case TK_FLOAT: \r
                        _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue));\r
@@ -727,11 +734,18 @@ public:
                \r
                while(_token != terminator) {\r
                        bool hasattrs = false;\r
+                       bool isstatic = false;\r
                        //check if is an attribute\r
-                       if(separator == ';' && _token == TK_ATTR_OPEN) {\r
-                               _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();\r
-                               ParseTableOrClass(',',TK_ATTR_CLOSE);\r
-                               hasattrs = true;\r
+                       if(separator == ';') {\r
+                               if(_token == TK_ATTR_OPEN) {\r
+                                       _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();\r
+                                       ParseTableOrClass(',',TK_ATTR_CLOSE);\r
+                                       hasattrs = true;\r
+                               }\r
+                               if(_token == TK_STATIC) {\r
+                                       isstatic = true;\r
+                                       Lex();\r
+                               }\r
                        }\r
                        switch(_token) {\r
                                case TK_FUNCTION:\r
@@ -760,9 +774,10 @@ public:
                        SQInteger key = _fs->PopTarget();\r
                        SQInteger attrs = hasattrs ? _fs->PopTarget():-1;\r
                        assert(hasattrs && attrs == key-1 || !hasattrs);\r
+                       unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);\r
                        SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE\r
-                       _fs->AddInstruction(hasattrs?_OP_NEWSLOTA:_OP_NEWSLOT, _fs->PushTarget(), table, key, val);\r
-                       _fs->PopTarget();\r
+                       _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);\r
+                       //_fs->PopTarget();\r
                }\r
                if(separator == _SC(',')) //hack recognizes a table from the separator\r
                        _fs->SetIntructionParam(tpos, 1, nkeys);\r
@@ -943,6 +958,7 @@ public:
                SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();\r
                _fs->_breaktargets.push_back(0);\r
                while(_token == TK_CASE) {\r
+                       //_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one\r
                        if(!bfirst) {\r
                                _fs->AddInstruction(_OP_JMP, 0, 0);\r
                                skipcondjmp = _fs->GetCurrentPos();\r
@@ -966,6 +982,7 @@ public:
                if(tonextcondjmp != -1)\r
                        _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);\r
                if(_token == TK_DEFAULT) {\r
+               //      _fs->AddLineInfos(_lex._currentline, _lineinfo);\r
                        Lex(); Expect(_SC(':'));\r
                        SQInteger stacksize = _fs->GetStackSize();\r
                        Statements();\r
index 71dbfa2..ea0a831 100644 (file)
@@ -67,6 +67,7 @@ struct SQVM;
 #define TK_MODEQ 319\r
 #define TK_ATTR_OPEN 320\r
 #define TK_ATTR_CLOSE 321\r
+#define TK_STATIC 322\r
 \r
 \r
 typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s);\r
index 9612d06..732bd01 100644 (file)
@@ -31,6 +31,7 @@ SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si)
                                si->funcname = _stringval(_nativeclosure(ci._closure)->_name);\r
                        si->line = -1;\r
                        break;\r
+               default: break; //shutup compiler\r
                }\r
                return SQ_OK;\r
        }\r
@@ -41,7 +42,7 @@ void SQVM::Raise_Error(const SQChar *s, ...)
 {\r
        va_list vl;\r
        va_start(vl, s);\r
-       scvsprintf(_sp(rsl(scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl);\r
+       scvsprintf(_sp(rsl((SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl);\r
        va_end(vl);\r
        _lasterror = SQString::Create(_ss(this),_spval,-1);\r
 }\r
index 9e16026..b986707 100644 (file)
@@ -13,6 +13,7 @@
 SQInstructionDesc g_InstrDesc[]={\r
        {_SC("_OP_LINE")},\r
        {_SC("_OP_LOAD")},\r
+       {_SC("_OP_LOADINT")},\r
        {_SC("_OP_DLOAD")},\r
        {_SC("_OP_TAILCALL")},\r
        {_SC("_OP_CALL")},\r
@@ -77,6 +78,7 @@ void DumpLiteral(SQObjectPtr &o)
                case OT_STRING: scprintf(_SC("\"%s\""),_stringval(o));break;\r
                case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break;\r
                case OT_INTEGER: scprintf(_SC("{%d}"),_integer(o));break;\r
+               default: assert(0); break; //shut up compiler\r
        }\r
 }\r
 \r
@@ -211,7 +213,6 @@ SQInteger SQFuncState::GetNumericConstant(const SQFloat cons)
 \r
 SQInteger SQFuncState::GetConstant(const SQObject &cons)\r
 {\r
-       SQInteger n=0;\r
        SQObjectPtr val;\r
        if(!_table(_literals)->Get(cons,val))\r
        {\r
@@ -228,20 +229,19 @@ SQInteger SQFuncState::GetConstant(const SQObject &cons)
 \r
 void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)\r
 {\r
-       _instructions[pos]._arg0=*((SQUnsignedInteger *)&arg0);\r
-       _instructions[pos]._arg1=*((SQUnsignedInteger *)&arg1);\r
-       _instructions[pos]._arg2=*((SQUnsignedInteger *)&arg2);\r
-       _instructions[pos]._arg3=*((SQUnsignedInteger *)&arg3);\r
+       _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0);\r
+       _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1);\r
+       _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2);\r
+       _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3);\r
 }\r
 \r
 void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val)\r
 {\r
        switch(arg){\r
-               case 0:_instructions[pos]._arg0=*((SQUnsignedInteger *)&val);break;\r
-               case 1:_instructions[pos]._arg1=*((SQUnsignedInteger *)&val);break;\r
-               case 2:_instructions[pos]._arg2=*((SQUnsignedInteger *)&val);break;\r
-               case 3:_instructions[pos]._arg3=*((SQUnsignedInteger *)&val);break;\r
-               case 4:_instructions[pos]._arg1=*((SQUnsignedInteger *)&val);break;\r
+               case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break;\r
+               case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break;\r
+               case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break;\r
+               case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break;\r
        };\r
 }\r
 \r
@@ -482,7 +482,7 @@ void SQFuncState::AddInstruction(SQInstruction &i)
 SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len)\r
 {\r
        SQObjectPtr ns(SQString::Create(_sharedstate,s,len));\r
-       _table(_strings)->NewSlot(ns,1);\r
+       _table(_strings)->NewSlot(ns,(SQInteger)1);\r
        return ns;\r
 }\r
 \r
index c69a2f4..df6d2e9 100644 (file)
@@ -23,7 +23,6 @@ struct SQFuncState
        void SetStackSize(SQInteger n);\r
        void SnoozeOpt(){_optimization=false;}\r
        SQInteger GetCurrentPos(){return _instructions.size()-1;}\r
-       //SQInteger GetStringConstant(const SQChar *cons);\r
        SQInteger GetNumericConstant(const SQInteger cons);\r
        SQInteger GetNumericConstant(const SQFloat cons);\r
        SQInteger PushLocalVariable(const SQObject &name);\r
@@ -63,10 +62,10 @@ struct SQFuncState
        SQInteger _nliterals;\r
        SQLineInfoVec _lineinfos;\r
        SQFuncState *_parent;\r
-       SQIntVec _breaktargets; //contains number of nested exception traps\r
+       SQIntVec _breaktargets;\r
        SQIntVec _continuetargets;\r
        SQInteger _lastline;\r
-       SQInteger _traps;\r
+       SQInteger _traps; //contains number of nested exception traps\r
        bool _optimization;\r
        SQSharedState *_sharedstate;\r
        sqvector<SQFuncState*> _childstates;\r
index 93bd577..7244e73 100644 (file)
@@ -65,6 +65,7 @@ void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,Compile
        ADD_KEYWORD(vargv,TK_VARGV);\r
        ADD_KEYWORD(true,TK_TRUE);\r
        ADD_KEYWORD(false,TK_FALSE);\r
+       ADD_KEYWORD(static,TK_STATIC);\r
 \r
        _readf = rg;\r
        _up = up;\r
@@ -84,7 +85,7 @@ void SQLexer::Next()
        SQInteger t = _readf(_up);\r
        if(t > MAX_CHAR) Error(_SC("Invalid character"));\r
        if(t != 0) {\r
-               _currdata = t;\r
+               _currdata = (LexChar)t;\r
                return;\r
        }\r
        _currdata = SQUIRREL_EOB;\r
@@ -249,7 +250,7 @@ SQInteger SQLexer::Lex()
                                }\r
                                else {\r
                                        SQInteger c = CUR_CHAR;\r
-                                       if (sciscntrl(c)) Error(_SC("unexpected character(control)"));\r
+                                       if (sciscntrl((int)c)) Error(_SC("unexpected character(control)"));\r
                                        NEXT();\r
                                        RETURN_TOKEN(c);  \r
                                }\r
@@ -351,8 +352,28 @@ SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)
        return TK_STRING_LITERAL;\r
 }\r
 \r
-SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; }\r
+void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res)\r
+{\r
+       *res = 0;\r
+       while(*s != 0)\r
+       {\r
+               if(scisdigit(*s)) *res = (*res)*16+((*s++)-'0');\r
+               else if(scisxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10);\r
+               else { assert(0); }\r
+       }\r
+}\r
 \r
+void LexInteger(const SQChar *s,SQUnsignedInteger *res)\r
+{\r
+       *res = 0;\r
+       while(*s != 0)\r
+       {\r
+               *res = (*res)*10+((*s++)-'0');\r
+       }\r
+}\r
+\r
+SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; }\r
+#define MAX_HEX_DIGITS (sizeof(SQInteger)*2)\r
 SQInteger SQLexer::ReadNumber()\r
 {\r
 #define TINT 1\r
@@ -360,7 +381,6 @@ SQInteger SQLexer::ReadNumber()
 #define THEX 3\r
 #define TSCIENTIFIC 4\r
        SQInteger type = TINT, firstchar = CUR_CHAR;\r
-       bool isfloat = false;\r
        SQChar *sTemp;\r
        INIT_TEMP_STRING();\r
        NEXT();\r
@@ -371,10 +391,10 @@ SQInteger SQLexer::ReadNumber()
                        APPEND_CHAR(CUR_CHAR);\r
                        NEXT();\r
                }\r
-               if(_longstr.size() > 8) Error(_SC("Hex number over 8 digits"));\r
+               if(_longstr.size() > MAX_HEX_DIGITS) Error(_SC("too many digits for an Hex number"));\r
        }\r
        else {\r
-               APPEND_CHAR(firstchar);\r
+               APPEND_CHAR((int)firstchar);\r
                while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) {\r
             if(CUR_CHAR == _SC('.')) type = TFLOAT;\r
                        if(isexponent(CUR_CHAR)) {\r
@@ -400,10 +420,10 @@ SQInteger SQLexer::ReadNumber()
                _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp);\r
                return TK_FLOAT;\r
        case TINT:\r
-               _nvalue = (SQInteger)scstrtol(&_longstr[0],&sTemp,10);\r
+               LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue);\r
                return TK_INTEGER;\r
        case THEX:\r
-               *((SQUnsignedInteger *)&_nvalue) = scstrtoul(&_longstr[0],&sTemp,16);\r
+               LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);\r
                return TK_INTEGER;\r
        }\r
        return 0;\r
@@ -411,7 +431,7 @@ SQInteger SQLexer::ReadNumber()
 \r
 SQInteger SQLexer::ReadID()\r
 {\r
-       SQInteger res, size = 0;\r
+       SQInteger res;\r
        INIT_TEMP_STRING();\r
        do {\r
                APPEND_CHAR(CUR_CHAR);\r
@@ -419,7 +439,7 @@ SQInteger SQLexer::ReadID()
        } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_'));\r
        TERMINATE_BUFFER();\r
        res = GetIDType(&_longstr[0]);\r
-       if(res == TK_IDENTIFIER) {\r
+       if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) {\r
                _svalue = &_longstr[0];\r
        }\r
        return res;\r
index 750bbd0..be3b188 100644 (file)
@@ -2,9 +2,11 @@
 #ifndef _SQLEXER_H_\r
 #define _SQLEXER_H_\r
 \r
-#define MAX_STRING 2024\r
-\r
-\r
+#ifdef _UNICODE\r
+typedef SQChar LexChar;\r
+#else\r
+typedef        unsigned char LexChar;\r
+#endif\r
 \r
 struct SQLexer\r
 {\r
@@ -33,11 +35,7 @@ public:
        SQFloat _fvalue;\r
        SQLEXREADFUNC _readf;\r
        SQUserPointer _up;\r
-#ifdef _UNICODE\r
-       SQChar _currdata;\r
-#else\r
-       unsigned char _currdata;\r
-#endif\r
+       LexChar _currdata;\r
        SQSharedState *_sharedstate;\r
        sqvector<SQChar> _longstr;\r
        CompilerErrorFunc _errfunc;\r
index 92499c2..f01ce93 100644 (file)
@@ -23,6 +23,19 @@ void SQString::Release()
        REMOVE_STRING(_sharedstate,this);\r
 }\r
 \r
+SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)\r
+{\r
+       SQInteger idx = (SQInteger)TranslateIndex(refpos);\r
+       while(idx < _len){\r
+               outkey = (SQInteger)idx;\r
+               outval = SQInteger(_val[idx]);\r
+               //return idx for the next iteration\r
+               return ++idx;\r
+       }\r
+       //nothing to iterate anymore\r
+       return -1;\r
+}\r
+\r
 SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx)\r
 {\r
        switch(type(idx)){\r
@@ -30,8 +43,8 @@ SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx)
                        return 0;\r
                case OT_INTEGER:\r
                        return (SQUnsignedInteger)_integer(idx);\r
+               default: assert(0); break;\r
        }\r
-       assert(0);\r
        return 0;\r
 }\r
 \r
@@ -60,9 +73,9 @@ void SQWeakRef::Release() {
        sq_delete(this,SQWeakRef);\r
 }\r
 \r
-bool SQDelegable::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res) {\r
+bool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) {\r
        if(_delegate) {\r
-               return _delegate->Get((*_ss(this)->_metamethods)[mm],res);\r
+               return _delegate->Get((*_ss(v)->_metamethods)[mm],res);\r
        }\r
        return false;\r
 }\r
@@ -167,7 +180,7 @@ const SQChar* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQU
 \r
 SQInteger SQFunctionProto::GetLine(SQInstruction *curr)\r
 {\r
-       SQInteger op=(curr-_instructions._vals);\r
+       SQInteger op = (SQInteger)(curr-_instructions._vals);\r
        SQInteger line=_lineinfos[0]._line;\r
        for(SQUnsignedInteger i=1;i<_lineinfos.size();i++){\r
                if(_lineinfos[i]._op>=op)\r
index 230ed4c..c448913 100644 (file)
@@ -27,7 +27,9 @@ enum SQMetaMethod{
        MT_NEWSLOT=13,\r
        MT_DELSLOT=14,\r
        MT_TOSTRING=15,\r
-       MT_LAST = 16,\r
+       MT_NEWMEMBER=16,\r
+       MT_INHERITED=17,\r
+       MT_LAST = 18\r
 };\r
 \r
 #define MM_ADD         _SC("_add")\r
@@ -46,13 +48,15 @@ enum SQMetaMethod{
 #define MM_NEWSLOT     _SC("_newslot")\r
 #define MM_DELSLOT     _SC("_delslot")\r
 #define MM_TOSTRING    _SC("_tostring")\r
+#define MM_NEWMEMBER _SC("_newmember")\r
+#define MM_INHERITED _SC("_inherited")\r
 \r
 #define MINPOWER2 4\r
 \r
 struct SQRefCounted\r
 {\r
        SQRefCounted() { _uiRef = 0; _weakref = NULL; }\r
-       ~SQRefCounted();\r
+       virtual ~SQRefCounted();\r
        SQWeakRef *GetWeakRef(SQObjectType type);\r
        SQUnsignedInteger _uiRef;\r
        struct SQWeakRef *_weakref;\r
@@ -315,7 +319,7 @@ struct SQCollectable : public SQRefCounted {
 \r
 struct SQDelegable : public CHAINABLE_OBJ {\r
        bool SetDelegate(SQTable *m);\r
-       virtual bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res);\r
+       virtual bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res);\r
        SQTable *_delegate;\r
 };\r
 \r
@@ -323,4 +327,5 @@ SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx);
 typedef sqvector<SQObjectPtr> SQObjectPtrVec;\r
 typedef sqvector<SQInteger> SQIntVec;\r
 \r
+\r
 #endif //_SQOBJECT_H_\r
index f34ca37..2d0ffa6 100644 (file)
@@ -3,7 +3,7 @@
 #define _SQOPCODES_H_\r
 \r
 #define MAX_FUNC_STACKSIZE 0xFF\r
-#define MAX_LITERALS 0xFFFFFFFF\r
+#define MAX_LITERALS ((SQInteger)0x7FFFFFFF)\r
 \r
 enum BitWiseOP {\r
        BW_AND = 0,\r
@@ -24,65 +24,65 @@ enum SQOpcode
 {\r
        _OP_LINE=                               0x00,   \r
        _OP_LOAD=                               0x01,\r
-       _OP_DLOAD=                              0x02,\r
-       _OP_TAILCALL=                   0x03,   \r
-       _OP_CALL=                               0x04,   \r
-       _OP_PREPCALL=                   0x05,   \r
-       _OP_PREPCALLK=                  0x06,   \r
-       _OP_GETK=                               0x07,   \r
-       _OP_MOVE=                               0x08,   \r
-       _OP_NEWSLOT=                    0x09,   \r
-       _OP_DELETE=                             0x0A,   \r
-       _OP_SET=                                0x0B,   \r
-       _OP_GET=                                0x0C,\r
-       _OP_EQ=                                 0x0D,\r
-       _OP_NE=                                 0x0E,\r
-       _OP_ARITH=                              0x0F,\r
-       _OP_BITW=                               0x10,\r
-       _OP_RETURN=                             0x11,   \r
-       _OP_LOADNULLS=                  0x12,   \r
-       _OP_LOADROOTTABLE=              0x13,\r
-       _OP_LOADBOOL=                   0x14,\r
-       _OP_DMOVE=                              0x15,   \r
-       _OP_JMP=                                0x16,   \r
-       _OP_JNZ=                                0x17,   \r
-       _OP_JZ=                                 0x18,   \r
-       _OP_LOADFREEVAR=                0x19,   \r
-       _OP_VARGC=                              0x1A,   \r
-       _OP_GETVARGV=                   0x1B,   \r
-       _OP_NEWTABLE=                   0x1C,   \r
-       _OP_NEWARRAY=                   0x1D,   \r
-       _OP_APPENDARRAY=                0x1E,   \r
-       _OP_GETPARENT=                  0x1F,   \r
-       _OP_COMPARITH=                  0x20,   \r
-       _OP_COMPARITHL=                 0x21,   \r
-       _OP_INC=                                0x22,   \r
-       _OP_INCL=                               0x23,   \r
-       _OP_PINC=                               0x24,   \r
-       _OP_PINCL=                              0x25,   \r
-       _OP_CMP=                                0x26,\r
-       _OP_EXISTS=                             0x27,   \r
-       _OP_INSTANCEOF=                 0x28,\r
-       _OP_AND=                                0x29,\r
-       _OP_OR=                                 0x2A,\r
-       _OP_NEG=                                0x2B,\r
-       _OP_NOT=                                0x2C,\r
-       _OP_BWNOT=                              0x2D,   \r
-       _OP_CLOSURE=                    0x2E,   \r
-       _OP_YIELD=                              0x2F,   \r
-       _OP_RESUME=                             0x30,\r
-       _OP_FOREACH=                    0x31,\r
-       _OP_DELEGATE=                   0x32,\r
-       _OP_CLONE=                              0x33,\r
-       _OP_TYPEOF=                             0x34,\r
-       _OP_PUSHTRAP=                   0x35,\r
-       _OP_POPTRAP=                    0x36,\r
-       _OP_THROW=                              0x37,\r
-       _OP_CLASS=                              0x38,\r
-       _OP_NEWSLOTA=                   0x39,\r
-                                                       \r
-       \r
+       _OP_LOADINT=                    0x02,\r
+       _OP_DLOAD=                              0x03,\r
+       _OP_TAILCALL=                   0x04,   \r
+       _OP_CALL=                               0x05,   \r
+       _OP_PREPCALL=                   0x06,   \r
+       _OP_PREPCALLK=                  0x07,   \r
+       _OP_GETK=                               0x08,   \r
+       _OP_MOVE=                               0x09,   \r
+       _OP_NEWSLOT=                    0x0A,   \r
+       _OP_DELETE=                             0x0B,   \r
+       _OP_SET=                                0x0C,   \r
+       _OP_GET=                                0x0D,\r
+       _OP_EQ=                                 0x0E,\r
+       _OP_NE=                                 0x0F,\r
+       _OP_ARITH=                              0x10,\r
+       _OP_BITW=                               0x11,\r
+       _OP_RETURN=                             0x12,   \r
+       _OP_LOADNULLS=                  0x13,   \r
+       _OP_LOADROOTTABLE=              0x14,\r
+       _OP_LOADBOOL=                   0x15,\r
+       _OP_DMOVE=                              0x16,   \r
+       _OP_JMP=                                0x17,   \r
+       _OP_JNZ=                                0x18,   \r
+       _OP_JZ=                                 0x19,   \r
+       _OP_LOADFREEVAR=                0x1A,   \r
+       _OP_VARGC=                              0x1B,   \r
+       _OP_GETVARGV=                   0x1C,   \r
+       _OP_NEWTABLE=                   0x1D,   \r
+       _OP_NEWARRAY=                   0x1E,   \r
+       _OP_APPENDARRAY=                0x1F,   \r
+       _OP_GETPARENT=                  0x20,   \r
+       _OP_COMPARITH=                  0x21,   \r
+       _OP_COMPARITHL=                 0x22,   \r
+       _OP_INC=                                0x23,   \r
+       _OP_INCL=                               0x24,   \r
+       _OP_PINC=                               0x25,   \r
+       _OP_PINCL=                              0x26,   \r
+       _OP_CMP=                                0x27,\r
+       _OP_EXISTS=                             0x28,   \r
+       _OP_INSTANCEOF=                 0x29,\r
+       _OP_AND=                                0x2A,\r
+       _OP_OR=                                 0x2B,\r
+       _OP_NEG=                                0x2C,\r
+       _OP_NOT=                                0x2D,\r
+       _OP_BWNOT=                              0x2E,   \r
+       _OP_CLOSURE=                    0x2F,   \r
+       _OP_YIELD=                              0x30,   \r
+       _OP_RESUME=                             0x31,\r
+       _OP_FOREACH=                    0x32,\r
+       _OP_DELEGATE=                   0x33,\r
+       _OP_CLONE=                              0x34,\r
+       _OP_TYPEOF=                             0x35,\r
+       _OP_PUSHTRAP=                   0x36,\r
+       _OP_POPTRAP=                    0x37,\r
+       _OP_THROW=                              0x38,\r
+       _OP_CLASS=                              0x39,\r
+       _OP_NEWSLOTA=                   0x3A\r
 };                                                       \r
+\r
 struct SQInstructionDesc {       \r
        const SQChar *name;               \r
 };                                                       \r
@@ -92,8 +92,8 @@ struct SQInstruction
        SQInstruction(){};\r
        SQInstruction(SQOpcode _op,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0)\r
        {       op = _op;\r
-               _arg0 = a0;_arg1 = a1;\r
-               _arg2 = a2;_arg3 = a3;\r
+               _arg0 = (unsigned char)a0;_arg1 = (SQInt32)a1;\r
+               _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3;\r
        }\r
     \r
        \r
@@ -107,4 +107,7 @@ struct SQInstruction
 #include "squtils.h"\r
 typedef sqvector<SQInstruction> SQInstructionVec;\r
 \r
+#define NEW_SLOT_ATTRIBUTES_FLAG       0x01\r
+#define NEW_SLOT_STATIC_FLAG           0x02\r
+\r
 #endif // _SQOPCODES_H_\r
index e209095..475afe9 100644 (file)
 SQObjectPtr _null_;\r
 SQObjectPtr _true_(true);\r
 SQObjectPtr _false_(false);\r
-SQObjectPtr _one_(1);\r
-SQObjectPtr _minusone_(-1);\r
+SQObjectPtr _one_((SQInteger)1);\r
+SQObjectPtr _minusone_((SQInteger)-1);\r
 \r
 SQSharedState::SQSharedState()\r
 {\r
        _compilererrorhandler = NULL;\r
        _printfunc = NULL;\r
        _debuginfo = false;\r
+       _notifyallexceptions = false;\r
 }\r
 \r
 #define newsysstring(s) {      \\r
@@ -139,9 +140,10 @@ void SQSharedState::Init()
        newmetamethod(MM_NEWSLOT);\r
        newmetamethod(MM_DELSLOT);\r
        newmetamethod(MM_TOSTRING);\r
+       newmetamethod(MM_NEWMEMBER);\r
+       newmetamethod(MM_INHERITED);\r
 \r
        _constructoridx = SQString::Create(this,_SC("constructor"));\r
-       _refs_table = SQTable::Create(this,0);\r
        _registry = SQTable::Create(this,0);\r
        _table_default_delegate=CreateDefaultDelegate(this,_table_default_delegate_funcz);\r
        _array_default_delegate=CreateDefaultDelegate(this,_array_default_delegate_funcz);\r
@@ -159,10 +161,10 @@ void SQSharedState::Init()
 SQSharedState::~SQSharedState()\r
 {\r
        _constructoridx = _null_;\r
-       _table(_refs_table)->Finalize();\r
+       _refs_table.Finalize();\r
        _table(_registry)->Finalize();\r
        _table(_metamethodsmap)->Finalize();\r
-       _refs_table = _null_;\r
+//     _refs_table = _null_;\r
        _registry = _null_;\r
        _metamethodsmap = _null_;\r
        while(!_systemstrings->empty()){\r
@@ -234,6 +236,7 @@ void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)
        case OT_THREAD:_thread(o)->Mark(chain);break;\r
        case OT_CLASS:_class(o)->Mark(chain);break;\r
        case OT_INSTANCE:_instance(o)->Mark(chain);break;\r
+       default: break; //shutup compiler\r
        }\r
 }\r
 \r
@@ -246,7 +249,7 @@ SQInteger SQSharedState::CollectGarbage(SQVM *vm)
        \r
        vms->Mark(&tchain);\r
        SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed();\r
-       MarkObject(_refs_table,&tchain);\r
+       _refs_table.Mark(&tchain);\r
        MarkObject(_registry,&tchain);\r
        MarkObject(_metamethodsmap,&tchain);\r
        MarkObject(_table_default_delegate,&tchain);\r
@@ -322,6 +325,147 @@ SQChar* SQSharedState::GetScratchPad(SQInteger size)
        return _scratchpad;\r
 }\r
 \r
+RefTable::RefTable()\r
+{\r
+       AllocNodes(4);\r
+}\r
+\r
+void RefTable::Finalize()\r
+{\r
+       RefNode *nodes = (RefNode *)&_buckets[_numofslots];\r
+       for(SQUnsignedInteger n = 0; n < _numofslots; n++) {\r
+               nodes->obj = _null_;\r
+               nodes++;\r
+       }\r
+}\r
+\r
+RefTable::~RefTable()\r
+{\r
+       SQ_FREE(_buckets,_buffersize);\r
+}\r
+#ifndef NO_GARBAGE_COLLECTOR\r
+void RefTable::Mark(SQCollectable **chain)\r
+{\r
+       RefNode *nodes = (RefNode *)&_buckets[_numofslots];\r
+       for(SQUnsignedInteger n = 0; n < _numofslots; n++) {\r
+               if(type(nodes->obj) != OT_NULL) {\r
+                       SQSharedState::MarkObject(nodes->obj,chain);\r
+               }\r
+               nodes++;\r
+       }\r
+}\r
+#endif\r
+void RefTable::AddRef(SQObject &obj)\r
+{\r
+       SQHash mainpos;\r
+       RefNode *prev;\r
+       RefNode *ref = Get(obj,mainpos,&prev,true);\r
+       ref->refs++;\r
+}\r
+\r
+SQBool RefTable::Release(SQObject &obj)\r
+{\r
+       SQHash mainpos;\r
+       RefNode *prev;\r
+       RefNode *ref = Get(obj,mainpos,&prev,false);\r
+       if(ref) {\r
+               if(--ref->refs == 0) {\r
+                       ref->obj = _null_;\r
+                       if(prev) {\r
+                               prev->next = ref->next;\r
+                       }\r
+                       else {\r
+                               _buckets[mainpos] = ref->next;\r
+                       }\r
+                       ref->next = _freelist;\r
+                       _freelist = ref;\r
+                       _slotused--;\r
+                       //<<FIXME>>test for shrink?\r
+                       return SQTrue;\r
+               }\r
+       }\r
+       return SQFalse;\r
+}\r
+\r
+void RefTable::Resize(SQUnsignedInteger size)\r
+{\r
+       RefNode **oldbuffer = _buckets;\r
+       RefNode *oldnodes = (RefNode *)&_buckets[_numofslots];\r
+       SQUnsignedInteger oldnumofslots = _numofslots;\r
+       SQUnsignedInteger oldbuffersize = _buffersize;\r
+       AllocNodes(size);\r
+       //rehash\r
+       for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {\r
+               if(type(oldnodes->obj) != OT_NULL) {\r
+                       //add back;\r
+                       assert(oldnodes->refs != 0);\r
+                       RefNode *nn = Add(::HashObj(oldnodes->obj)&(_numofslots-1),oldnodes->obj);\r
+                       nn->refs = oldnodes->refs; \r
+                       oldnodes->obj = _null_;\r
+               }\r
+               oldnodes++;\r
+       }\r
+       SQ_FREE(oldbuffer,oldbuffersize);\r
+}\r
+\r
+RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)\r
+{\r
+       RefNode *t = _buckets[mainpos];\r
+       RefNode *newnode = _freelist;\r
+       newnode->obj = obj;\r
+       _buckets[mainpos] = newnode;\r
+       _freelist = _freelist->next;\r
+       newnode->next = t;\r
+       assert(newnode->refs == 0);\r
+       _slotused++;\r
+       return newnode;\r
+}\r
+\r
+RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)\r
+{\r
+       RefNode *ref;\r
+       mainpos = ::HashObj(obj)&(_numofslots-1);\r
+       *prev = NULL;\r
+       for (ref = _buckets[mainpos]; ref; ) {\r
+               if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))\r
+                       break;\r
+               *prev = ref;\r
+               ref = ref->next;\r
+       }\r
+       if(ref == NULL && add) {\r
+               if(_numofslots == _slotused) {\r
+                       Resize(_numofslots*2);\r
+               }\r
+               ref = Add(mainpos,obj);\r
+       }\r
+       return ref;\r
+}\r
+\r
+void RefTable::AllocNodes(SQUnsignedInteger size)\r
+{\r
+       RefNode **bucks;\r
+       RefNode *firstnode;\r
+       _buffersize = size * sizeof(RefNode *) + size * sizeof(RefNode);\r
+       bucks = (RefNode **)SQ_MALLOC(_buffersize);\r
+       firstnode = (RefNode *)&bucks[size];\r
+       RefNode *temp = firstnode;\r
+       SQUnsignedInteger n;\r
+       for(n = 0; n < size - 1; n++) {\r
+               bucks[n] = NULL;\r
+               temp->refs = 0;\r
+               new (&temp->obj) SQObjectPtr;\r
+               temp->next = temp+1;\r
+               temp++;\r
+       }\r
+       bucks[n] = NULL;\r
+       temp->refs = 0;\r
+       new (&temp->obj) SQObjectPtr;\r
+       temp->next = NULL;\r
+       _freelist = firstnode;\r
+       _buckets = bucks;\r
+       _slotused = 0;\r
+       _numofslots = size;\r
+}\r
 //////////////////////////////////////////////////////////////////////////\r
 //StringTable\r
 /*\r
@@ -330,19 +474,6 @@ SQChar* SQSharedState::GetScratchPad(SQInteger size)
 * http://www.lua.org/source/4.0.1/src_lstring.c.html\r
 */\r
 \r
-SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)\r
-{\r
-       SQInteger idx = (SQInteger)TranslateIndex(refpos);\r
-       while(idx < _len){\r
-               outkey = (SQInteger)idx;\r
-               outval = SQInteger(_val[idx]);\r
-               //return idx for the next iteration\r
-               return ++idx;\r
-       }\r
-       //nothing to iterate anymore\r
-       return -1;\r
-}\r
-\r
 StringTable::StringTable()\r
 {\r
        AllocNodes(4);\r
@@ -366,7 +497,7 @@ void StringTable::AllocNodes(SQInteger size)
 SQString *StringTable::Add(const SQChar *news,SQInteger len)\r
 {\r
        if(len<0)\r
-               len=scstrlen(news);\r
+               len = (SQInteger)scstrlen(news);\r
        SQHash h = ::_hashstr(news,len)&(_numofslots-1);\r
        SQString *s;\r
        for (s = _strings[h]; s; s = s->_next){\r
index 13aa719..64892c4 100644 (file)
@@ -13,10 +13,6 @@ struct StringTable
 {\r
        StringTable();\r
        ~StringTable();\r
-       //return a string obj if exists\r
-       //so when there is a table query, if the string doesn't exists in the global state\r
-       //it cannot be in a table so the result will be always null\r
-       //SQString *get(const SQChar *news);\r
        SQString *Add(const SQChar *,SQInteger len);\r
        void Remove(SQString *);\r
 private:\r
@@ -27,6 +23,32 @@ private:
        SQUnsignedInteger _slotused;\r
 };\r
 \r
+struct RefTable {\r
+       struct RefNode {\r
+               SQObjectPtr obj;\r
+               SQUnsignedInteger refs;\r
+               struct RefNode *next;\r
+       };\r
+       RefTable();\r
+       ~RefTable();\r
+       void AddRef(SQObject &obj);\r
+       SQBool Release(SQObject &obj);\r
+#ifndef NO_GARBAGE_COLLECTOR\r
+       void Mark(SQCollectable **chain);\r
+#endif\r
+       void Finalize();\r
+private:\r
+       RefNode *Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add);\r
+       RefNode *Add(SQHash mainpos,SQObject &obj);\r
+       void Resize(SQUnsignedInteger size);\r
+       void AllocNodes(SQUnsignedInteger size);\r
+       SQUnsignedInteger _numofslots;\r
+       SQUnsignedInteger _slotused;\r
+       SQUnsignedInteger _buffersize;\r
+       RefNode *_freelist;\r
+       RefNode **_buckets;\r
+};\r
+\r
 #define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len)\r
 #define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr)\r
 \r
@@ -49,7 +71,7 @@ public:
        SQObjectPtrVec *_systemstrings;\r
        SQObjectPtrVec *_types;\r
        StringTable *_stringtable;\r
-       SQObjectPtr _refs_table;\r
+       RefTable _refs_table;\r
        SQObjectPtr _registry;\r
        SQObjectPtr _constructoridx;\r
 #ifndef NO_GARBAGE_COLLECTOR\r
@@ -80,6 +102,7 @@ public:
        SQCOMPILERERROR _compilererrorhandler;\r
        SQPRINTFUNCTION _printfunc;\r
        bool _debuginfo;\r
+       bool _notifyallexceptions;\r
 private:\r
        SQChar *_scratchpad;\r
        SQInteger _scratchpadsize;\r
index 29ca9c2..235d190 100644 (file)
@@ -4,7 +4,7 @@
 \r
 inline SQHash _hashstr (const SQChar *s, size_t l)\r
 {\r
-               SQHash h = l;  /* seed */\r
+               SQHash h = (SQHash)l;  /* seed */\r
                size_t step = (l>>5)|1;  /* if string is too long, don't hash all its chars */\r
                for (; l>=step; l-=step)\r
                        h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++));\r
index 8eef4b8..4d96080 100644 (file)
@@ -20,7 +20,8 @@ SQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize)
 \r
 void SQTable::Remove(const SQObjectPtr &key)\r
 {\r
-       _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1));\r
+       \r
+       _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));\r
        if (n) {\r
                n->val = n->key = _null_;\r
                _usednodes--;\r
@@ -81,7 +82,9 @@ SQTable *SQTable::Clone()
 \r
 bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val)\r
 {\r
-       _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1));\r
+       if(type(key) == OT_NULL)\r
+               return false;\r
+       _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));\r
        if (n) {\r
                val = _realval(n->val);\r
                return true;\r
@@ -90,7 +93,8 @@ bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val)
 }\r
 bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)\r
 {\r
-       SQHash h = HashKey(key) & (_numofnodes - 1);\r
+       assert(type(key) != OT_NULL);\r
+       SQHash h = HashObj(key) & (_numofnodes - 1);\r
        _HashNode *n = _Get(key, h);\r
        if (n) {\r
                n->val = val;\r
@@ -99,19 +103,27 @@ bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)
        _HashNode *mp = &_nodes[h];\r
        n = mp;\r
 \r
+\r
        //key not found I'll insert it\r
        //main pos is not free\r
 \r
-       if(type(mp->key)!=OT_NULL) {\r
-\r
-               _HashNode *othern;  /* main position of colliding node */\r
+       if(type(mp->key) != OT_NULL) {\r
                n = _firstfree;  /* get a free place */\r
-               if (mp > n && (othern = &_nodes[h]) != mp){\r
+               SQHash mph = HashObj(mp->key) & (_numofnodes - 1);\r
+               _HashNode *othern;  /* main position of colliding node */\r
+               \r
+               if (mp > n && (othern = &_nodes[mph]) != mp){\r
                        /* yes; move colliding node into free position */\r
-                       while (othern->next != mp)\r
+                       while (othern->next != mp){\r
+                               assert(othern->next != NULL);\r
                                othern = othern->next;  /* find previous */\r
+                       }\r
                        othern->next = n;  /* redo the chain with `n' in place of `mp' */\r
-                       *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */\r
+                       n->key = mp->key;\r
+                       n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */\r
+                       n->next = mp->next;\r
+                       mp->key = _null_;\r
+                       mp->val = _null_;\r
                        mp->next = NULL;  /* now `mp' is free */\r
                }\r
                else{\r
@@ -124,7 +136,7 @@ bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)
        mp->key = key;\r
 \r
        for (;;) {  /* correct `firstfree' */\r
-               if (type(_firstfree->key) == OT_NULL) {\r
+               if (type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) {\r
                        mp->val = val;\r
                        _usednodes++;\r
                        return true;  /* OK; table still has a free place */\r
@@ -157,7 +169,7 @@ SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr
 \r
 bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val)\r
 {\r
-       _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1));\r
+       _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));\r
        if (n) {\r
                n->val = val;\r
                return true;\r
index 8d90f7b..be66843 100644 (file)
@@ -9,13 +9,25 @@
 \r
 #include "sqstring.h"\r
 \r
-#define hashptr(p)  (((SQHash)(reinterpret_cast<long>(p))) >> 3)\r
+\r
+#define hashptr(p)  ((SQHash)(((SQInteger)p) >> 3))\r
+\r
+inline SQHash HashObj(const SQObjectPtr &key)\r
+{\r
+       switch(type(key)) {\r
+               case OT_STRING:         return _string(key)->_hash;\r
+               case OT_FLOAT:          return (SQHash)((SQInteger)_float(key));\r
+               case OT_BOOL: case OT_INTEGER:  return (SQHash)((SQInteger)_integer(key));\r
+               default:                        return hashptr(key._unVal.pRefCounted);\r
+       }\r
+}\r
 \r
 struct SQTable : public SQDelegable \r
 {\r
 private:\r
        struct _HashNode\r
        {\r
+               _HashNode() { next = NULL; }\r
                SQObjectPtr val;\r
                SQObjectPtr key;\r
                _HashNode *next;\r
@@ -49,15 +61,6 @@ public:
 #ifndef NO_GARBAGE_COLLECTOR \r
        void Mark(SQCollectable **chain);\r
 #endif\r
-       inline SQHash HashKey(const SQObjectPtr &key)\r
-       {\r
-               switch(type(key)){\r
-                       case OT_STRING:         return _string(key)->_hash;\r
-                       case OT_FLOAT:          return (SQHash)((SQInteger)_float(key));\r
-                       case OT_INTEGER:        return (SQHash)((SQInteger)_integer(key));\r
-                       default:                        return hashptr(key._unVal.pRefCounted);\r
-               }\r
-       }\r
        inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash)\r
        {\r
                _HashNode *n = &_nodes[hash];\r
@@ -65,7 +68,7 @@ public:
                        if(_rawval(n->key) == _rawval(key) && type(n->key) == type(key)){\r
                                return n;\r
                        }\r
-               }while(n = n->next);\r
+               }while((n = n->next));\r
                return NULL;\r
        }\r
        bool Get(const SQObjectPtr &key,SQObjectPtr &val);\r
index 3137b0a..b13ae24 100644 (file)
@@ -82,6 +82,7 @@ SQVM::SQVM(SQSharedState *ss)
        _lasterror = _null_;\r
        _errorhandler = _null_;\r
        _debughook = _null_;\r
+       ci = NULL;\r
        INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);\r
 }\r
 \r
@@ -112,6 +113,7 @@ bool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr
                case _SC('/'): mm=MT_DIV; break;\r
                case _SC('*'): mm=MT_MUL; break;\r
                case _SC('%'): mm=MT_MODULO; break;\r
+               default: mm = MT_ADD; assert(0); break; //shutup compiler\r
        }\r
        if(is_delegable(o1) && _delegable(o1)->_delegate) {\r
                Push(o1);Push(o2);\r
@@ -140,8 +142,7 @@ bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o)
                                return true;\r
                        }\r
                }\r
-               return true;\r
-\r
+       default:break; //shutup compiler\r
        }\r
        Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o));\r
        return false;\r
@@ -166,9 +167,11 @@ bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)
                        Push(o1);Push(o2);\r
                        if(_delegable(o1)->_delegate)CallMetaMethod(_delegable(o1),MT_CMP,2,res);\r
                        break;\r
+               default: break; //shutup compiler\r
                }\r
                if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; }\r
-               _RET_SUCCEED(_integer(res));\r
+                       _RET_SUCCEED(_integer(res));\r
+               \r
        }\r
        else{\r
                if(sq_isnumeric(o1) && sq_isnumeric(o2)){\r
@@ -235,49 +238,22 @@ void SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)
                        }\r
                }\r
        default:\r
-               scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),_rawval(o));\r
+               scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o));\r
        }\r
        res = SQString::Create(_ss(this),_spval);\r
-       return;\r
 }\r
 \r
 \r
 bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest)\r
 {\r
-       switch(type(obj))\r
-       {\r
-       case OT_STRING:\r
-               switch(type(str)){\r
-               case OT_STRING: {\r
-                       SQInteger l=_string(str)->_len,ol=_string(obj)->_len;\r
-                       SQChar *s=_sp(rsl(l+ol+1));\r
-                       memcpy(s,_stringval(str),rsl(l));memcpy(s+l,_stringval(obj),rsl(ol));s[l+ol]=_SC('\0');\r
-                       break;\r
-               }\r
-               case OT_FLOAT:\r
-                       scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%g%s"),_float(str),_stringval(obj));\r
-                       break;\r
-               case OT_INTEGER:\r
-                       scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%d%s"),_integer(str),_stringval(obj));\r
-                       break;\r
-               default:\r
-                       Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj));\r
-                       return false;\r
-               }\r
-               dest=SQString::Create(_ss(this),_spval);\r
-               break;\r
-       case OT_FLOAT:\r
-               scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%g"),_stringval(str),_float(obj));\r
-               dest=SQString::Create(_ss(this),_spval);\r
-               break;\r
-       case OT_INTEGER:\r
-               scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%d"),_stringval(str),_integer(obj));\r
-               dest=SQString::Create(_ss(this),_spval);\r
-               break;\r
-       default:\r
-               Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj));\r
-               return false;\r
-       }\r
+       SQObjectPtr a, b;\r
+       ToString(str, a);\r
+       ToString(obj, b);\r
+       SQInteger l = _string(a)->_len , ol = _string(b)->_len;\r
+       SQChar *s = _sp(rsl(l + ol + 1));\r
+       memcpy(s, _stringval(a), rsl(l)); \r
+       memcpy(s + l, _stringval(b), rsl(ol));\r
+       dest = SQString::Create(_ss(this), _spval, l + ol);\r
        return true;\r
 }\r
 \r
@@ -347,10 +323,8 @@ extern SQInstructionDesc g_InstrDesc[];
 bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger nargs,SQInteger stackbase,bool tailcall)\r
 {\r
        SQFunctionProto *func = _funcproto(closure->_function);\r
-       //const SQInteger outerssize = func->_outervalues.size();\r
-\r
+       \r
        const SQInteger paramssize = func->_parameters.size();\r
-       const SQInteger oldtop = _top;\r
        const SQInteger newtop = stackbase + func->_stacksize;\r
        \r
        \r
@@ -371,21 +345,27 @@ bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger nargs,SQInteg
                        return false;\r
                }\r
        }\r
-       \r
+\r
+       if(type(closure->_env) == OT_WEAKREF) {\r
+               _stack[stackbase] = _weakref(closure->_env)->_obj;\r
+       }\r
+\r
        if (!tailcall) {\r
-               PUSH_CALLINFO(this, CallInfo());\r
-               ci->_etraps = 0;\r
-               ci->_prevstkbase = stackbase - _stackbase;\r
-               ci->_target = target;\r
-               ci->_prevtop = _top - _stackbase;\r
-               ci->_ncalls = 1;\r
-               ci->_root = SQFalse;\r
+               CallInfo lc;\r
+               lc._etraps = 0;\r
+               lc._prevstkbase = stackbase - _stackbase;\r
+               lc._target = target;\r
+               lc._prevtop = _top - _stackbase;\r
+               lc._ncalls = 1;\r
+               lc._root = SQFalse;\r
+               PUSH_CALLINFO(this, lc);\r
        }\r
        else {\r
                ci->_ncalls++;\r
+               if(ci->_vargs.size) PopVarArgs(ci->_vargs);\r
        }\r
        ci->_vargs.size = (nargs - paramssize);\r
-       ci->_vargs.base = _vargsstack.size()-(nargs - paramssize);\r
+       ci->_vargs.base = _vargsstack.size()-(ci->_vargs.size);\r
        ci->_closure._unVal.pClosure = closure;\r
        ci->_closure._type = OT_CLOSURE;\r
        ci->_iv = &func->_instructions;\r
@@ -406,7 +386,7 @@ bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval)
        if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure))\r
                for(SQInteger i=0;i<ci->_ncalls;i++)\r
                        CallDebugHook(_SC('r'));\r
-                                               \r
+                       \r
        SQBool broot = ci->_root;\r
        SQInteger last_top = _top;\r
        SQInteger target = ci->_target;\r
@@ -420,10 +400,12 @@ bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval)
                else retval = _null_;\r
        }\r
        else {\r
-               if (_arg0 != MAX_FUNC_STACKSIZE)\r
-                       STK(target) = _stack[oldstackbase+_arg1];\r
-               else\r
-                       STK(target) = _null_;\r
+               if(target != -1) { //-1 is when a class contructor ret value has to be ignored\r
+                       if (_arg0 != MAX_FUNC_STACKSIZE)\r
+                               STK(target) = _stack[oldstackbase+_arg1];\r
+                       else\r
+                               STK(target) = _null_;\r
+               }\r
        }\r
 \r
        while (last_top >= _top) _stack[last_top--].Null();\r
@@ -461,10 +443,10 @@ bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjec
 \r
 #define arg0 (_i_._arg0)\r
 #define arg1 (_i_._arg1)\r
-#define sarg1 (*((SQInteger *)&_i_._arg1))\r
+#define sarg1 (*((SQInt32 *)&_i_._arg1))\r
 #define arg2 (_i_._arg2)\r
 #define arg3 (_i_._arg3)\r
-#define sarg3 (*((char *)&_i_._arg3))\r
+#define sarg3 ((SQInteger)*((signed char *)&_i_._arg3))\r
 \r
 SQRESULT SQVM::Suspend()\r
 {\r
@@ -530,8 +512,9 @@ bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr
                        _generator(o1)->Resume(this, arg_2+1);\r
                        _FINISH(false);\r
                }\r
+       default: \r
+               Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1));\r
        }\r
-       Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1));\r
        return false; //cannot be hit(just to avoid warnings)\r
 }\r
 \r
@@ -566,7 +549,7 @@ bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func)
 {\r
        SQInteger nouters;\r
        SQClosure *closure = SQClosure::Create(_ss(this), func);\r
-       if(nouters = func->_outervalues.size()) {\r
+       if((nouters = func->_outervalues.size())) {\r
                closure->_outervalues.reserve(nouters);\r
                for(SQInteger i = 0; i<nouters; i++) {\r
                        SQOuterVar &v = func->_outervalues[i];\r
@@ -610,7 +593,7 @@ bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes
 {\r
        SQClass *base = NULL;\r
        SQObjectPtr attrs;\r
-       if(baseclass != MAX_LITERALS) {\r
+       if(baseclass != -1) {\r
                if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; }\r
                base = _class(_stack._vals[_stackbase + baseclass]);\r
        }\r
@@ -618,6 +601,13 @@ bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes
                attrs = _stack._vals[_stackbase+attributes];\r
        }\r
        target = SQClass::Create(_ss(this),base);\r
+       if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) {\r
+               int nparams = 2;\r
+               SQObjectPtr ret;\r
+               Push(target); Push(attrs);\r
+               Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false);\r
+               Pop(nparams);\r
+       }\r
        _class(target)->_attributes = attrs;\r
        return true;\r
 }\r
@@ -642,7 +632,30 @@ bool SQVM::IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res)
        return true;\r
 }\r
 \r
-bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, ExecutionType et)\r
+bool SQVM::IsFalse(SQObjectPtr &o)\r
+{\r
+       if((type(o) & SQOBJECT_CANBEFALSE) && ( (type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0)) )\r
+               || (_integer(o) == 0) ) { //OT_NULL|OT_INTEGER|OT_BOOL\r
+               return true;\r
+       }\r
+       return false;\r
+}\r
+\r
+bool SQVM::GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target)\r
+{\r
+       switch(type(o)) {\r
+               case OT_TABLE: target = _table(o)->_delegate?SQObjectPtr(_table(o)->_delegate):_null_;\r
+                       break;\r
+               case OT_CLASS: target = _class(o)->_base?_class(o)->_base:_null_;\r
+                       break;\r
+               default:\r
+                       Raise_Error(_SC("the %s type doesn't have a parent slot"), GetTypeName(o));\r
+                       return false;\r
+       }\r
+       return true;\r
+}\r
+\r
+bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et)\r
 {\r
        if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; }\r
        _nnativecalls++;\r
@@ -684,6 +697,7 @@ exception_restore:
                                        CallDebugHook(_SC('l'),arg1);\r
                                continue;\r
                        case _OP_LOAD: TARGET = (*ci->_literals)[arg1]; continue;\r
+                       case _OP_LOADINT: TARGET = (SQInteger)arg1; continue;\r
                        case _OP_DLOAD: TARGET = (*ci->_literals)[arg1]; STK(arg2) = (*ci->_literals)[arg3];continue;\r
                        case _OP_TAILCALL:\r
                                temp_reg = STK(arg1);\r
@@ -726,11 +740,20 @@ common_call:
                                                        outres = temp_reg;\r
                                                        return true;\r
                                                }\r
-                                               STK(ct_target) = temp_reg;\r
+                                               if(ct_target != -1) { //skip return value for contructors\r
+                                                       STK(ct_target) = temp_reg;\r
+                                               }\r
                                                                                   }\r
                                                break;\r
                                        case OT_CLASS:{\r
-                                               _GUARD(CreateClassInstance(_class(temp_reg),arg3,_stackbase+arg2,STK(ct_target)));\r
+                                               SQObjectPtr inst;\r
+                                               _GUARD(CreateClassInstance(_class(temp_reg),inst,temp_reg));\r
+                                               STK(ct_target) = inst;\r
+                                               ct_target = -1; //fakes return value target so that is not overwritten by the contructor\r
+                                               if(type(temp_reg) != OT_NULL) {\r
+                                                       _stack[_stackbase+arg2] = inst;\r
+                                                       goto common_call; //hard core spaghetti code(reissues the OP_CALL to invoke the contructor)\r
+                                               }\r
                                                }\r
                                                break;\r
                                        case OT_TABLE:\r
@@ -782,7 +805,7 @@ common_prepcall:
                                continue;\r
                        case _OP_MOVE: TARGET = STK(arg1); continue;\r
                        case _OP_NEWSLOT:\r
-                               _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3)));\r
+                               _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false));\r
                                if(arg0 != arg3) TARGET = STK(arg3);\r
                                continue;\r
                        case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue;\r
@@ -831,17 +854,7 @@ common_prepcall:
                        case _OP_NEWTABLE: TARGET = SQTable::Create(_ss(this), arg1); continue;\r
                        case _OP_NEWARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue;\r
                        case _OP_APPENDARRAY: _array(STK(arg0))->Append(COND_LITERAL);  continue;\r
-                       case _OP_GETPARENT:\r
-                               switch(type(STK(arg1))) {\r
-                               case OT_TABLE: \r
-                       TARGET = _table(STK(arg1))->_delegate?SQObjectPtr(_table(STK(arg1))->_delegate):_null_;\r
-                                       continue;\r
-                               case OT_CLASS: TARGET = _class(STK(arg1))->_base?_class(STK(arg1))->_base:_null_;\r
-                                       continue;\r
-                               }\r
-                               Raise_Error(_SC("the %s type doesn't have a parent slot"), GetTypeName(STK(arg1)));\r
-                               SQ_THROW();\r
-                               continue;\r
+                       case _OP_GETPARENT: _GUARD(GETPARENT_OP(STK(arg1),TARGET)); continue;\r
                        case _OP_COMPARITH: _GUARD(DerefInc(arg3, TARGET, STK((((SQUnsignedInteger)arg1&0xFFFF0000)>>16)), STK(arg2), STK(arg1&0x0000FFFF), false)); continue;\r
                        case _OP_COMPARITHL: _GUARD(LOCAL_INC(arg3, TARGET, STK(arg1), STK(arg2))); continue;\r
                        case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false));} continue;\r
@@ -871,7 +884,8 @@ common_prepcall:
                        case _OP_NOT: TARGET = (IsFalse(STK(arg1))?_true_:_false_); continue;\r
                        case _OP_BWNOT:\r
                                if(type(STK(arg1)) == OT_INTEGER) {\r
-                                       TARGET = SQInteger(~_integer(STK(arg1)));\r
+                                       SQInteger t = _integer(STK(arg1));\r
+                                       TARGET = SQInteger(~t);\r
                                        continue;\r
                                }\r
                                Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1)));\r
@@ -891,7 +905,7 @@ common_prepcall:
                                }\r
                                else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();}\r
                                if(Return(arg0, arg1, temp_reg)){\r
-                                       assert(traps==0);\r
+                                       assert(traps == 0);\r
                                        outres = temp_reg;\r
                                        return true;\r
                                }\r
@@ -917,18 +931,31 @@ common_prepcall:
                                _etraps.push_back(SQExceptionTrap(_top,_stackbase, &ci->_iv->_vals[(ci->_ip-ci->_iv->_vals)+arg1], arg0)); traps++;\r
                                ci->_etraps++;\r
                                continue;\r
-                       case _OP_POPTRAP:{\r
-                               for(SQInteger i=0; i<arg0; i++) {\r
+                       case _OP_POPTRAP:\r
+                               for(SQInteger i = 0; i < arg0; i++) {\r
                                        _etraps.pop_back(); traps--;\r
                                        ci->_etraps--;\r
-                               }}\r
+                               }\r
                                continue;\r
                        case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue;\r
                        case _OP_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue;\r
                        case _OP_NEWSLOTA:\r
-                               _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3)));\r
-                               _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1));\r
-                               if(arg0 != arg3) TARGET = STK(arg3);\r
+                               bool bstatic = (arg0&NEW_SLOT_STATIC_FLAG)?true:false;\r
+                               if(type(STK(arg1)) == OT_CLASS) {\r
+                                       if(type(_class(STK(arg1))->_metamethods[MT_NEWMEMBER]) != OT_NULL ) {\r
+                                               Push(STK(arg1)); Push(STK(arg2)); Push(STK(arg3));\r
+                                               Push((arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : _null_);\r
+                                               int nparams = 4;\r
+                                               if(Call(_class(STK(arg1))->_metamethods[MT_NEWMEMBER], nparams, _top - nparams, temp_reg,SQFalse)) {\r
+                                                       Pop(nparams);\r
+                                                       continue;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),bstatic));\r
+                               if((arg0&NEW_SLOT_ATTRIBUTES_FLAG)) {\r
+                                       _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1));\r
+                               }\r
                                continue;\r
                        }\r
                        \r
@@ -941,6 +968,8 @@ exception_trap:
                SQInteger n = 0;\r
                SQInteger last_top = _top;\r
                if(ci) {\r
+                       if(_ss(this)->_notifyallexceptions) CallErrorHandler(currerror);\r
+\r
                        if(traps) {\r
                                do {\r
                                        if(ci->_etraps > 0) {\r
@@ -960,12 +989,15 @@ exception_trap:
                                        PopVarArgs(ci->_vargs);\r
                                        POP_CALLINFO(this);\r
                                        n++;\r
-                               }while(_callsstack.size());\r
+                               } while(_callsstack.size());\r
+                       }\r
+                       else {\r
+                               //call the hook\r
+                               if(raiseerror && !_ss(this)->_notifyallexceptions)\r
+                                       CallErrorHandler(currerror);\r
                        }\r
-                       //call the hook\r
-                       CallErrorHandler(currerror);\r
                        //remove call stack until a C function is found or the cstack is empty\r
-                       if(ci) do{\r
+                       if(ci) do {\r
                                SQBool exitafterthisone = ci->_root;\r
                                if(type(ci->_generator) == OT_GENERATOR) _generator(ci->_generator)->Kill();\r
                                _stackbase -= ci->_prevstkbase;\r
@@ -973,7 +1005,7 @@ exception_trap:
                                PopVarArgs(ci->_vargs);\r
                                POP_CALLINFO(this);\r
                                if( (ci && type(ci->_closure) != OT_CLOSURE) || exitafterthisone) break;\r
-                       }while(_callsstack.size());\r
+                       } while(_callsstack.size());\r
 \r
                        while(last_top >= _top) _stack[last_top--].Null();\r
                }\r
@@ -983,16 +1015,14 @@ exception_trap:
        assert(0);\r
 }\r
 \r
-bool SQVM::CreateClassInstance(SQClass *theclass, SQInteger nargs, SQInteger stackbase, SQObjectPtr &retval)\r
+bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor)\r
 {\r
-       SQObjectPtr constr;\r
-       SQObjectPtr inst = theclass->CreateInstance();\r
-       _stack[stackbase] = inst;\r
-       if(theclass->Get(_ss(this)->_constructoridx,constr)) {\r
-               if(!Call(constr,nargs,stackbase,constr))\r
-                       return false;\r
+       inst = theclass->CreateInstance();\r
+       if(!theclass->Get(_ss(this)->_constructoridx,constructor)) {\r
+               //if(!Call(constr,nargs,stackbase,constr,false))\r
+               //      return false;\r
+               constructor = _null_;\r
        }\r
-       retval = inst;\r
        return true;\r
 }\r
 \r
@@ -1001,7 +1031,7 @@ void SQVM::CallErrorHandler(SQObjectPtr &error)
        if(type(_errorhandler) != OT_NULL) {\r
                SQObjectPtr out;\r
                Push(_roottable); Push(error);\r
-               Call(_errorhandler, 2, _top-2, out);\r
+               Call(_errorhandler, 2, _top-2, out,SQFalse);\r
                Pop(2);\r
        }\r
 }\r
@@ -1012,7 +1042,7 @@ void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline)
        SQInteger nparams=5;\r
        SQFunctionProto *func=_funcproto(_closure(ci->_closure)->_function);\r
        Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name);\r
-       Call(_debughook,nparams,_top-nparams,temp_reg);\r
+       Call(_debughook,nparams,_top-nparams,temp_reg,SQFalse);\r
        Pop(nparams);\r
 }\r
 \r
@@ -1027,7 +1057,7 @@ bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackb
                }\r
 \r
        SQInteger tcs;\r
-       if(tcs = nclosure->_typecheck.size()) {\r
+       if((tcs = nclosure->_typecheck.size())) {\r
                for(SQInteger i = 0; i < nargs && i < tcs; i++)\r
                        if((nclosure->_typecheck[i] != -1) && !(type(_stack[stackbase+i]) & nclosure->_typecheck[i])) {\r
                 Raise_ParamTypeError(i,nclosure->_typecheck[i],type(_stack[stackbase+i]));\r
@@ -1053,6 +1083,11 @@ bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackb
        for (SQInteger i = 0; i < outers; i++) {\r
                Push(nclosure->_outervalues[i]);\r
        }\r
+\r
+       if(type(nclosure->_env) == OT_WEAKREF) {\r
+               _stack[stackbase] = _weakref(nclosure->_env)->_obj;\r
+       }\r
+\r
        ci->_prevtop = (oldtop - oldstackbase);\r
        SQInteger ret = (nclosure->_function)(this);\r
        _nnativecalls--;\r
@@ -1088,6 +1123,7 @@ bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,
        case OT_INSTANCE:\r
                if(_instance(self)->Get(key,dest)) return true;\r
                break;\r
+       default:break; //shut up compiler\r
        }\r
        if(FallBackGet(self,key,dest,raw)) return true;\r
 \r
@@ -1129,7 +1165,7 @@ bool SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPt
        case OT_STRING:\r
                if(sq_isnumeric(key)){\r
                        SQInteger n=tointeger(key);\r
-                       if(abs(n)<_string(self)->_len){\r
+                       if(abs((int)n)<_string(self)->_len){\r
                                if(n<0)n=_string(self)->_len-n;\r
                                dest=SQInteger(_stringval(self)[n]);\r
                                return true;\r
@@ -1214,27 +1250,29 @@ bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr
 bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target)\r
 {\r
        SQObjectPtr temp_reg;\r
+       SQObjectPtr newobj;\r
        switch(type(self)){\r
        case OT_TABLE:\r
-               target = _table(self)->Clone();\r
+               newobj = _table(self)->Clone();\r
                goto cloned_mt;\r
        case OT_INSTANCE:\r
-               target = _instance(self)->Clone(_ss(this));\r
+               newobj = _instance(self)->Clone(_ss(this));\r
 cloned_mt:\r
-               if(_delegable(target)->_delegate){\r
-                       Push(target);\r
+               if(_delegable(newobj)->_delegate){\r
+                       Push(newobj);\r
                        Push(self);\r
-                       CallMetaMethod(_delegable(target),MT_CLONED,2,temp_reg);\r
+                       CallMetaMethod(_delegable(newobj),MT_CLONED,2,temp_reg);\r
                }\r
+               target = newobj;\r
                return true;\r
        case OT_ARRAY: \r
-               target=_array(self)->Clone();\r
+               target = _array(self)->Clone();\r
                return true;\r
        default: return false;\r
        }\r
 }\r
 \r
-bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val)\r
+bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)\r
 {\r
        if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; }\r
        switch(type(self)) {\r
@@ -1251,7 +1289,7 @@ bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObject
                \r
                break;}\r
        case OT_CLASS: \r
-               if(!_class(self)->NewSlot(key,val)) {\r
+               if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) {\r
                        if(_class(self)->_locked) {\r
                                Raise_Error(_SC("trying to modify a class that has already been instantiated"));\r
                                return false;\r
@@ -1309,14 +1347,14 @@ bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr
        return true;\r
 }\r
 \r
-bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres)\r
+bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror)\r
 {\r
 #ifdef _DEBUG\r
 SQInteger prevstackbase = _stackbase;\r
 #endif\r
        switch(type(closure)) {\r
        case OT_CLOSURE:\r
-               return Execute(closure, _top - nparams, nparams, stackbase,outres);\r
+               return Execute(closure, _top - nparams, nparams, stackbase,outres,raiseerror);\r
                break;\r
        case OT_NATIVECLOSURE:{\r
                bool suspend;\r
@@ -1324,8 +1362,16 @@ SQInteger prevstackbase = _stackbase;
                \r
                                                  }\r
                break;\r
-       case OT_CLASS:\r
-               return CreateClassInstance(_class(closure),nparams,stackbase,outres);\r
+       case OT_CLASS: {\r
+               SQObjectPtr constr;\r
+               SQObjectPtr temp;\r
+               CreateClassInstance(_class(closure),outres,constr);\r
+               if(type(constr) != OT_NULL) {\r
+                       _stack[stackbase] = outres;\r
+                       return Call(constr,nparams,stackbase,temp,raiseerror);\r
+               }\r
+               return true;\r
+                                  }\r
                break;\r
        default:\r
                return false;\r
@@ -1341,8 +1387,8 @@ SQInteger prevstackbase = _stackbase;
 bool SQVM::CallMetaMethod(SQDelegable *del,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres)\r
 {\r
        SQObjectPtr closure;\r
-       if(del->GetMetaMethod(mm, closure)) {\r
-               if(Call(closure, nparams, _top - nparams, outres)) {\r
+       if(del->GetMetaMethod(this, mm, closure)) {\r
+               if(Call(closure, nparams, _top - nparams, outres, SQFalse)) {\r
                        Pop(nparams);\r
                        return true;\r
                }\r
@@ -1360,6 +1406,21 @@ void SQVM::Remove(SQInteger n) {
        _top--;\r
 }\r
 \r
+void SQVM::Pop() {\r
+       _stack[--_top] = _null_;\r
+}\r
+\r
+void SQVM::Pop(SQInteger n) {\r
+       for(SQInteger i = 0; i < n; i++){\r
+               _stack[--_top] = _null_;\r
+       }\r
+}\r
+\r
+void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; }\r
+SQObjectPtr &SQVM::Top() { return _stack[_top-1]; }\r
+SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; }\r
+SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; }\r
+SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; }\r
 \r
 #ifdef _DEBUG_DUMP\r
 void SQVM::dumpstack(SQInteger stackbase,bool dumpall)\r
@@ -1368,7 +1429,7 @@ void SQVM::dumpstack(SQInteger stackbase,bool dumpall)
        SQInteger n=0;\r
        scprintf(_SC("\n>>>>stack dump<<<<\n"));\r
        CallInfo &ci=_callsstack.back();\r
-       scprintf(_SC("IP: %d\n"),ci._ip);\r
+       scprintf(_SC("IP: %p\n"),ci._ip);\r
        scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase);\r
        scprintf(_SC("prev top: %d\n"),ci._prevtop);\r
        for(SQInteger i=0;i<size;i++){\r
@@ -1401,4 +1462,6 @@ void SQVM::dumpstack(SQInteger stackbase,bool dumpall)
        }\r
 }\r
 \r
+\r
+\r
 #endif\r
index 00fce00..569bd43 100644 (file)
@@ -21,6 +21,7 @@ struct SQExceptionTrap{
        SQInteger _extarget;\r
 };\r
 \r
+#define _INLINE \r
 \r
 #define STK(a) _stack._vals[_stackbase+(a)]\r
 #define TARGET _stack._vals[_stackbase+arg0]\r
@@ -51,21 +52,21 @@ struct SQVM : public CHAINABLE_OBJ
                SQBool _root;\r
                VarArgs _vargs;\r
        };\r
-\r
+       \r
 typedef sqvector<CallInfo> CallInfoVec;\r
 public:\r
        enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM };\r
        SQVM(SQSharedState *ss);\r
        ~SQVM();\r
        bool Init(SQVM *friendvm, SQInteger stacksize);\r
-       bool Execute(SQObjectPtr &func, SQInteger target, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, ExecutionType et = ET_CALL);\r
-       //start a native call return when the NATIVE closure returns(returns true if the vm has been suspended)\r
+       bool Execute(SQObjectPtr &func, SQInteger target, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL);\r
+       //starts a native call return when the NATIVE closure returns\r
        bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger stackbase, bool tailcall, SQObjectPtr &retval,bool &suspend);\r
-       //start a SQUIRREL call in the same "Execution loop"\r
+       //starts a SQUIRREL call in the same "Execution loop"\r
        bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall);\r
-       bool CreateClassInstance(SQClass *theclass, SQInteger nargs, SQInteger stackbase, SQObjectPtr &retval);\r
+       bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor);\r
        //call a generic closure pure SQUIRREL or NATIVE\r
-       bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres);\r
+       bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror);\r
        SQRESULT Suspend();\r
 \r
        void CallDebugHook(SQInteger type,SQInteger forcedline=0);\r
@@ -73,7 +74,7 @@ public:
        bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, bool fetchroot);\r
        bool FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw);\r
        bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, bool fetchroot);\r
-       bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val);\r
+       bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val,bool bstatic);\r
        bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res);\r
        bool Clone(const SQObjectPtr &self, SQObjectPtr &target);\r
        bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res);\r
@@ -94,19 +95,20 @@ public:
        bool ArithMetaMethod(SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest);\r
        bool Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval);\r
        //new stuff\r
-       inline bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\r
-       inline bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\r
-       inline bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1);\r
-       inline bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res);\r
+       _INLINE bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\r
+       _INLINE bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\r
+       _INLINE bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1);\r
+       _INLINE bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res);\r
        bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func);\r
        bool GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &idx,CallInfo *ci);\r
        bool CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs);\r
+       bool GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target);\r
        //return true if the loop is finished\r
        bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,bool &finished);\r
        bool DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2);\r
-       inline bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);\r
-       inline bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);\r
-       inline bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix);\r
+       _INLINE bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);\r
+       _INLINE bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);\r
+       _INLINE bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix);\r
        void PopVarArgs(VarArgs &vargs);\r
 #ifdef _DEBUG_DUMP\r
        void dumpstack(SQInteger stackbase=-1, bool dumpall = false);\r
@@ -122,36 +124,21 @@ public:
        //stack functions for the api\r
        void Remove(SQInteger n);\r
 \r
-       inline bool IsFalse(SQObjectPtr &o)\r
-       {\r
-               if((type(o) & SQOBJECT_CANBEFALSE) && ( (type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0)) )\r
-                       || (_integer(o) == 0) ) { //OT_NULL|OT_INTEGER|OT_BOOL\r
-                       return true;\r
-               }\r
-               return false;\r
-       }\r
-       inline void Pop() {\r
-               _stack[--_top] = _null_;\r
-       }\r
-\r
-       inline void Pop(SQInteger n) {\r
-               for(SQInteger i = 0; i < n; i++){\r
-                       _stack[--_top] = _null_;\r
-               }\r
-       }\r
-\r
-       inline void Push(const SQObjectPtr &o) { _stack[_top++] = o; }\r
-       inline SQObjectPtr &Top() { return _stack[_top-1]; }\r
-       inline SQObjectPtr &PopGet() { return _stack[--_top]; }\r
-       inline SQObjectPtr &GetUp(SQInteger n) { return _stack[_top+n]; }\r
-       inline SQObjectPtr &GetAt(SQInteger n) { return _stack[n]; }\r
+       bool IsFalse(SQObjectPtr &o);\r
+       \r
+       void Pop();\r
+       void Pop(SQInteger n);\r
+       void Push(const SQObjectPtr &o);\r
+       SQObjectPtr &Top();\r
+       SQObjectPtr &PopGet();\r
+       SQObjectPtr &GetUp(SQInteger n);\r
+       SQObjectPtr &GetAt(SQInteger n);\r
 \r
        SQObjectPtrVec _stack;\r
        SQObjectPtrVec _vargsstack;\r
        SQInteger _top;\r
        SQInteger _stackbase;\r
        SQObjectPtr _roottable;\r
-       //SQObjectPtr _thrownerror;\r
        SQObjectPtr _lasterror;\r
        SQObjectPtr _errorhandler;\r
        SQObjectPtr _debughook;\r
index 939b930..105ce75 100644 (file)
@@ -23,6 +23,7 @@
 #include "timer.hpp"
 
 float game_time = 0;
+float real_time = 0;
 
 Timer::Timer()
   : period(0), cycle_start(0), cyclic(false)
index 340e8ce..903ffa8 100644 (file)
@@ -21,6 +21,7 @@
 #define __SUPERTUX_TIMER_H__
 
 extern float game_time;
+extern float real_time;
 
 /**
  * Simple timer designed to be used in the update functions of objects
index edb44c6..fd8856b 100644 (file)
@@ -299,6 +299,7 @@ TitleScreen::leave()
 {
   Sector* sector = titlesession->get_current_sector();
   sector->deactivate();
+  Menu::set_current(NULL);
 }
 
 void
index 54db311..0ccb630 100644 (file)
@@ -16,7 +16,6 @@
 //  You should have received a copy of the GNU General Public License
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
 #ifndef __GLUTIL_HPP__
 #define __GLUTIL_HPP__
 
@@ -24,7 +23,7 @@
 #include <stdexcept>
 #include <GL/gl.h>
 
-static inline void assert_gl(const char* message)
+static inline void check_gl_error(const char* message)
 {
 #ifdef DEBUG
   GLenum error = glGetError();
@@ -53,6 +52,11 @@ static inline void assert_gl(const char* message)
         msg << "OUT_OF_MEMORY: There is not enough memory left to execute the "
                "command.";
         break;
+#ifdef GL_TABLE_TOO_LARGE
+      case GL_TABLE_TOO_LARGE:
+        msg << "TABLE_TOO_LARGE: table is too large";
+        break;
+#endif                        
       default:
         msg << "Unknown error (code " << error << ")";
     }
@@ -62,5 +66,13 @@ static inline void assert_gl(const char* message)
 #endif
 }
 
+static inline void assert_gl(const char* message)
+{
+#ifdef DEBUG
+  check_gl_error(message);
+#else
+  (void) message;
 #endif
+}
 
+#endif
index 53fcdb7..8b68b08 100644 (file)
@@ -28,8 +28,7 @@
 #include "lisp/parser.hpp"
 #include "lisp/lisp.hpp"
 #include "physfs/physfs_stream.hpp"
-#include "script_manager.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "scripting/serialize.hpp"
 #include "log.hpp"
 #include "worldmap/worldmap.hpp"
@@ -49,10 +48,12 @@ World::World()
 {
   is_levelset = true;
   hide_from_contribs = false;
+  sq_resetobject(&world_thread);
 }
 
 World::~World()
 {
+  sq_release(Scripting::global_vm, &world_thread);
   if(current_ == this)
     current_ = NULL;
 }
@@ -123,10 +124,12 @@ World::load(const std::string& filename)
 void
 World::run()
 {
+  using namespace Scripting;
+
   current_ = this;
   
   // create new squirrel table for persisten game state
-  HSQUIRRELVM vm = ScriptManager::instance->get_vm();
+  HSQUIRRELVM vm = Scripting::global_vm;
 
   sq_pushroottable(vm);
   sq_pushstring(vm, "state", -1);
@@ -141,8 +144,9 @@ World::run()
   try {
     IFileStream in(filename);
 
-    HSQUIRRELVM new_vm = ScriptManager::instance->create_thread();
-    Scripting::compile_and_run(new_vm, in, filename);
+    sq_release(global_vm, &world_thread);
+    world_thread = create_thread(global_vm);
+    compile_and_run(object_to_vm(world_thread), in, filename);
   } catch(std::exception& e) {
     // fallback: try to load worldmap worldmap.stwm
     using namespace WorldMapNS;
@@ -153,6 +157,8 @@ World::run()
 void
 World::save_state()
 {
+  using namespace Scripting;
+
   lisp::Writer writer(savegame_filename);
 
   writer.start_list("supertux-savegame");
@@ -172,14 +178,14 @@ World::save_state()
   writer.end_list("tux");
 
   writer.start_list("state");
-  HSQUIRRELVM vm = ScriptManager::instance->get_vm();
-  sq_pushroottable(vm);
-  sq_pushstring(vm, "state", -1);
-  if(SQ_SUCCEEDED(sq_get(vm, -2))) {
-    Scripting::save_squirrel_table(vm, -1, writer);
-    sq_pop(vm, 1);
+  
+  sq_pushroottable(global_vm);
+  sq_pushstring(global_vm, "state", -1);
+  if(SQ_SUCCEEDED(sq_get(global_vm, -2))) {
+    Scripting::save_squirrel_table(global_vm, -1, writer);
+    sq_pop(global_vm, 1);
   }
-  sq_pop(vm, 1);
+  sq_pop(global_vm, 1);
   writer.end_list("state");
   
   writer.end_list("supertux-savegame");
@@ -188,6 +194,8 @@ World::save_state()
 void
 World::load_state()
 {
+  using namespace Scripting;
+
   try {
     lisp::Parser parser;
     std::auto_ptr<lisp::Lisp> root (parser.parse(savegame_filename));
@@ -210,18 +218,17 @@ World::load_state()
     if(state == NULL)
       throw std::runtime_error("No state section in savegame");
     
-    HSQUIRRELVM vm = ScriptManager::instance->get_vm();
-    sq_pushroottable(vm);
-    sq_pushstring(vm, "state", -1);
-    if(SQ_FAILED(sq_deleteslot(vm, -2, SQFalse)))
-      sq_pop(vm, 1);
+    sq_pushroottable(global_vm);
+    sq_pushstring(global_vm, "state", -1);
+    if(SQ_FAILED(sq_deleteslot(global_vm, -2, SQFalse)))
+      sq_pop(global_vm, 1);
     
-    sq_pushstring(vm, "state", -1);
-    sq_newtable(vm);
-    Scripting::load_squirrel_table(vm, -1, state);
-    if(SQ_FAILED(sq_createslot(vm, -3)))
+    sq_pushstring(global_vm, "state", -1);
+    sq_newtable(global_vm);
+    load_squirrel_table(global_vm, -1, state);
+    if(SQ_FAILED(sq_createslot(global_vm, -3)))
       throw std::runtime_error("Couldn't create state table");
-    sq_pop(vm, 1); 
+    sq_pop(global_vm, 1); 
   } catch(std::exception& e) {
     log_debug << "Couldn't load savegame: " << e.what() << std::endl;
   }
index 891a438..71095b8 100644 (file)
@@ -31,6 +31,7 @@ private:
   std::string savegame_filename;
   /// squirrel table that saves persistent state (about the world)
   HSQOBJECT state_table;
+  HSQOBJECT world_thread;
   static World* current_;
 
 public:
index 2b070a5..40c1327 100644 (file)
@@ -28,7 +28,7 @@
 #include "special_tile.hpp"
 #include "sprite_change.hpp"
 #include "control/joystickkeyboardcontroller.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "main.hpp"
 
 namespace WorldMapNS
@@ -190,8 +190,7 @@ Tux::tryContinueWalking(float elapsed_time)
       } else if(special_tile->script != "") {
         try {
           std::istringstream in(special_tile->script);
-          HSQUIRRELVM vm = ScriptManager::instance->create_thread();
-          Scripting::compile_and_run(vm, in, "specialtile");
+          worldmap->run_script(in, "specialtile");
         } catch(std::exception& e) {
           log_warning << "Couldn't execute special tile script: " << e.what()
                       << std::endl;
index d834fac..946b21f 100644 (file)
 #include "control/joystickkeyboardcontroller.hpp"
 #include "object/background.hpp"
 #include "object/tilemap.hpp"
-#include "script_manager.hpp"
 #include "options_menu.hpp"
 #include "scripting/squirrel_error.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
 #include "worldmap/level.hpp"
 #include "worldmap/special_tile.hpp"
 #include "worldmap/tux.hpp"
@@ -155,6 +154,14 @@ WorldMap::WorldMap(const std::string& filename)
 
 WorldMap::~WorldMap()
 {
+  using namespace Scripting;
+
+  for(ScriptList::iterator i = scripts.begin();
+      i != scripts.end(); ++i) {
+    HSQOBJECT& object = *i;
+    sq_release(global_vm, &object);
+  }
+  
   if(current_ == this)
     current_ = NULL;
 
@@ -403,10 +410,8 @@ WorldMap::finished_level(Level* gamelevel)
 
   if (level->extro_script != "") {
     try {
-      HSQUIRRELVM vm = ScriptManager::instance->create_thread();
-
       std::istringstream in(level->extro_script);
-      Scripting::compile_and_run(vm, in, "worldmap,extro_script");
+      run_script(in, "worldmap:extro_script");
     } catch(std::exception& e) {
       log_fatal << "Couldn't run level-extro-script: " << e.what() << std::endl;
     }
@@ -737,7 +742,9 @@ static bool read_bool(HSQUIRRELVM vm, const char* name)
 void
 WorldMap::save_state()
 {
-  HSQUIRRELVM vm = ScriptManager::instance->get_vm();
+  using namespace Scripting;
+  
+  HSQUIRRELVM vm = global_vm;
   int oldtop = sq_gettop(vm);
 
   try {
@@ -811,7 +818,9 @@ WorldMap::save_state()
 void
 WorldMap::load_state()
 {
-  HSQUIRRELVM vm = ScriptManager::instance->get_vm();
+  using namespace Scripting;
+  
+  HSQUIRRELVM vm = global_vm;
   int oldtop = sq_gettop(vm);
  
   try {
@@ -887,5 +896,35 @@ WorldMap::solved_level_count()
 
   return count;
 }
-    
+
+HSQUIRRELVM
+WorldMap::run_script(std::istream& in, const std::string& sourcename)
+{
+  using namespace Scripting;
+
+  // garbage collect thread list
+  for(ScriptList::iterator i = scripts.begin();
+      i != scripts.end(); ) {
+    HSQOBJECT& object = *i;
+    HSQUIRRELVM vm = object_to_vm(object);
+
+    if(sq_getvmstate(vm) != SQ_VMSTATE_SUSPENDED) {
+      sq_release(global_vm, &object);
+      i = scripts.erase(i);
+      continue;
+    }
+
+    ++i;
+  }
+
+  HSQOBJECT object = create_thread(global_vm);
+  scripts.push_back(object);
+
+  HSQUIRRELVM vm = object_to_vm(object);
+
+  compile_and_run(vm, in, sourcename);
+
+  return vm;
+}
+   
 } // namespace WorldMapNS
index 2be401b..1490b9c 100644 (file)
@@ -105,6 +105,9 @@ private:
 
   Statistics total_stats;
 
+  typedef std::vector<HSQOBJECT> ScriptList;
+  ScriptList scripts;      
+
 public:
   WorldMap(const std::string& filename);
   ~WorldMap();
@@ -153,6 +156,12 @@ public:
 
   const std::string& get_title() const
   { return name; }
+
+  /**
+   * runs a script in the context of the worldmap (and keeps a reference to 
+   * the script (so the script gets destroyed when the worldmap is destroyed)
+   */
+  HSQUIRRELVM run_script(std::istream& in, const std::string& sourcename);
     
 private:
   void get_level_title(LevelTile& level);
index 3310e48..821dedb 100644 (file)
@@ -1,3 +1,5 @@
+#include <config.h>
+
 #include "tree.hpp"
 #include <iostream>
 #include <sstream>
index e072b6f..62bfccc 100644 (file)
@@ -1,3 +1,5 @@
+#include <config.h>
+
 #include "tree.hpp"
 #include <iostream>
 #include <sstream>
index 42d7f64..954138b 100644 (file)
@@ -1,4 +1,6 @@
 %{
+#include <config.h>
+  
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
index cbb76f1..8a50801 100644 (file)
@@ -1,3 +1,5 @@
+#include <config.h>
+
 #include <iostream>
 #include <fstream>
 #include <vector>
index a54c0af..f992fc7 100644 (file)
@@ -1,4 +1,5 @@
 %{
+#include <config.h>
 
 #include <iostream>
 #include <sstream>
index 3d5413e..848b30b 100644 (file)
@@ -1,3 +1,4 @@
+#include <config.h>
 #include "tree.hpp"
 
 BasicType BasicType::VOID("void");