From: Matthias Braun Date: Sun, 23 Apr 2006 13:08:57 +0000 (+0000) Subject: - Avoid some expensive SDL_GetTicks() calls X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=c62711567861587107d124642db29e2674ee6533;p=supertux.git - Avoid some expensive SDL_GetTicks() calls - 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 --- diff --git a/configure.ac b/configure.ac index be44942b8..54ccbcf1a 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/data/levels/test/default.nut b/data/levels/test/default.nut index 34e17f7c3..b159b104d 100644 --- a/data/levels/test/default.nut +++ b/data/levels/test/default.nut @@ -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); diff --git a/data/levels/test/script.stl b/data/levels/test/script.stl index 7c6846b68..2020bc22d 100644 --- a/data/levels/test/script.stl +++ b/data/levels/test/script.stl @@ -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) diff --git a/data/levels/world1/27 - No More Mr Ice Guy.stl b/data/levels/world1/27 - No More Mr Ice Guy.stl index b4814a9b7..8f17e2798 100644 --- a/data/levels/world1/27 - No More Mr Ice Guy.stl +++ b/data/levels/world1/27 - No More Mr Ice Guy.stl @@ -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 index e049a591d..000000000 --- a/data/levels/world1/default.nut +++ /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(); -} diff --git a/data/levels/world1/intro.nut b/data/levels/world1/intro.nut index 3f33f6c78..e418a7f5a 100644 --- a/data/levels/world1/intro.nut +++ b/data/levels/world1/intro.nut @@ -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) { diff --git a/data/levels/world1/world.nut b/data/levels/world1/world.nut index c83bcc3c2..539cbd641 100644 --- a/data/levels/world1/world.nut +++ b/data/levels/world1/world.nut @@ -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(); diff --git a/src/audio/sound_manager.cpp b/src/audio/sound_manager.cpp index a05ca019c..34e9a9502 100644 --- a/src/audio/sound_manager.cpp +++ b/src/audio/sound_manager.cpp @@ -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(); ) { diff --git a/src/audio/stream_sound_source.cpp b/src/audio/stream_sound_source.cpp index d27856342..0cf75b234 100644 --- a/src/audio/stream_sound_source.cpp +++ b/src/audio/stream_sound_source.cpp @@ -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 diff --git a/src/audio/stream_sound_source.hpp b/src/audio/stream_sound_source.hpp index 25c8cd81a..18b2dc979 100644 --- a/src/audio/stream_sound_source.hpp +++ b/src/audio/stream_sound_source.hpp @@ -63,7 +63,7 @@ private: ALuint buffers[STREAMFRAGMENTS]; FadeState fade_state; - Uint32 fade_start_ticks; + float fade_start_time; float fade_time; bool looping; }; diff --git a/src/console.cpp b/src/console.cpp index 9ac545c0f..1b5f01ea9 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -23,10 +23,9 @@ #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) diff --git a/src/gameconfig.cpp b/src/gameconfig.cpp index a3de3253f..416d10432 100644 --- a/src/gameconfig.cpp +++ b/src/gameconfig.cpp @@ -43,6 +43,8 @@ Config::Config() screenwidth = 800; screenheight = 600; + + enable_script_debugger = false; } Config::~Config() diff --git a/src/gameconfig.hpp b/src/gameconfig.hpp index ab639d86a..109df1a04 100644 --- a/src/gameconfig.hpp +++ b/src/gameconfig.hpp @@ -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; }; diff --git a/src/gui/menu.cpp b/src/gui/menu.cpp index 7374ff7e9..c1408047e 100644 --- a/src/gui/menu.cpp +++ b/src/gui/menu.cpp @@ -37,11 +37,12 @@ #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::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) { diff --git a/src/gui/menu.hpp b/src/gui/menu.hpp index 0357c032a..55d97e216 100644 --- a/src/gui/menu.hpp +++ b/src/gui/menu.hpp @@ -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; diff --git a/src/main.cpp b/src/main.cpp index 5543ea3d9..c1bd12781 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,15 +43,14 @@ #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(); diff --git a/src/main.hpp b/src/main.hpp index 5f2ebbf6e..93c03d941 100644 --- a/src/main.hpp +++ b/src/main.hpp @@ -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 diff --git a/src/mainloop.cpp b/src/mainloop.cpp index 65da30ba4..3f2f4c0e2 100644 --- a/src/mainloop.cpp +++ b/src/mainloop.cpp @@ -26,10 +26,11 @@ #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::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); diff --git a/src/mainloop.hpp b/src/mainloop.hpp index db961e06b..47621f348 100644 --- a/src/mainloop.hpp +++ b/src/mainloop.hpp @@ -21,6 +21,7 @@ #include #include +#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); diff --git a/src/object/ambient_sound.cpp b/src/object/ambient_sound.cpp index f8d3eb92d..6893054e7 100644 --- a/src/object/ambient_sound.cpp +++ b/src/object/ambient_sound.cpp @@ -33,16 +33,17 @@ 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 #include "video/drawing_context.hpp" -#include "scripting/wrapper_util.hpp" +#include "scripting/squirrel_util.hpp" #include "main.hpp" static const float BORDER_SIZE = 75; diff --git a/src/object/player.cpp b/src/object/player.cpp index 1547ca7da..35f874e83 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -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 #include @@ -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" diff --git a/src/object/scripted_object.cpp b/src/object/scripted_object.cpp index f315174cf..07eebb352 100644 --- a/src/object/scripted_object.cpp +++ b/src/object/scripted_object.cpp @@ -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" diff --git a/src/object/text_object.cpp b/src/object/text_object.cpp index 5fbd47f0f..acf48dd73 100644 --- a/src/object/text_object.cpp +++ b/src/object/text_object.cpp @@ -24,7 +24,7 @@ #include #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 index da3f6064a..000000000 --- a/src/script_manager.cpp +++ /dev/null @@ -1,258 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#include "script_manager.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -#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::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 index e0f297852..000000000 --- a/src/script_manager.hpp +++ /dev/null @@ -1,110 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 -#include -#include -#include -#include "timer.hpp" -#ifdef ENABLE_SQDBG -#include -#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 SquirrelVMs; - SquirrelVMs squirrel_vms; - - HSQUIRRELVM vm; - ScriptManager* parent; - std::vector childs; -#ifdef ENABLE_SQDBG - HSQREMOTEDBG debugger; -#endif -}; - -#endif - diff --git a/src/scripting/functions.cpp b/src/scripting/functions.cpp index fc946db97..1285da65b 100644 --- a/src/scripting/functions.cpp +++ b/src/scripting/functions.cpp @@ -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" @@ -45,9 +44,11 @@ #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 (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 (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; diff --git a/src/scripting/functions.hpp b/src/scripting/functions.hpp index 2b690630c..250fa7bf8 100644 --- a/src/scripting/functions.hpp +++ b/src/scripting/functions.hpp @@ -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 index 5dca8772a..000000000 --- a/src/scripting/sound.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#include -#include -#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 index e7bf1ce73..000000000 --- a/src/scripting/sound.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - diff --git a/src/scripting/squirrel_error.cpp b/src/scripting/squirrel_error.cpp index f7d45e435..2c28273fb 100644 --- a/src/scripting/squirrel_error.cpp +++ b/src/scripting/squirrel_error.cpp @@ -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 #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 index 000000000..f9cb64835 --- /dev/null +++ b/src/scripting/squirrel_util.cpp @@ -0,0 +1,381 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "squirrel_util.hpp" +#include "log.hpp" +#include "level.hpp" +#include "physfs/physfs_stream.hpp" + +#ifdef ENABLE_SQDBG +#include + +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 << ""; + 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 << ""; + break; + case OT_CLOSURE: + os << ""; + break; + case OT_NATIVECLOSURE: + os << ""; + break; + case OT_GENERATOR: + os << ""; + break; + case OT_USERPOINTER: + os << "userpointer"; + break; + case OT_THREAD: + os << ""; + break; + case OT_CLASS: + os << ""; + break; + case OT_INSTANCE: + os << ""; + break; + case OT_WEAKREF: + os << ""; + break; + default: + os << ""; + 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 (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 index 000000000..f7cbf65a2 --- /dev/null +++ b/src/scripting/squirrel_util.hpp @@ -0,0 +1,85 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// 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 +#include +#include +#include +#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 + 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 index 000000000..100db79c1 --- /dev/null +++ b/src/scripting/thread_queue.cpp @@ -0,0 +1,87 @@ +// $Id: wrapper_util.cpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $ +// +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// 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 + +#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 index 000000000..f336cd354 --- /dev/null +++ b/src/scripting/thread_queue.hpp @@ -0,0 +1,50 @@ +// $Id: wrapper_util.cpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $ +// +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// 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 +#include + +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 ThreadList; + ThreadList threads; +}; + +} + +#endif + diff --git a/src/scripting/time_scheduler.cpp b/src/scripting/time_scheduler.cpp new file mode 100644 index 000000000..8310abcd5 --- /dev/null +++ b/src/scripting/time_scheduler.cpp @@ -0,0 +1,101 @@ +// $Id: script_manager.hpp 3379 2006-04-20 18:44:10Z matzebraun $ +// +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// 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 + +#include + +#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 index 000000000..05c6569ee --- /dev/null +++ b/src/scripting/time_scheduler.hpp @@ -0,0 +1,65 @@ +// $Id: script_manager.hpp 3379 2006-04-20 18:44:10Z matzebraun $ +// +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// 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 +#include + +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 ScheduleHeap; + ScheduleHeap schedule; +}; + +} + +#endif + diff --git a/src/scripting/wrapper.cpp b/src/scripting/wrapper.cpp index 910d6bc77..d28de4793 100644 --- a/src/scripting/wrapper.cpp +++ b/src/scripting/wrapper.cpp @@ -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 (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 (&_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 (&_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 (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) { diff --git a/src/scripting/wrapper.hpp b/src/scripting/wrapper.hpp index d0b969aac..8f55ffc45 100644 --- a/src/scripting/wrapper.hpp +++ b/src/scripting/wrapper.hpp @@ -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); diff --git a/src/scripting/wrapper.interface.hpp b/src/scripting/wrapper.interface.hpp index 823db4944..14135a801 100644 --- a/src/scripting/wrapper.interface.hpp +++ b/src/scripting/wrapper.interface.hpp @@ -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 index a24a5acc3..000000000 --- a/src/scripting/wrapper_util.cpp +++ /dev/null @@ -1,238 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#include -#include -#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 << ""; - 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 << ""; - break; - case OT_CLOSURE: - os << ""; - break; - case OT_NATIVECLOSURE: - os << ""; - break; - case OT_GENERATOR: - os << ""; - break; - case OT_USERPOINTER: - os << "userpointer"; - break; - case OT_THREAD: - os << ""; - break; - case OT_CLASS: - os << ""; - break; - case OT_INSTANCE: - os << ""; - break; - default: - os << ""; - 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 (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 index 2d7d1d9e3..000000000 --- a/src/scripting/wrapper_util.hpp +++ /dev/null @@ -1,72 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 -#include -#include -#include -#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 -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/sector.cpp b/src/sector.cpp index 1fbbbb0e6..3a0e2299d 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -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(§or_table); - if(SQ_FAILED(sq_getstackobj(vm, -1, §or_table))) - throw Scripting::SquirrelError(vm, "Couldn't get sector table"); - sq_addref(vm, §or_table); - sq_pop(vm, 1); + if(SQ_FAILED(sq_getstackobj(global_vm, -1, §or_table))) + throw Scripting::SquirrelError(global_vm, "Couldn't get sector table"); + sq_addref(global_vm, §or_table); + sq_pop(global_vm, 1); } Sector::~Sector() { - deactivate(); + using namespace Scripting; - script_manager.reset(NULL); - sq_release(ScriptManager::instance->get_vm(), §or_table); + deactivate(); + + for(ScriptList::iterator i = scripts.begin(); + i != scripts.end(); ++i) { + HSQOBJECT& object = *i; + sq_release(global_vm, &object); + } + sq_release(global_vm, §or_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 (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 (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 { diff --git a/src/sector.hpp b/src/sector.hpp index d291c0a69..7a973966d 100644 --- a/src/sector.hpp +++ b/src/sector.hpp @@ -25,7 +25,6 @@ #include #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 script_manager; + typedef std::vector ScriptList; + ScriptList scripts; public: // TODO make this private again /// show collision rectangles of moving objects (for debugging) diff --git a/src/sprite/sprite.cpp b/src/sprite/sprite.cpp index 6c7cedbd2..4d6898033 100644 --- a/src/sprite/sprite.cpp +++ b/src/sprite/sprite.cpp @@ -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; diff --git a/src/sprite/sprite.hpp b/src/sprite/sprite.hpp index c8f6cb27c..e86a58b58 100644 --- a/src/sprite/sprite.hpp +++ b/src/sprite/sprite.hpp @@ -91,7 +91,7 @@ private: float frame; int animation_loops; - Uint32 last_ticks; + float last_ticks; SpriteData::Action* action; }; diff --git a/src/squirrel/include/sqstdio.h b/src/squirrel/include/sqstdio.h index 864b4f1de..1174201a9 100644 --- a/src/squirrel/include/sqstdio.h +++ b/src/squirrel/include/sqstdio.h @@ -7,7 +7,6 @@ #define SQSTD_STREAM_TYPE_TAG 0x80000000 struct SQStream { - virtual ~SQStream() {} virtual SQInteger Read(void *buffer, SQInteger size) = 0; virtual SQInteger Write(void *buffer, SQInteger size) = 0; virtual SQInteger Flush() = 0; diff --git a/src/squirrel/include/squirrel.h b/src/squirrel/include/squirrel.h index d301f834e..12fb4d5d3 100644 --- a/src/squirrel/include/squirrel.h +++ b/src/squirrel/include/squirrel.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2005 Alberto Demichelis +Copyright (c) 2003-2006 Alberto Demichelis This software is provided 'as-is', without any express or implied warranty. In no event will the @@ -39,12 +39,26 @@ extern "C" { #define SQUIRREL_API extern #endif -typedef float SQFloat; +#ifdef _SQ64 +#ifdef _MSC_VER +typedef __int64 SQInteger; +typedef unsigned __int64 SQUnsignedInteger; +typedef unsigned __int64 SQHash; /*should be the same size of a pointer*/ +#else +typedef long SQInteger; +typedef unsigned long SQUnsignedInteger; +typedef unsigned long SQHash; /*should be the same size of a pointer*/ +#endif +typedef int SQInt32; +#else typedef int SQInteger; -typedef int SQInt32; //must be 32 bits(also on 64bits processors) -typedef void* SQUserPointer; +typedef int SQInt32; /*must be 32 bits(also on 64bits processors)*/ typedef unsigned int SQUnsignedInteger; -typedef unsigned int SQHash; //should be the same size of a pointer +typedef unsigned int SQHash; /*should be the same size of a pointer*/ +#endif + +typedef float SQFloat; +typedef void* SQUserPointer; typedef SQUnsignedInteger SQBool; typedef SQInteger SQRESULT; @@ -71,7 +85,10 @@ struct SQDelegable; #endif #ifdef SQUNICODE -typedef unsigned short SQChar; +#if defined(wchar_t) //this is if the compiler considers wchar_t as native type +#define wchar_t unsigned short +#endif +typedef wchar_t SQChar; #define _SC(a) L##a #define scstrcmp wcscmp #define scsprintf swprintf @@ -84,6 +101,7 @@ typedef unsigned short SQChar; #define scstrstr wcsstr #define scisspace iswspace #define scisdigit iswdigit +#define scisxdigit iswxdigit #define scisalpha iswalpha #define sciscntrl iswcntrl #define scisalnum iswalnum @@ -103,6 +121,7 @@ typedef char SQChar; #define scstrstr strstr #define scisspace isspace #define scisdigit isdigit +#define scisxdigit isxdigit #define sciscntrl iscntrl #define scisalpha isalpha #define scisalnum isalnum @@ -110,8 +129,8 @@ typedef char SQChar; #define MAX_CHAR 0xFF #endif -#define SQUIRREL_VERSION _SC("Squirrel 2.0.5 stable") -#define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2005 Alberto Demichelis") +#define SQUIRREL_VERSION _SC("Squirrel 2.1 stable") +#define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2006 Alberto Demichelis") #define SQUIRREL_AUTHOR _SC("Alberto Demichelis") #define SQ_VMSTATE_IDLE 0 @@ -149,7 +168,7 @@ typedef char SQChar; #define _RT_INSTANCE 0x00008000 #define _RT_WEAKREF 0x00010000 -typedef enum { +typedef enum tagSQObjectType{ OT_NULL = (_RT_NULL|SQOBJECT_CANBEFALSE), OT_INTEGER = (_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), OT_FLOAT = (_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), @@ -235,13 +254,14 @@ SQUIRREL_API SQUserPointer sq_getforeignptr(HSQUIRRELVM v); SQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc); SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v); -SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval); +SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool raiseerror); SQUIRREL_API SQInteger sq_getvmstate(HSQUIRRELVM v); /*compiler*/ SQUIRREL_API SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror); SQUIRREL_API SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror); -SQUIRREL_API void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo); +SQUIRREL_API void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable); +SQUIRREL_API void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable); SQUIRREL_API void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f); /*stack operations*/ @@ -261,6 +281,7 @@ SQUIRREL_API void sq_newtable(HSQUIRRELVM v); SQUIRREL_API void sq_newarray(HSQUIRRELVM v,SQInteger size); SQUIRREL_API void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars); SQUIRREL_API SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask); +SQUIRREL_API SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len); SQUIRREL_API void sq_pushfloat(HSQUIRRELVM v,SQFloat f); SQUIRREL_API void sq_pushinteger(HSQUIRRELVM v,SQInteger n); @@ -269,7 +290,10 @@ SQUIRREL_API void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p); SQUIRREL_API void sq_pushnull(HSQUIRRELVM v); SQUIRREL_API SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQBool sq_instanceof(HSQUIRRELVM v); SQUIRREL_API void sq_tostring(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b); SQUIRREL_API SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c); SQUIRREL_API SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i); SQUIRREL_API SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f); @@ -291,12 +315,14 @@ SQUIRREL_API SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API void sq_weakref(HSQUIRRELVM v,SQInteger idx); +SQUIRREL_API SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t); /*object manipulation*/ SQUIRREL_API void sq_pushroottable(HSQUIRRELVM v); SQUIRREL_API void sq_pushregistrytable(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_setroottable(HSQUIRRELVM v); -SQUIRREL_API SQRESULT sq_createslot(HSQUIRRELVM v,SQInteger idx); +/*SQUIRREL_API SQRESULT sq_createslot(HSQUIRRELVM v,SQInteger idx);*/ +SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic); SQUIRREL_API SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval); SQUIRREL_API SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx); @@ -315,8 +341,8 @@ SQUIRREL_API SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx); /*calls*/ -SQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval); -SQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval); +SQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror); +SQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror); SQUIRREL_API const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx); SQUIRREL_API const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval); SQUIRREL_API SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err); @@ -333,6 +359,7 @@ SQUIRREL_API const SQChar *sq_objtostring(HSQOBJECT *o); SQUIRREL_API SQBool sq_objtobool(HSQOBJECT *o); SQUIRREL_API SQInteger sq_objtointeger(HSQOBJECT *o); SQUIRREL_API SQFloat sq_objtofloat(HSQOBJECT *o); +SQUIRREL_API SQRESULT sq_getobjtypetag(HSQOBJECT *o,SQUserPointer * typetag); /*GC*/ SQUIRREL_API SQInteger sq_collectgarbage(HSQUIRRELVM v); @@ -371,6 +398,9 @@ SQUIRREL_API void sq_setdebughook(HSQUIRRELVM v); #define sq_isweakref(o) ((o)._type==OT_WEAKREF) #define sq_type(o) ((o)._type) +/* deprecated */ +#define sq_createslot(v,n) sq_newslot(v,n,SQFalse) + #define SQ_OK (0) #define SQ_ERROR (-1) diff --git a/src/squirrel/sqdbg/sqdbgserver.cpp b/src/squirrel/sqdbg/sqdbgserver.cpp index 7cdbe998f..c76ff0bff 100644 --- a/src/squirrel/sqdbg/sqdbgserver.cpp +++ b/src/squirrel/sqdbg/sqdbgserver.cpp @@ -537,7 +537,7 @@ void SQDbgServer::SerializeState() sq_createslot(_v,-3); } sq_rawset(_v,-3); - if(SQ_SUCCEEDED(sq_call(_v,1,SQTrue))){ + if(SQ_SUCCEEDED(sq_call(_v,1,SQTrue,SQTrue))){ if(SQ_SUCCEEDED(sqstd_getblob(_v,-1,(SQUserPointer*)&sz))) SendChunk(sz); } diff --git a/src/squirrel/sqstdlib/sqstdaux.cpp b/src/squirrel/sqstdlib/sqstdaux.cpp index 30808ed41..ddfac0812 100644 --- a/src/squirrel/sqstdlib/sqstdaux.cpp +++ b/src/squirrel/sqstdlib/sqstdaux.cpp @@ -1,6 +1,7 @@ /* see copyright notice in squirrel.h */ #include #include +#include void sqstd_printcallstack(HSQUIRRELVM v) { @@ -28,7 +29,7 @@ void sqstd_printcallstack(HSQUIRRELVM v) for(level=0;level<10;level++){ seq=0; - while(name=sq_getlocal(v,level,seq)) + while((name = sq_getlocal(v,level,seq))) { seq++; switch(sq_gettype(v,-1)) @@ -63,6 +64,9 @@ void sqstd_printcallstack(HSQUIRRELVM v) case OT_NATIVECLOSURE: pf(v,_SC("[%s] NATIVECLOSURE\n"),name); break; + case OT_GENERATOR: + pf(v,_SC("[%s] NATIVECLOSURE\n"),name); + break; case OT_USERDATA: pf(v,_SC("[%s] USERDATA\n"),name); break; @@ -75,6 +79,15 @@ void sqstd_printcallstack(HSQUIRRELVM v) case OT_INSTANCE: pf(v,_SC("[%s] INSTANCE\n"),name); break; + case OT_WEAKREF: + pf(v,_SC("[%s] INSTANCE\n"),name); + break; + case OT_BOOL:{ + sq_getinteger(v,-1,&i); + pf(v,_SC("[%s] %s\n"),name,i?_SC("true"):_SC("false")); + } + break; + default: assert(0); break; } sq_pop(v,1); } diff --git a/src/squirrel/sqstdlib/sqstdblob.cpp b/src/squirrel/sqstdlib/sqstdblob.cpp index 9b0fe5949..5036db11a 100644 --- a/src/squirrel/sqstdlib/sqstdblob.cpp +++ b/src/squirrel/sqstdlib/sqstdblob.cpp @@ -30,7 +30,7 @@ static SQInteger _blob_resize(HSQUIRRELVM v) static void __swap_dword(unsigned int *n) { - *n=(SQUnsignedInteger)(((*n&0xFF000000)>>24) | + *n=(unsigned int)(((*n&0xFF000000)>>24) | ((*n&0x00FF0000)>>8) | ((*n&0x0000FF00)<<8) | ((*n&0x000000FF)<<24)); @@ -182,8 +182,9 @@ static SQInteger _g_blob_swap4(HSQUIRRELVM v) { SQInteger i; sq_getinteger(v,2,&i); - __swap_dword((SQUnsignedInteger *)&i); - sq_pushinteger(v,i); + unsigned int t4 = (unsigned int)i; + __swap_dword(&t4); + sq_pushinteger(v,(SQInteger)t4); return 1; } @@ -191,7 +192,7 @@ static SQInteger _g_blob_swapfloat(HSQUIRRELVM v) { SQFloat f; sq_getfloat(v,2,&f); - __swap_dword((SQUnsignedInteger *)&f); + __swap_dword((unsigned int *)&f); sq_pushfloat(v,f); return 1; } @@ -233,7 +234,7 @@ SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size) sq_push(v,1); // push the this sq_pushinteger(v,size); //size SQBlob *blob = NULL; - if(SQ_SUCCEEDED(sq_call(v,2,SQTrue)) + if(SQ_SUCCEEDED(sq_call(v,2,SQTrue,SQFalse)) && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) { sq_remove(v,-2); sq_remove(v,-2); diff --git a/src/squirrel/sqstdlib/sqstdblobimpl.h b/src/squirrel/sqstdlib/sqstdblobimpl.h index b927e7c4e..b2291b73c 100644 --- a/src/squirrel/sqstdlib/sqstdblobimpl.h +++ b/src/squirrel/sqstdlib/sqstdblobimpl.h @@ -12,7 +12,7 @@ struct SQBlob : public SQStream _ptr = 0; _owns = true; } - ~SQBlob() { + virtual ~SQBlob() { sq_free(_buf, _allocated); } SQInteger Write(void *buffer, SQInteger size) { diff --git a/src/squirrel/sqstdlib/sqstdio.cpp b/src/squirrel/sqstdlib/sqstdio.cpp index 396d2226c..306cf12b7 100644 --- a/src/squirrel/sqstdlib/sqstdio.cpp +++ b/src/squirrel/sqstdlib/sqstdio.cpp @@ -35,7 +35,7 @@ SQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin) case SQ_SEEK_SET: realorigin = SEEK_SET; break; default: return -1; //failed } - return fseek((FILE *)file,offset,realorigin); + return fseek((FILE *)file,(long)offset,(int)realorigin); } SQInteger sqstd_ftell(SQFILE file) @@ -62,10 +62,10 @@ SQInteger sqstd_feof(SQFILE file) struct SQFile : public SQStream { SQFile() { _handle = NULL; _owns = false;} SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;} - ~SQFile() { Close(); } + virtual ~SQFile() { Close(); } bool Open(const SQChar *filename ,const SQChar *mode) { Close(); - if(_handle = sqstd_fopen(filename,mode)) { + if( (_handle = sqstd_fopen(filename,mode)) ) { _owns = true; return true; } @@ -172,7 +172,7 @@ SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own) else{ sq_pushnull(v); //false } - if(SQ_SUCCEEDED( sq_call(v,3,SQTrue) )) { + if(SQ_SUCCEEDED( sq_call(v,3,SQTrue,SQFalse) )) { sq_remove(v,-2); return SQ_OK; } @@ -326,8 +326,7 @@ SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool { if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) { sq_push(v,-2); - SQInteger ntop = sq_gettop(v); - if(SQ_SUCCEEDED(sq_call(v,1,retval))) { + if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) { sq_remove(v,retval?-2:-1); //removes the closure return 1; } @@ -361,6 +360,15 @@ SQInteger _g_io_loadfile(HSQUIRRELVM v) return SQ_ERROR; //propagates the error } +SQInteger _g_io_writeclosuretofile(HSQUIRRELVM v) +{ + const SQChar *filename; + sq_getstring(v,2,&filename); + if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,filename))) + return 1; + return SQ_ERROR; //propagates the error +} + SQInteger _g_io_dofile(HSQUIRRELVM v) { const SQChar *filename; @@ -379,6 +387,7 @@ SQInteger _g_io_dofile(HSQUIRRELVM v) static SQRegFunction iolib_funcs[]={ _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")), _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")), + _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(".sc")), {0,0} }; diff --git a/src/squirrel/sqstdlib/sqstdmath.cpp b/src/squirrel/sqstdlib/sqstdmath.cpp index 3d90ee975..ae1a219be 100644 --- a/src/squirrel/sqstdlib/sqstdmath.cpp +++ b/src/squirrel/sqstdlib/sqstdmath.cpp @@ -23,7 +23,7 @@ static SQInteger math_srand(HSQUIRRELVM v) { SQInteger i; if(!sq_getinteger(v,2,&i))return sq_throwerror(v,_SC("invalid param")); - srand(i); + srand((unsigned int)i); return 0; } @@ -37,7 +37,7 @@ static SQInteger math_abs(HSQUIRRELVM v) { SQInteger n; sq_getinteger(v,2,&n); - sq_pushinteger(v,(SQInteger)abs(n)); + sq_pushinteger(v,(SQInteger)abs((int)n)); return 1; } diff --git a/src/squirrel/sqstdlib/sqstdrex.c b/src/squirrel/sqstdlib/sqstdrex.c deleted file mode 100644 index e37a58c5d..000000000 --- a/src/squirrel/sqstdlib/sqstdrex.c +++ /dev/null @@ -1,586 +0,0 @@ -/* see copyright notice in squirrel.h */ -#include -#include -#include -#include -#include "sqstdstring.h" - -#ifdef _DEBUG -#include - -static const SQChar *g_nnames[] = -{ - _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"), - _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"), - _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"), - _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB") -}; - -#endif - -#define OP_GREEDY MAX_CHAR+1 // * + ? {n} -#define OP_OR MAX_CHAR+2 -#define OP_EXPR MAX_CHAR+3 //parentesis () -#define OP_NOCAPEXPR MAX_CHAR+4 //parentesis (?:) -#define OP_DOT MAX_CHAR+5 -#define OP_CLASS MAX_CHAR+6 -#define OP_CCLASS MAX_CHAR+7 -#define OP_NCLASS MAX_CHAR+8 //negates class the [^ -#define OP_RANGE MAX_CHAR+9 -#define OP_CHAR MAX_CHAR+10 -#define OP_EOL MAX_CHAR+11 -#define OP_BOL MAX_CHAR+12 -#define OP_WB MAX_CHAR+13 - -#define SQREX_SYMBOL_ANY_CHAR '.' -#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE '+' -#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE '*' -#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE '?' -#define SQREX_SYMBOL_BRANCH '|' -#define SQREX_SYMBOL_END_OF_STRING '$' -#define SQREX_SYMBOL_BEGINNING_OF_STRING '^' -#define SQREX_SYMBOL_ESCAPE_CHAR '\\' - - -typedef int SQRexNodeType; - -typedef struct tagSQRexNode{ - SQRexNodeType type; - SQInteger left; - SQInteger right; - SQInteger next; -}SQRexNode; - -struct SQRex{ - const SQChar *_eol; - const SQChar *_bol; - const SQChar *_p; - SQInteger _first; - SQInteger _op; - SQRexNode *_nodes; - SQInteger _nallocated; - SQInteger _nsize; - SQInteger _nsubexpr; - SQRexMatch *_matches; - SQInteger _currsubexp; - void *_jmpbuf; - const SQChar **_error; -}; - -static SQInteger sqstd_rex_list(SQRex *exp); - -static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type) -{ - SQRexNode n; - n.type = type; - n.next = n.right = n.left = -1; - if(type == OP_EXPR) - n.right = exp->_nsubexpr++; - if(exp->_nallocated < (exp->_nsize + 1)) { - SQInteger oldsize = exp->_nallocated; - exp->_nallocated *= 2; - exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode)); - } - exp->_nodes[exp->_nsize++] = n; - return (SQInteger)exp->_nsize - 1; -} - -static void sqstd_rex_error(SQRex *exp,const SQChar *error) -{ - if(exp->_error) *exp->_error = error; - longjmp(*((jmp_buf*)exp->_jmpbuf),-1); -} - -static void sqstd_rex_expect(SQRex *exp, SQInteger n){ - if((*exp->_p) != n) - sqstd_rex_error(exp, _SC("expected paren")); - exp->_p++; -} - -static SQBool sqstd_rex_ischar(SQChar c) -{ - switch(c) { - case SQREX_SYMBOL_BRANCH:case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: - case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE:case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: - case SQREX_SYMBOL_BEGINNING_OF_STRING:case SQREX_SYMBOL_END_OF_STRING: - case SQREX_SYMBOL_ANY_CHAR:case SQREX_SYMBOL_ESCAPE_CHAR:case '(':case ')':case '[':case '{': case '}': - return SQFalse; - } - return SQTrue; -} - -static SQChar sqstd_rex_escapechar(SQRex *exp) -{ - if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){ - exp->_p++; - switch(*exp->_p) { - case 'v': exp->_p++; return '\v'; - case 'n': exp->_p++; return '\n'; - case 't': exp->_p++; return '\t'; - case 'r': exp->_p++; return '\r'; - case 'f': exp->_p++; return '\f'; - default: return (*exp->_p++); - } - } else if(!sqstd_rex_ischar(*exp->_p)) sqstd_rex_error(exp,_SC("letter expected")); - return (*exp->_p++); -} - -static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid) -{ - SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS); - exp->_nodes[n].left = classid; - return n; -} - -static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass) -{ - if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) { - exp->_p++; - switch(*exp->_p) { - case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n'); - case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t'); - case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r'); - case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f'); - case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v'); - case 'a': case 'A': case 'w': case 'W': case 's': case 'S': - case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': - case 'p': case 'P': case 'l': case 'u': - { - SQChar t = *exp->_p; - exp->_p++; - return sqstd_rex_charclass(exp,t); - } - case 'b': - case 'B': - if(!isclass) { - SQInteger node = sqstd_rex_newnode(exp,OP_WB); - exp->_nodes[node].left = *exp->_p; - exp->_p++; - return node; - } //else default - default: return sqstd_rex_newnode(exp,(*exp->_p++)); - } - } - else if(!sqstd_rex_ischar(*exp->_p)) { - - sqstd_rex_error(exp,_SC("letter expected")); - } - return sqstd_rex_newnode(exp,*exp->_p++); -} -static SQInteger sqstd_rex_class(SQRex *exp) -{ - SQInteger ret = -1; - SQInteger first = -1,chain; - if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){ - ret = sqstd_rex_newnode(exp,OP_NCLASS); - exp->_p++; - }else ret = sqstd_rex_newnode(exp,OP_CLASS); - - if(*exp->_p == ']' || *exp->_p == '-'){ - first = *exp->_p; - exp->_p++; - } - chain = ret; - while(*exp->_p != ']' && exp->_p != exp->_eol) { - if(*exp->_p == '-' && first != -1){ - SQInteger r; - if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range")); - r = sqstd_rex_newnode(exp,OP_RANGE); - if(first>*exp->_p) sqstd_rex_error(exp,_SC("invalid range")); - if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC("cannot use character classes in ranges")); - exp->_nodes[r].left = exp->_nodes[first].type; - exp->_nodes[r].right = sqstd_rex_escapechar(exp); - exp->_nodes[chain].next = r; - chain = r; - first = -1; - } - else{ - if(first!=-1){ - SQInteger c = first; - exp->_nodes[chain].next = c; - chain = c; - first = sqstd_rex_charnode(exp,SQTrue); - } - else{ - first = sqstd_rex_charnode(exp,SQTrue); - } - } - } - if(first!=-1){ - SQInteger c = first; - exp->_nodes[chain].next = c; - chain = c; - first = -1; - } - /* hack? */ - exp->_nodes[ret].left = exp->_nodes[ret].next; - exp->_nodes[ret].next = -1; - return ret; -} - -static SQInteger sqstd_rex_parsenumber(SQRex *exp) -{ - SQInteger ret = *exp->_p-'0'; - SQInteger positions = 10; - exp->_p++; - while(isdigit(*exp->_p)) { - ret = ret*10+(*exp->_p++-'0'); - if(positions==1000000000) sqstd_rex_error(exp,_SC("overflow in numeric constant")); - positions *= 10; - }; - return ret; -} - -static SQInteger sqstd_rex_element(SQRex *exp) -{ - SQInteger ret; - switch(*exp->_p) - { - case '(': { - SQInteger expr; - exp->_p++; - - - if(*exp->_p =='?') { - exp->_p++; - sqstd_rex_expect(exp,':'); - expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR); - } - else - expr = sqstd_rex_newnode(exp,OP_EXPR); - exp->_nodes[expr].left = sqstd_rex_list(exp); - ret = expr; - sqstd_rex_expect(exp,')'); - } - break; - case '[': - exp->_p++; - ret = sqstd_rex_class(exp); - sqstd_rex_expect(exp,']'); - break; - case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break; - case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break; - default: - ret = sqstd_rex_charnode(exp,SQFalse); - break; - } - /* scope block */ - { - SQInteger op; - unsigned short p0 = 0, p1 = 0; - switch(*exp->_p){ - case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; goto __end; - case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; goto __end; - case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; goto __end; - case '{':{ - exp->_p++; - if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC("number expected")); - p0 = sqstd_rex_parsenumber(exp); - switch(*exp->_p) { - case '}': - p1 = p0; exp->_p++; - goto __end; - case ',': - exp->_p++; - p1 = 0xFFFF; - if(isdigit(*exp->_p)){ - p1 = sqstd_rex_parsenumber(exp); - } - sqstd_rex_expect(exp,'}'); - goto __end; - default: - sqstd_rex_error(exp,_SC(", or } expected")); - } - } - __end: { - SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY); - op = OP_GREEDY; - exp->_nodes[nnode].left = ret; - exp->_nodes[nnode].right = ((p0)<<16)|p1; - ret = nnode; - } - } - } - 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') - exp->_nodes[ret].next = sqstd_rex_element(exp); - return ret; -} - -static SQInteger sqstd_rex_list(SQRex *exp) -{ - SQInteger ret=-1,e; - if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) { - exp->_p++; - ret = sqstd_rex_newnode(exp,OP_BOL); - } - e = sqstd_rex_element(exp); - if(ret != -1) { - exp->_nodes[ret].next = e; - } - else ret = e; - - if(*exp->_p == SQREX_SYMBOL_BRANCH) { - SQInteger temp; - exp->_p++; - temp = sqstd_rex_newnode(exp,OP_OR); - exp->_nodes[temp].left = ret; - exp->_nodes[temp].right = sqstd_rex_list(exp); - ret = temp; - } - return ret; -} - -static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c) -{ - switch(cclass) { - case 'a': return isalpha(c)?SQTrue:SQFalse; - case 'A': return !isalpha(c)?SQTrue:SQFalse; - case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse; - case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse; - case 's': return isspace(c)?SQTrue:SQFalse; - case 'S': return !isspace(c)?SQTrue:SQFalse; - case 'd': return isdigit(c)?SQTrue:SQFalse; - case 'D': return !isdigit(c)?SQTrue:SQFalse; - case 'x': return isxdigit(c)?SQTrue:SQFalse; - case 'X': return !isxdigit(c)?SQTrue:SQFalse; - case 'c': return iscntrl(c)?SQTrue:SQFalse; - case 'C': return !iscntrl(c)?SQTrue:SQFalse; - case 'p': return ispunct(c)?SQTrue:SQFalse; - case 'P': return !ispunct(c)?SQTrue:SQFalse; - case 'l': return islower(c)?SQTrue:SQFalse; - case 'u': return isupper(c)?SQTrue:SQFalse; - } - return SQFalse; /*cannot happen*/ -} - -static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQChar c) -{ - do { - switch(node->type) { - case OP_RANGE: - if(c >= node->left && c <= node->right) return SQTrue; - break; - case OP_CCLASS: - if(sqstd_rex_matchcclass(node->left,c)) return SQTrue; - break; - default: - if(c == node->type)return SQTrue; - } - } while((node->next != -1) && (node = &exp->_nodes[node->next])); - return SQFalse; -} - -static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str) -{ - SQRexNodeType type = node->type; - switch(type) { - case OP_GREEDY: { - SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; - const SQChar *s=str, *good = str; - while((nmaches == 0xFFFF || nmaches < p1) - && (s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s))) { - good=s; - nmaches++; - if(s >= exp->_eol) - break; - } - if(p0 == p1 && p0 == nmaches) return good; - else if(nmaches >= p0 && p1 == 0xFFFF) return good; - else if(nmaches >= p0 && nmaches <= p1) return good; - return NULL; - } - case OP_OR: { - const SQChar *asd = str; - SQRexNode *temp=&exp->_nodes[node->left]; - while(asd = sqstd_rex_matchnode(exp,temp,asd)) { - if(temp->next != -1) - temp = &exp->_nodes[temp->next]; - else - return asd; - } - asd = str; - temp = &exp->_nodes[node->right]; - while(asd = sqstd_rex_matchnode(exp,temp,asd)) { - if(temp->next != -1) - temp = &exp->_nodes[temp->next]; - else - return asd; - } - return NULL; - break; - } - case OP_EXPR: - case OP_NOCAPEXPR:{ - SQRexNode *n = &exp->_nodes[node->left]; - const SQChar *cur = str; - SQInteger capture = -1; - if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { - capture = exp->_currsubexp; - exp->_matches[capture].begin = cur; - exp->_currsubexp++; - } - - do { - if(!(cur = sqstd_rex_matchnode(exp,n,cur))) { - if(capture != -1){ - exp->_matches[capture].begin = 0; - exp->_matches[capture].len = 0; - } - return NULL; - } - } while((n->next != -1) && (n = &exp->_nodes[n->next])); - - if(capture != -1) - exp->_matches[capture].len = cur - exp->_matches[capture].begin; - return cur; - } - case OP_WB: - if(str == exp->_bol && !isspace(*str) - || (str == exp->_eol && !isspace(*(str-1))) - || (!isspace(*str) && isspace(*(str+1))) - || (isspace(*str) && !isspace(*(str+1))) ) { - return (node->left == 'b')?str:NULL; - } - return (node->left == 'b')?NULL:str; - case OP_BOL: - if(str == exp->_bol) return str; - return NULL; - case OP_EOL: - if(str == exp->_eol) return str; - return NULL; - case OP_DOT: - *str++; - return str; - case OP_NCLASS: - case OP_CLASS: - if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) { - *str++; - return str; - } - return NULL; - case OP_CCLASS: - if(sqstd_rex_matchcclass(node->left,*str)) { - *str++; - return str; - } - return NULL; - default: /* char */ - if(*str != node->type) return NULL; - *str++; - return str; - } - return NULL; -} - -/* public api */ -SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error) -{ - SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex)); - exp->_p = pattern; - exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar); - exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode)); - exp->_nsize = 0; - exp->_matches = 0; - exp->_nsubexpr = 0; - exp->_first = sqstd_rex_newnode(exp,OP_EXPR); - exp->_error = error; - exp->_jmpbuf = sq_malloc(sizeof(jmp_buf)); - if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) { - exp->_nodes[exp->_first].left=sqstd_rex_list(exp); - if(*exp->_p!='\0') - sqstd_rex_error(exp,_SC("unexpected character")); -#ifdef _DEBUG - { - SQInteger nsize,i; - SQRexNode *t; - nsize = exp->_nsize; - t = &exp->_nodes[0]; - scprintf(_SC("\n")); - for(i = 0;i < nsize; i++) { - if(exp->_nodes[i].type>MAX_CHAR) - scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]); - else - scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type); - scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next); - } - scprintf(_SC("\n")); - } -#endif - exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch)); - memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch)); - } - else{ - sqstd_rex_free(exp); - return NULL; - } - return exp; -} - -void sqstd_rex_free(SQRex *exp) -{ - if(exp) { - if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode)); - if(exp->_jmpbuf) sq_free(exp->_jmpbuf,sizeof(jmp_buf)); - if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch)); - sq_free(exp,sizeof(SQRex)); - } -} - -SQBool sqstd_rex_match(SQRex* exp,const SQChar* text) -{ - const SQChar* res = NULL; - exp->_bol = text; - exp->_eol = text + scstrlen(text); - exp->_currsubexp = 0; - res = sqstd_rex_matchnode(exp,exp->_nodes,text); - if(res == NULL || res != exp->_eol) - return SQFalse; - return SQTrue; -} - -SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end) -{ - const SQChar *cur = NULL; - SQInteger node = exp->_first; - if(text_begin >= text_end) return SQFalse; - exp->_bol = text_begin; - exp->_eol = text_end; - do { - cur = text_begin; - while(node != -1) { - exp->_currsubexp = 0; - cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur); - if(!cur) - break; - node = exp->_nodes[node].next; - } - *text_begin++; - } while(cur == NULL && text_begin != text_end); - - if(cur == NULL) - return SQFalse; - - --text_begin; - - if(out_begin) *out_begin = text_begin; - if(out_end) *out_end = cur; - return SQTrue; -} - -SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end) -{ - return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end); -} - -SQInteger sqstd_rex_getsubexpcount(SQRex* exp) -{ - return exp->_nsubexpr; -} - -SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp) -{ - if( n<0 || n >= exp->_nsubexpr) return SQFalse; - *subexp = exp->_matches[n]; - return SQTrue; -} - diff --git a/src/squirrel/sqstdlib/sqstdrex.cpp b/src/squirrel/sqstdlib/sqstdrex.cpp new file mode 100644 index 000000000..9c3c2685d --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdrex.cpp @@ -0,0 +1,633 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include "sqstdstring.h" + +#ifdef _UINCODE +#define scisprint iswprint +#else +#define scisprint isprint +#endif + +#ifdef _DEBUG +#include + +static const SQChar *g_nnames[] = +{ + _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"), + _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"), + _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"), + _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB") +}; + +#endif + +#define OP_GREEDY MAX_CHAR+1 // * + ? {n} +#define OP_OR MAX_CHAR+2 +#define OP_EXPR MAX_CHAR+3 //parentesis () +#define OP_NOCAPEXPR MAX_CHAR+4 //parentesis (?:) +#define OP_DOT MAX_CHAR+5 +#define OP_CLASS MAX_CHAR+6 +#define OP_CCLASS MAX_CHAR+7 +#define OP_NCLASS MAX_CHAR+8 //negates class the [^ +#define OP_RANGE MAX_CHAR+9 +#define OP_CHAR MAX_CHAR+10 +#define OP_EOL MAX_CHAR+11 +#define OP_BOL MAX_CHAR+12 +#define OP_WB MAX_CHAR+13 + +#define SQREX_SYMBOL_ANY_CHAR '.' +#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE '+' +#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE '*' +#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE '?' +#define SQREX_SYMBOL_BRANCH '|' +#define SQREX_SYMBOL_END_OF_STRING '$' +#define SQREX_SYMBOL_BEGINNING_OF_STRING '^' +#define SQREX_SYMBOL_ESCAPE_CHAR '\\' + + +typedef int SQRexNodeType; + +typedef struct tagSQRexNode{ + SQRexNodeType type; + SQInteger left; + SQInteger right; + SQInteger next; +}SQRexNode; + +struct SQRex{ + const SQChar *_eol; + const SQChar *_bol; + const SQChar *_p; + SQInteger _first; + SQInteger _op; + SQRexNode *_nodes; + SQInteger _nallocated; + SQInteger _nsize; + SQInteger _nsubexpr; + SQRexMatch *_matches; + SQInteger _currsubexp; + void *_jmpbuf; + const SQChar **_error; +}; + +static SQInteger sqstd_rex_list(SQRex *exp); + +static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type) +{ + SQRexNode n; + n.type = type; + n.next = n.right = n.left = -1; + if(type == OP_EXPR) + n.right = exp->_nsubexpr++; + if(exp->_nallocated < (exp->_nsize + 1)) { + SQInteger oldsize = exp->_nallocated; + exp->_nallocated *= 2; + exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode)); + } + exp->_nodes[exp->_nsize++] = n; + return (SQInteger)exp->_nsize - 1; +} + +static void sqstd_rex_error(SQRex *exp,const SQChar *error) +{ + if(exp->_error) *exp->_error = error; + longjmp(*((jmp_buf*)exp->_jmpbuf),-1); +} + +static void sqstd_rex_expect(SQRex *exp, SQInteger n){ + if((*exp->_p) != n) + sqstd_rex_error(exp, _SC("expected paren")); + exp->_p++; +} + +/*static SQBool sqstd_rex_ischar(SQChar c) +{ + switch(c) { + case SQREX_SYMBOL_BRANCH:case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: + case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE:case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: + case SQREX_SYMBOL_BEGINNING_OF_STRING:case SQREX_SYMBOL_END_OF_STRING: + case SQREX_SYMBOL_ANY_CHAR:case SQREX_SYMBOL_ESCAPE_CHAR:case '(':case ')':case '[':case '{': case '}': + return SQFalse; + } + return SQTrue; +}*/ + +static SQChar sqstd_rex_escapechar(SQRex *exp) +{ + if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){ + exp->_p++; + switch(*exp->_p) { + case 'v': exp->_p++; return '\v'; + case 'n': exp->_p++; return '\n'; + case 't': exp->_p++; return '\t'; + case 'r': exp->_p++; return '\r'; + case 'f': exp->_p++; return '\f'; + default: return (*exp->_p++); + } + } else if(!scisprint(*exp->_p)) sqstd_rex_error(exp,_SC("letter expected")); + return (*exp->_p++); +} + +static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid) +{ + SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS); + exp->_nodes[n].left = classid; + return n; +} + +static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass) +{ + if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) { + exp->_p++; + switch(*exp->_p) { + case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n'); + case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t'); + case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r'); + case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f'); + case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v'); + case 'a': case 'A': case 'w': case 'W': case 's': case 'S': + case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': + case 'p': case 'P': case 'l': case 'u': + { + SQChar t = *exp->_p; + exp->_p++; + return sqstd_rex_charclass(exp,t); + } + case 'b': + case 'B': + if(!isclass) { + SQInteger node = sqstd_rex_newnode(exp,OP_WB); + exp->_nodes[node].left = *exp->_p; + exp->_p++; + return node; + } //else default + default: return sqstd_rex_newnode(exp,(*exp->_p++)); + } + } + else if(!scisprint(*exp->_p)) { + + sqstd_rex_error(exp,_SC("letter expected")); + } + return sqstd_rex_newnode(exp,*exp->_p++); +} +static SQInteger sqstd_rex_class(SQRex *exp) +{ + SQInteger ret = -1; + SQInteger first = -1,chain; + if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){ + ret = sqstd_rex_newnode(exp,OP_NCLASS); + exp->_p++; + }else ret = sqstd_rex_newnode(exp,OP_CLASS); + + if(*exp->_p == ']') sqstd_rex_error(exp,_SC("empty class")); + chain = ret; + while(*exp->_p != ']' && exp->_p != exp->_eol) { + if(*exp->_p == '-' && first != -1){ + SQInteger r; + if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range")); + r = sqstd_rex_newnode(exp,OP_RANGE); + if(first>*exp->_p) sqstd_rex_error(exp,_SC("invalid range")); + if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC("cannot use character classes in ranges")); + exp->_nodes[r].left = exp->_nodes[first].type; + exp->_nodes[r].right = sqstd_rex_escapechar(exp); + exp->_nodes[chain].next = r; + chain = r; + first = -1; + } + else{ + if(first!=-1){ + SQInteger c = first; + exp->_nodes[chain].next = c; + chain = c; + first = sqstd_rex_charnode(exp,SQTrue); + } + else{ + first = sqstd_rex_charnode(exp,SQTrue); + } + } + } + if(first!=-1){ + SQInteger c = first; + exp->_nodes[chain].next = c; + chain = c; + first = -1; + } + /* hack? */ + exp->_nodes[ret].left = exp->_nodes[ret].next; + exp->_nodes[ret].next = -1; + return ret; +} + +static SQInteger sqstd_rex_parsenumber(SQRex *exp) +{ + SQInteger ret = *exp->_p-'0'; + SQInteger positions = 10; + exp->_p++; + while(isdigit(*exp->_p)) { + ret = ret*10+(*exp->_p++-'0'); + if(positions==1000000000) sqstd_rex_error(exp,_SC("overflow in numeric constant")); + positions *= 10; + }; + return ret; +} + +static SQInteger sqstd_rex_element(SQRex *exp) +{ + SQInteger ret; + switch(*exp->_p) + { + case '(': { + SQInteger expr; + exp->_p++; + + + if(*exp->_p =='?') { + exp->_p++; + sqstd_rex_expect(exp,':'); + expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR); + } + else + expr = sqstd_rex_newnode(exp,OP_EXPR); + exp->_nodes[expr].left = sqstd_rex_list(exp); + ret = expr; + sqstd_rex_expect(exp,')'); + } + break; + case '[': + exp->_p++; + ret = sqstd_rex_class(exp); + sqstd_rex_expect(exp,']'); + break; + case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break; + case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break; + default: + ret = sqstd_rex_charnode(exp,SQFalse); + break; + } + /* scope block */ + { + SQInteger op; + unsigned short p0 = 0, p1 = 0; + switch(*exp->_p){ + case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; goto __end; + case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; goto __end; + case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; goto __end; + case '{':{ + exp->_p++; + if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC("number expected")); + p0 = (unsigned short)sqstd_rex_parsenumber(exp); + switch(*exp->_p) { + case '}': + p1 = p0; exp->_p++; + goto __end; + case ',': + exp->_p++; + p1 = 0xFFFF; + if(isdigit(*exp->_p)){ + p1 = (unsigned short)sqstd_rex_parsenumber(exp); + } + sqstd_rex_expect(exp,'}'); + goto __end; + default: + sqstd_rex_error(exp,_SC(", or } expected")); + } + } + __end: { + SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY); + op = OP_GREEDY; + exp->_nodes[nnode].left = ret; + exp->_nodes[nnode].right = ((p0)<<16)|p1; + ret = nnode; + } + } + } + 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') + exp->_nodes[ret].next = sqstd_rex_element(exp); + return ret; +} + +static SQInteger sqstd_rex_list(SQRex *exp) +{ + SQInteger ret=-1,e; + if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) { + exp->_p++; + ret = sqstd_rex_newnode(exp,OP_BOL); + } + e = sqstd_rex_element(exp); + if(ret != -1) { + exp->_nodes[ret].next = e; + } + else ret = e; + + if(*exp->_p == SQREX_SYMBOL_BRANCH) { + SQInteger temp; + exp->_p++; + temp = sqstd_rex_newnode(exp,OP_OR); + exp->_nodes[temp].left = ret; + exp->_nodes[temp].right = sqstd_rex_list(exp); + ret = temp; + } + return ret; +} + +static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c) +{ + switch(cclass) { + case 'a': return isalpha(c)?SQTrue:SQFalse; + case 'A': return !isalpha(c)?SQTrue:SQFalse; + case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse; + case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse; + case 's': return isspace(c)?SQTrue:SQFalse; + case 'S': return !isspace(c)?SQTrue:SQFalse; + case 'd': return isdigit(c)?SQTrue:SQFalse; + case 'D': return !isdigit(c)?SQTrue:SQFalse; + case 'x': return isxdigit(c)?SQTrue:SQFalse; + case 'X': return !isxdigit(c)?SQTrue:SQFalse; + case 'c': return iscntrl(c)?SQTrue:SQFalse; + case 'C': return !iscntrl(c)?SQTrue:SQFalse; + case 'p': return ispunct(c)?SQTrue:SQFalse; + case 'P': return !ispunct(c)?SQTrue:SQFalse; + case 'l': return islower(c)?SQTrue:SQFalse; + case 'u': return isupper(c)?SQTrue:SQFalse; + } + return SQFalse; /*cannot happen*/ +} + +static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQChar c) +{ + do { + switch(node->type) { + case OP_RANGE: + if(c >= node->left && c <= node->right) return SQTrue; + break; + case OP_CCLASS: + if(sqstd_rex_matchcclass(node->left,c)) return SQTrue; + break; + default: + if(c == node->type)return SQTrue; + } + } while((node->next != -1) && (node = &exp->_nodes[node->next])); + return SQFalse; +} + +static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str,SQRexNode *next) +{ + + SQRexNodeType type = node->type; + switch(type) { + case OP_GREEDY: { + //SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; + SQRexNode *greedystop = NULL; + SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; + const SQChar *s=str, *good = str; + + if(node->next != -1) { + greedystop = &exp->_nodes[node->next]; + } + else { + greedystop = next; + } + + while((nmaches == 0xFFFF || nmaches < p1)) { + + const SQChar *stop; + if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop))) + break; + nmaches++; + good=s; + if(greedystop) { + //checks that 0 matches satisfy the expression(if so skips) + //if not would always stop(for instance if is a '?') + if(greedystop->type != OP_GREEDY || + (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0)) + { + SQRexNode *gnext = NULL; + if(greedystop->next != -1) { + gnext = &exp->_nodes[greedystop->next]; + }else if(next && next->next != -1){ + gnext = &exp->_nodes[next->next]; + } + stop = sqstd_rex_matchnode(exp,greedystop,s,gnext); + if(stop) { + //if satisfied stop it + if(p0 == p1 && p0 == nmaches) break; + else if(nmaches >= p0 && p1 == 0xFFFF) break; + else if(nmaches >= p0 && nmaches <= p1) break; + } + } + } + + if(s >= exp->_eol) + break; + } + if(p0 == p1 && p0 == nmaches) return good; + else if(nmaches >= p0 && p1 == 0xFFFF) return good; + else if(nmaches >= p0 && nmaches <= p1) return good; + return NULL; + } + case OP_OR: { + const SQChar *asd = str; + SQRexNode *temp=&exp->_nodes[node->left]; + while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) { + if(temp->next != -1) + temp = &exp->_nodes[temp->next]; + else + return asd; + } + asd = str; + temp = &exp->_nodes[node->right]; + while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) { + if(temp->next != -1) + temp = &exp->_nodes[temp->next]; + else + return asd; + } + return NULL; + break; + } + case OP_EXPR: + case OP_NOCAPEXPR:{ + SQRexNode *n = &exp->_nodes[node->left]; + const SQChar *cur = str; + SQInteger capture = -1; + if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { + capture = exp->_currsubexp; + exp->_matches[capture].begin = cur; + exp->_currsubexp++; + } + + do { + SQRexNode *subnext = NULL; + if(n->next != -1) { + subnext = &exp->_nodes[n->next]; + }else { + subnext = next; + } + if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) { + if(capture != -1){ + exp->_matches[capture].begin = 0; + exp->_matches[capture].len = 0; + } + return NULL; + } + } while((n->next != -1) && (n = &exp->_nodes[n->next])); + + if(capture != -1) + exp->_matches[capture].len = cur - exp->_matches[capture].begin; + return cur; + } + case OP_WB: + if(str == exp->_bol && !isspace(*str) + || (str == exp->_eol && !isspace(*(str-1))) + || (!isspace(*str) && isspace(*(str+1))) + || (isspace(*str) && !isspace(*(str+1))) ) { + return (node->left == 'b')?str:NULL; + } + return (node->left == 'b')?NULL:str; + case OP_BOL: + if(str == exp->_bol) return str; + return NULL; + case OP_EOL: + if(str == exp->_eol) return str; + return NULL; + case OP_DOT:{ + *str++; + } + return str; + case OP_NCLASS: + case OP_CLASS: + if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) { + *str++; + return str; + } + return NULL; + case OP_CCLASS: + if(sqstd_rex_matchcclass(node->left,*str)) { + *str++; + return str; + } + return NULL; + default: /* char */ + if(*str != node->type) return NULL; + *str++; + return str; + } + return NULL; +} + +/* public api */ +SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error) +{ + SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex)); + exp->_eol = exp->_bol = NULL; + exp->_p = pattern; + exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar); + exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode)); + exp->_nsize = 0; + exp->_matches = 0; + exp->_nsubexpr = 0; + exp->_first = sqstd_rex_newnode(exp,OP_EXPR); + exp->_error = error; + exp->_jmpbuf = sq_malloc(sizeof(jmp_buf)); + if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) { + exp->_nodes[exp->_first].left=sqstd_rex_list(exp); + if(*exp->_p!='\0') + sqstd_rex_error(exp,_SC("unexpected character")); +#ifdef _DEBUG + { + SQInteger nsize,i; + SQRexNode *t; + nsize = exp->_nsize; + t = &exp->_nodes[0]; + scprintf(_SC("\n")); + for(i = 0;i < nsize; i++) { + if(exp->_nodes[i].type>MAX_CHAR) + scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]); + else + scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type); + scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next); + } + scprintf(_SC("\n")); + } +#endif + exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch)); + memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch)); + } + else{ + sqstd_rex_free(exp); + return NULL; + } + return exp; +} + +void sqstd_rex_free(SQRex *exp) +{ + if(exp) { + if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode)); + if(exp->_jmpbuf) sq_free(exp->_jmpbuf,sizeof(jmp_buf)); + if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch)); + sq_free(exp,sizeof(SQRex)); + } +} + +SQBool sqstd_rex_match(SQRex* exp,const SQChar* text) +{ + const SQChar* res = NULL; + exp->_bol = text; + exp->_eol = text + scstrlen(text); + exp->_currsubexp = 0; + res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL); + if(res == NULL || res != exp->_eol) + return SQFalse; + return SQTrue; +} + +SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end) +{ + const SQChar *cur = NULL; + SQInteger node = exp->_first; + if(text_begin >= text_end) return SQFalse; + exp->_bol = text_begin; + exp->_eol = text_end; + do { + cur = text_begin; + while(node != -1) { + exp->_currsubexp = 0; + cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL); + if(!cur) + break; + node = exp->_nodes[node].next; + } + *text_begin++; + } while(cur == NULL && text_begin != text_end); + + if(cur == NULL) + return SQFalse; + + --text_begin; + + if(out_begin) *out_begin = text_begin; + if(out_end) *out_end = cur; + return SQTrue; +} + +SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end) +{ + return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end); +} + +SQInteger sqstd_rex_getsubexpcount(SQRex* exp) +{ + return exp->_nsubexpr; +} + +SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp) +{ + if( n<0 || n >= exp->_nsubexpr) return SQFalse; + *subexp = exp->_matches[n]; + return SQTrue; +} + diff --git a/src/squirrel/sqstdlib/sqstdstream.cpp b/src/squirrel/sqstdlib/sqstdstream.cpp index a02c0220c..669ca23f3 100644 --- a/src/squirrel/sqstdlib/sqstdstream.cpp +++ b/src/squirrel/sqstdlib/sqstdstream.cpp @@ -16,53 +16,6 @@ if(!self->IsValid()) \ return sq_throwerror(v,_SC("the stream is invalid")); -SQInteger _stream_readstr(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - SQInteger type = _SC('a'), size = 0; - sq_getinteger(v, 2, &size); - if(size <= 0) return sq_throwerror(v,_SC("invalid size")); - if(sq_gettop(v) > 2) - sq_getinteger(v, 3, &type); - SQChar *dest = NULL; - switch(type) { - case _SC('a'): { - char *temp; - if(self->Read(sq_getscratchpad(v, size+1), size) != size) - return sq_throwerror(v, _SC("io failure")); -#ifdef _UNICODE - temp = (char*) sq_getscratchpad(v, size + (size * sizeof(SQChar))); - dest = (SQChar*) &temp[size]; - size = (SQInteger)mbstowcs(dest, (const char*)temp, size); -#else - temp = (char *) sq_getscratchpad(v, -1); - dest = temp; -#endif - } - break; - case _SC('u'): { - wchar_t *temp; - if(self->Read(sq_getscratchpad(v, (size + 1) * sizeof(wchar_t)),size * sizeof(wchar_t)) != (size * sizeof(wchar_t))) - return sq_throwerror(v, _SC("io failure")); - -#ifdef _UNICODE - temp = (wchar_t*) sq_getscratchpad(v, -1); - dest = (SQChar*) temp; -#else - temp = (wchar_t*) sq_getscratchpad(v,(size * 3) + (size * sizeof(wchar_t))); - dest = (char*) &temp[size]; - size = (SQInteger)wcstombs(dest, (const wchar_t*)temp, size); -#endif - } - break; - default: - return sq_throwerror(v, _SC("invalid coding")); - } - - sq_pushstring(v, dest, size); - return 1; -} - SQInteger _stream_readblob(HSQUIRRELVM v) { SETUP_STREAM(v); @@ -90,12 +43,18 @@ SQInteger _stream_readn(HSQUIRRELVM v) SQInteger format; sq_getinteger(v, 2, &format); switch(format) { - case 'i': { + case 'l': { SQInteger i; SAFE_READN(&i, sizeof(i)); sq_pushinteger(v, i); } break; + case 'i': { + SQInt32 i; + SAFE_READN(&i, sizeof(i)); + sq_pushinteger(v, i); + } + break; case 's': { short s; SAFE_READN(&s, sizeof(short)); @@ -138,42 +97,6 @@ SQInteger _stream_readn(HSQUIRRELVM v) return 1; } -SQInteger _stream_writestr(HSQUIRRELVM v) -{ - SETUP_STREAM(v); - const SQChar *str,*res; - SQInteger trgformat = 'a',len = 0; - sq_getstring(v,2,&str); - len = sq_getsize(v,2); - if(sq_gettop(v)>2) - sq_getinteger(v,3,&trgformat); - switch(trgformat) - { - case 'a': -#ifdef _UNICODE - res = sq_getscratchpad(v,len*3); - len = (SQInteger) wcstombs((char *)res, (const wchar_t*)str, len); -#else - res = str; -#endif - self->Write((void *)res,len); - break; - case 'u': -#ifdef _UNICODE - res = str; -#else - res = sq_getscratchpad(v,len*sizeof(wchar_t)); - len = (SQInteger) mbstowcs((wchar_t*)res, str, len); -#endif - self->Write((void *)res,len*sizeof(wchar_t)); - break; - default: - return sq_throwerror(v,_SC("wrong encoding")); - } - - return 0; -} - SQInteger _stream_writeblob(HSQUIRRELVM v) { SQUserPointer data; @@ -195,38 +118,45 @@ SQInteger _stream_writen(HSQUIRRELVM v) SQFloat tf; sq_getinteger(v, 3, &format); switch(format) { - case 'i': { + case 'l': { SQInteger i; sq_getinteger(v, 2, &ti); i = ti; self->Write(&i, sizeof(SQInteger)); } break; + case 'i': { + SQInt32 i; + sq_getinteger(v, 2, &ti); + i = (SQInt32)ti; + self->Write(&i, sizeof(SQInt32)); + } + break; case 's': { short s; sq_getinteger(v, 2, &ti); - s = ti; + s = (short)ti; self->Write(&s, sizeof(short)); } break; case 'w': { unsigned short w; sq_getinteger(v, 2, &ti); - w = ti; + w = (unsigned short)ti; self->Write(&w, sizeof(unsigned short)); } break; case 'c': { char c; sq_getinteger(v, 2, &ti); - c = ti; + c = (char)ti; self->Write(&c, sizeof(char)); } break; case 'b': { unsigned char b; sq_getinteger(v, 2, &ti); - b = ti; + b = (unsigned char)ti; self->Write(&b, sizeof(unsigned char)); } break; @@ -304,10 +234,8 @@ SQInteger _stream_eos(HSQUIRRELVM v) } static SQRegFunction _stream_methods[] = { - _DECL_STREAM_FUNC(readstr,-2,_SC("xnn")), _DECL_STREAM_FUNC(readblob,2,_SC("xn")), _DECL_STREAM_FUNC(readn,2,_SC("xn")), - _DECL_STREAM_FUNC(writestr,-2,_SC("xsn")), _DECL_STREAM_FUNC(writeblob,-2,_SC("xx")), _DECL_STREAM_FUNC(writen,3,_SC("xnn")), _DECL_STREAM_FUNC(seek,-2,_SC("xnn")), @@ -336,6 +264,12 @@ void init_streamclass(HSQUIRRELVM v) i++; } sq_createslot(v,-3); + sq_pushroottable(v); + sq_pushstring(v,_SC("stream"),-1); + sq_pushstring(v,_SC("std_stream"),-1); + sq_get(v,-4); + sq_createslot(v,-3); + sq_pop(v,1); } else { sq_pop(v,1); //result diff --git a/src/squirrel/sqstdlib/sqstdstream.h b/src/squirrel/sqstdlib/sqstdstream.h index d08fc4c9e..6f562da1e 100644 --- a/src/squirrel/sqstdlib/sqstdstream.h +++ b/src/squirrel/sqstdlib/sqstdstream.h @@ -2,11 +2,9 @@ #ifndef _SQSTD_STREAM_H_ #define _SQSTD_STREAM_H_ -SQInteger _stream_readstr(HSQUIRRELVM v); SQInteger _stream_readblob(HSQUIRRELVM v); SQInteger _stream_readline(HSQUIRRELVM v); SQInteger _stream_readn(HSQUIRRELVM v); -SQInteger _stream_writestr(HSQUIRRELVM v); SQInteger _stream_writeblob(HSQUIRRELVM v); SQInteger _stream_writen(HSQUIRRELVM v); SQInteger _stream_seek(HSQUIRRELVM v); diff --git a/src/squirrel/sqstdlib/sqstdstring.cpp b/src/squirrel/sqstdlib/sqstdstring.cpp index 81fc7c207..832f3aa07 100644 --- a/src/squirrel/sqstdlib/sqstdstring.cpp +++ b/src/squirrel/sqstdlib/sqstdstring.cpp @@ -11,10 +11,12 @@ #define scstrchr wcschr #define scsnprintf wsnprintf #define scatoi _wtoi +#define scstrtok wcstok #else #define scstrchr strchr #define scsnprintf snprintf #define scatoi atoi +#define scstrtok strtok #endif #define MAX_FORMAT_LEN 20 #define MAX_WFORMAT_LEN 3 @@ -71,7 +73,7 @@ static SQInteger _string_format(HSQUIRRELVM v) sq_getstring(v,2,&format); SQInteger allocated = (sq_getsize(v,2)+1)*sizeof(SQChar); dest = sq_getscratchpad(v,allocated); - SQInteger n = 0,i = 0, nparam = 3, w; + SQInteger n = 0,i = 0, nparam = 3, w = 0; while(format[n] != '\0') { if(format[n] != '%') { assert(i < allocated); @@ -116,8 +118,7 @@ static SQInteger _string_format(HSQUIRRELVM v) return sq_throwerror(v,_SC("invalid format")); } n++; - if((allocated-i) < addlen) - allocated += addlen; + allocated += addlen; dest = sq_getscratchpad(v,allocated); switch(valtype) { case 's': i += scsprintf(&dest[i],fmt,ts); break; @@ -131,6 +132,74 @@ static SQInteger _string_format(HSQUIRRELVM v) return 1; } +static void __strip_l(const SQChar *str,const SQChar **start) +{ + const SQChar *t = str; + while(((*t) != '\0') && scisspace(*t)){ t++; } + *start = t; +} + +static void __strip_r(const SQChar *str,SQInteger len,const SQChar **end) +{ + if(len == 0) { + *end = str; + return; + } + const SQChar *t = &str[len-1]; + while(t != str && scisspace(*t)) { t--; } + *end = t+1; +} + +static SQInteger _string_strip(HSQUIRRELVM v) +{ + const SQChar *str,*start,*end; + sq_getstring(v,2,&str); + SQInteger len = sq_getsize(v,2); + __strip_l(str,&start); + __strip_r(str,len,&end); + sq_pushstring(v,start,end - start); + return 1; +} + +static SQInteger _string_lstrip(HSQUIRRELVM v) +{ + const SQChar *str,*start; + sq_getstring(v,2,&str); + __strip_l(str,&start); + sq_pushstring(v,start,-1); + return 1; +} + +static SQInteger _string_rstrip(HSQUIRRELVM v) +{ + const SQChar *str,*end; + sq_getstring(v,2,&str); + SQInteger len = sq_getsize(v,2); + __strip_r(str,len,&end); + sq_pushstring(v,str,end - str); + return 1; +} + +static SQInteger _string_split(HSQUIRRELVM v) +{ + const SQChar *str,*seps; + SQChar *stemp,*tok; + sq_getstring(v,2,&str); + sq_getstring(v,3,&seps); + if(sq_getsize(v,3) == 0) return sq_throwerror(v,_SC("empty separators string")); + SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar); + stemp = sq_getscratchpad(v,memsize); + memcpy(stemp,str,memsize); + tok = scstrtok(stemp,seps); + sq_newarray(v,0); + while( tok != NULL ) { + sq_pushstring(v,tok,-1); + sq_arrayappend(v,-2); + tok = scstrtok( NULL, seps ); + } + return 1; +} + #define SETUP_REX(v) \ SQRex *self = NULL; \ sq_getinstanceup(v,1,(SQUserPointer *)&self,0); @@ -149,10 +218,11 @@ static SQInteger _regexp_match(HSQUIRRELVM v) sq_getstring(v,2,&str); if(sqstd_rex_match(self,str) == SQTrue) { - sq_pushinteger(v,1); + sq_pushbool(v,SQTrue); return 1; } - return 0; + sq_pushbool(v,SQFalse); + return 1; } static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end) @@ -242,6 +312,10 @@ static SQRegFunction rexobj_funcs[]={ #define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask} static SQRegFunction stringlib_funcs[]={ _DECL_FUNC(format,-2,_SC(".s")), + _DECL_FUNC(strip,2,_SC(".s")), + _DECL_FUNC(lstrip,2,_SC(".s")), + _DECL_FUNC(rstrip,2,_SC(".s")), + _DECL_FUNC(split,3,_SC(".ss")), {0,0} }; diff --git a/src/squirrel/sqstdlib/sqstdsystem.cpp b/src/squirrel/sqstdlib/sqstdsystem.cpp index b52f057d2..c7153a67c 100644 --- a/src/squirrel/sqstdlib/sqstdsystem.cpp +++ b/src/squirrel/sqstdlib/sqstdsystem.cpp @@ -85,9 +85,11 @@ static void _set_integer_slot(HSQUIRRELVM v,const SQChar *name,SQInteger val) static SQInteger _system_date(HSQUIRRELVM v) { time_t t; + SQInteger it; SQInteger format = 'l'; if(sq_gettop(v) > 1) { - sq_getinteger(v,2,(SQInteger*)&t); + sq_getinteger(v,2,&it); + t = it; if(sq_gettop(v) > 2) { sq_getinteger(v,3,(SQInteger*)&format); } diff --git a/src/squirrel/squirrel/sqapi.cpp b/src/squirrel/squirrel/sqapi.cpp index 638280f01..b17bab90a 100644 --- a/src/squirrel/squirrel/sqapi.cpp +++ b/src/squirrel/squirrel/sqapi.cpp @@ -124,40 +124,26 @@ SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQCha return SQ_ERROR; } -void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo) +void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable) { - _ss(v)->_debuginfo = debuginfo?true:false; + _ss(v)->_debuginfo = enable?true:false; +} + +void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable) +{ + _ss(v)->_notifyallexceptions = enable?true:false; } void sq_addref(HSQUIRRELVM v,HSQOBJECT *po) { - SQObjectPtr refs; if(!ISREFCOUNTED(type(*po))) return; - if(_table(_ss(v)->_refs_table)->Get(*po, refs)) { - refs = _integer(refs) + 1; - } - else{ - refs = 1; - } - _table(_ss(v)->_refs_table)->NewSlot(*po, refs); + _ss(v)->_refs_table.AddRef(*po); } SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po) { - SQObjectPtr refs; if(!ISREFCOUNTED(type(*po))) return SQTrue; - if(_table(_ss(v)->_refs_table)->Get(*po, refs)) { - SQInteger n = _integer(refs) - 1; - if(n <= 0) { - _table(_ss(v)->_refs_table)->Remove(*po); - sq_resetobject(po); - } - else { - refs = n;_table(_ss(v)->_refs_table)->Set(*po, refs); - return SQFalse; - } - } - return SQTrue; + return _ss(v)->_refs_table.Release(*po); } const SQChar *sq_objtostring(HSQOBJECT *o) @@ -256,13 +242,13 @@ SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase) return SQ_OK; } -SQInteger sq_instanceof(HSQUIRRELVM v) +SQBool sq_instanceof(HSQUIRRELVM v) { SQObjectPtr &inst = stack_get(v,-1); SQObjectPtr &cl = stack_get(v,-2); if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS) return sq_throwerror(v,_SC("invalid param type")); - return _instance(inst)->InstanceOf(_class(cl))?1:0; + return _instance(inst)->InstanceOf(_class(cl))?SQTrue:SQFalse; } SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx) @@ -377,6 +363,34 @@ SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *ty return SQ_OK; } +SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v,idx); + if(!sq_isnativeclosure(o) && + !sq_isclosure(o)) + return sq_throwerror(v,_SC("the target is not a closure")); + SQObjectPtr &env = stack_get(v,-1); + if(!sq_istable(env) && + !sq_isclass(env) && + !sq_isinstance(env)) + return sq_throwerror(v,_SC("invalid environment")); + SQObjectPtr w = _refcounted(env)->GetWeakRef(type(env)); + SQObjectPtr ret; + if(sq_isclosure(o)) { + SQClosure *c = _closure(o)->Clone(); + c->_env = w; + ret = c; + } + else { //then must be a native closure + SQNativeClosure *c = _nativeclosure(o)->Clone(); + c->_env = w; + ret = c; + } + v->Pop(); + v->Push(ret); + return SQ_OK; +} + void sq_pushroottable(HSQUIRRELVM v) { v->Push(v->_roottable); @@ -426,6 +440,12 @@ void sq_tostring(HSQUIRRELVM v,SQInteger idx) v->Push(res); } +void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b) +{ + SQObjectPtr &o = stack_get(v, idx); + *b = v->IsFalse(o)?SQFalse:SQTrue; +} + SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i) { SQObjectPtr &o = stack_get(v, idx); @@ -608,19 +628,32 @@ SQInteger sq_cmp(HSQUIRRELVM v) return res; } -SQRESULT sq_createslot(HSQUIRRELVM v, SQInteger idx) +SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic) { sq_aux_paramscheck(v, 3); SQObjectPtr &self = stack_get(v, idx); if(type(self) == OT_TABLE || type(self) == OT_CLASS) { SQObjectPtr &key = v->GetUp(-2); if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); - v->NewSlot(self, key, v->GetUp(-1)); + v->NewSlot(self, key, v->GetUp(-1),bstatic?true:false); v->Pop(2); } return SQ_OK; } +/*SQRESULT sq_createslot(HSQUIRRELVM v, SQInteger idx) +{ + sq_aux_paramscheck(v, 3); + SQObjectPtr &self = stack_get(v, idx); + if(type(self) == OT_TABLE || type(self) == OT_CLASS) { + SQObjectPtr &key = v->GetUp(-2); + if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); + v->NewSlot(self, key, v->GetUp(-1)); + v->Pop(2); + } + return SQ_OK; +}*/ + SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval) { sq_aux_paramscheck(v, 2); @@ -658,7 +691,7 @@ SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx) return SQ_OK; break; case OT_CLASS: - _class(self)->NewSlot(v->GetUp(-2), v->GetUp(-1)); + _class(self)->NewSlot(_ss(v), v->GetUp(-2), v->GetUp(-1),false); v->Pop(2); return SQ_OK; break; @@ -732,15 +765,15 @@ SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx) case OT_TABLE: if(!_table(self)->_delegate)break; v->Push(SQObjectPtr(_table(self)->_delegate)); - return SQ_OK; break; case OT_USERDATA: if(!_userdata(self)->_delegate)break; v->Push(SQObjectPtr(_userdata(self)->_delegate)); - return SQ_OK; break; + default: return sq_throwerror(v,_SC("wrong type")); break; } - return sq_throwerror(v,_SC("wrong type")); + return SQ_OK; + } SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx) @@ -801,7 +834,7 @@ const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedIntege return NULL; SQClosure *c=_closure(ci._closure); SQFunctionProto *func=_funcproto(c->_function); - return func->GetLocal(v,stackbase,idx,(ci._ip-func->_instructions._vals)-1); + return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions._vals)-1); } return NULL; } @@ -839,11 +872,11 @@ void sq_reservestack(HSQUIRRELVM v,SQInteger nsize) } } -SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval) +SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror) { if(type(v->GetUp(-1))==OT_GENERATOR){ v->Push(_null_); //retval - if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),SQVM::ET_RESUME_GENERATOR)) + if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),raiseerror,SQVM::ET_RESUME_GENERATOR)) {v->Raise_Error(v->_lasterror); return SQ_ERROR;} if(!retval) v->Pop(); @@ -852,10 +885,10 @@ SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval) return sq_throwerror(v,_SC("only generators can be resumed")); } -SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval) +SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror) { SQObjectPtr res; - if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res)){ + if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false)){ v->Pop(params);//pop closure and args if(retval){ v->Push(res); return SQ_OK; @@ -876,7 +909,7 @@ SQRESULT sq_suspendvm(HSQUIRRELVM v) return v->Suspend(); } -SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval) +SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval,SQBool raiseerror) { SQObjectPtr ret; if(!v->_suspended) @@ -885,7 +918,7 @@ SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval) v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval v->Pop(); } else v->GetAt(v->_stackbase+v->_suspended_target)=_null_; - if(!v->Execute(_null_,v->_top,-1,-1,ret,SQVM::ET_RESUME_VM)) + if(!v->Execute(_null_,v->_top,-1,-1,ret,raiseerror,SQVM::ET_RESUME_VM)) return SQ_ERROR; if(sq_getvmstate(v) == SQ_VMSTATE_IDLE) { while (v->_top > 1) v->_stack[--v->_top] = _null_; @@ -900,12 +933,10 @@ void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook) if(sq_gettop(v) >= 1){ SQObjectPtr &ud=stack_get(v,idx); switch( type(ud) ) { - case OT_USERDATA: - _userdata(ud)->_hook = hook; - break; - case OT_INSTANCE: - _instance(ud)->_hook = hook; - break; + case OT_USERDATA: _userdata(ud)->_hook = hook; break; + case OT_INSTANCE: _instance(ud)->_hook = hook; break; + case OT_CLASS: _class(ud)->_hook = hook; break; + default: break; //shutup compiler } } } @@ -919,7 +950,6 @@ SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, -1, OT_CLOSURE,o); - SQClosure *c=_closure(*o); unsigned short tag = SQ_BYTECODE_STREAM_TAG; if(w(up,&tag,2) != 2) return sq_throwerror(v,_SC("io error")); @@ -1027,7 +1057,7 @@ SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx) if(type(key) == OT_NULL) { attrs = _class(*o)->_attributes; v->Pop(); - v->Push(attrs); + v->Push(attrs); return SQ_OK; } else if(_class(*o)->GetAttributes(key,attrs)) { @@ -1038,6 +1068,17 @@ SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx) return sq_throwerror(v,_SC("wrong index")); } +SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + if(_class(*o)->_base) + v->Push(SQObjectPtr(_class(*o)->_base)); + else + v->Push(_null_); + return SQ_OK; +} + SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr *o = NULL; @@ -1074,6 +1115,25 @@ SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx) return SQ_OK; } +SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t) +{ + SQSharedState *ss = _ss(v); + switch(t) { + case OT_TABLE: v->Push(ss->_table_default_delegate); break; + case OT_ARRAY: v->Push(ss->_array_default_delegate); break; + case OT_STRING: v->Push(ss->_string_default_delegate); break; + case OT_INTEGER: case OT_FLOAT: v->Push(ss->_number_default_delegate); break; + case OT_GENERATOR: v->Push(ss->_generator_default_delegate); break; + case OT_CLOSURE: case OT_NATIVECLOSURE: v->Push(ss->_closure_default_delegate); break; + case OT_THREAD: v->Push(ss->_thread_default_delegate); break; + case OT_CLASS: v->Push(ss->_class_default_delegate); break; + case OT_INSTANCE: v->Push(ss->_instance_default_delegate); break; + case OT_WEAKREF: v->Push(ss->_weakref_default_delegate); break; + default: return sq_throwerror(v,_SC("the type doesn't have a default delegate")); + } + return SQ_OK; +} + SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val; diff --git a/src/squirrel/squirrel/sqbaselib.cpp b/src/squirrel/squirrel/sqbaselib.cpp index 674608fcc..b8d342143 100644 --- a/src/squirrel/squirrel/sqbaselib.cpp +++ b/src/squirrel/squirrel/sqbaselib.cpp @@ -97,7 +97,7 @@ static SQInteger base_getstackinfos(HSQUIRRELVM v) sq_pushstring(v, _SC("locals"), -1); sq_newtable(v); seq=0; - while (name = sq_getlocal(v, level, seq)) { + while ((name = sq_getlocal(v, level, seq))) { sq_pushstring(v, name, -1); sq_push(v, -2); sq_createslot(v, -4); @@ -238,6 +238,9 @@ void sq_base_register(HSQUIRRELVM v) sq_pushstring(v,_SC("_charsize_"),-1); sq_pushinteger(v,sizeof(SQChar)); sq_createslot(v,-3); + sq_pushstring(v,_SC("_intsize_"),-1); + sq_pushinteger(v,sizeof(SQInteger)); + sq_createslot(v,-3); sq_pop(v,1); } @@ -288,7 +291,7 @@ static SQInteger default_delegate_tointeger(HSQUIRRELVM v) v->Push(SQObjectPtr(tointeger(o))); break; case OT_BOOL: - v->Push(SQObjectPtr(_integer(o)?1:0)); + v->Push(SQObjectPtr(_integer(o)?(SQInteger)1:(SQInteger)0)); break; default: v->Push(_null_); @@ -312,7 +315,7 @@ static SQInteger obj_delegate_weakref(HSQUIRRELVM v) static SQInteger number_delegate_tochar(HSQUIRRELVM v) { SQObject &o=stack_get(v,1); - SQChar c=tointeger(o); + SQChar c = (SQChar)tointeger(o); v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1)); return 1; } @@ -357,6 +360,7 @@ SQRegFunction SQSharedState::_table_default_delegate_funcz[]={ {_SC("rawdelete"),table_rawdelete,2, _SC("t")}, {_SC("rawin"),container_rawexists,2, _SC("t")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {0,0} }; @@ -443,7 +447,7 @@ bool _qsort_compare(HSQUIRRELVM v,SQObjectPtr &arr,SQObjectPtr &a,SQObjectPtr &b sq_pushroottable(v); v->Push(a); v->Push(b); - if(SQ_FAILED(sq_call(v, 3, SQTrue))) { + if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) { v->Raise_Error(_SC("compare func failed")); return false; } @@ -488,7 +492,6 @@ bool _qsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger f static SQInteger array_sort(HSQUIRRELVM v) { - //SQ_TRY { SQInteger func = -1; SQObjectPtr &o = stack_get(v,1); SQObject &funcobj = stack_get(v,2); @@ -534,6 +537,7 @@ SQRegFunction SQSharedState::_array_default_delegate_funcz[]={ {_SC("sort"),array_sort,-1, _SC("ac")}, {_SC("slice"),array_slice,-1, _SC("ann")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {0,0} }; @@ -588,7 +592,7 @@ SQRegFunction SQSharedState::_string_default_delegate_funcz[]={ {_SC("len"),default_delegate_len,1, _SC("s")}, {_SC("tointeger"),default_delegate_tointeger,1, _SC("s")}, {_SC("tofloat"),default_delegate_tofloat,1, _SC("s")}, - {_SC("tostring"),default_delegate_tostring,1, _SC("s")}, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {_SC("slice"),string_slice,-1, _SC(" s n n")}, {_SC("find"),string_find,-2, _SC("s s n ")}, {_SC("tolower"),string_tolower,1, _SC("s")}, @@ -601,31 +605,97 @@ SQRegFunction SQSharedState::_string_default_delegate_funcz[]={ SQRegFunction SQSharedState::_number_default_delegate_funcz[]={ {_SC("tointeger"),default_delegate_tointeger,1, _SC("n|b")}, {_SC("tofloat"),default_delegate_tofloat,1, _SC("n|b")}, - {_SC("tostring"),default_delegate_tostring,1, _SC("n|b")}, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {_SC("tochar"),number_delegate_tochar,1, _SC("n|b")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {0,0} }; //CLOSURE DEFAULT DELEGATE////////////////////////// +static SQInteger closure_pcall(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR; +} + static SQInteger closure_call(HSQUIRRELVM v) { - return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue))?1:SQ_ERROR; + return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQTrue))?1:SQ_ERROR; } -static SQInteger closure_acall(HSQUIRRELVM v) +static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror) { SQArray *aparams=_array(stack_get(v,2)); SQInteger nparams=aparams->Size(); v->Push(stack_get(v,1)); for(SQInteger i=0;iPush(aparams->_values[i]); - return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue))?1:SQ_ERROR; + return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue,raiseerror))?1:SQ_ERROR; +} + +static SQInteger closure_acall(HSQUIRRELVM v) +{ + return _closure_acall(v,SQTrue); +} + +static SQInteger closure_pacall(HSQUIRRELVM v) +{ + return _closure_acall(v,SQFalse); +} + +static SQInteger closure_bindenv(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_bindenv(v,1))) + return SQ_ERROR; + return 1; +} + +static SQInteger closure_getinfos(HSQUIRRELVM v) { + SQObject o = stack_get(v,1); + SQTable *res = SQTable::Create(_ss(v),4); + if(type(o) == OT_CLOSURE) { + SQFunctionProto *f = _funcproto(_closure(o)->_function); + SQInteger nparams = f->_parameters.size() + (f->_varparams?1:0); + SQObjectPtr params = SQArray::Create(_ss(v),nparams); + for(SQUnsignedInteger n = 0; n_parameters.size(); n++) { + _array(params)->Set((SQInteger)n,f->_parameters[n]); + } + if(f->_varparams) { + _array(params)->Set(nparams-1,SQString::Create(_ss(v),_SC("..."),-1)); + } + res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),false); + res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),f->_name); + res->NewSlot(SQString::Create(_ss(v),_SC("src"),-1),f->_sourcename); + res->NewSlot(SQString::Create(_ss(v),_SC("parameters"),-1),params); + res->NewSlot(SQString::Create(_ss(v),_SC("varargs"),-1),f->_varparams); + } + else { //OT_NATIVECLOSURE + SQNativeClosure *nc = _nativeclosure(o); + res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),true); + res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),nc->_name); + res->NewSlot(SQString::Create(_ss(v),_SC("paramscheck"),-1),nc->_nparamscheck); + SQObjectPtr typecheck; + if(nc->_typecheck.size() > 0) { + typecheck = + SQArray::Create(_ss(v), nc->_typecheck.size()); + for(SQUnsignedInteger n = 0; n_typecheck.size(); n++) { + _array(typecheck)->Set((SQInteger)n,nc->_typecheck[n]); + } + } + res->NewSlot(SQString::Create(_ss(v),_SC("typecheck"),-1),typecheck); + } + v->Push(res); + return 1; } + SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={ {_SC("call"),closure_call,-1, _SC("c")}, + {_SC("pcall"),closure_pcall,-1, _SC("c")}, {_SC("acall"),closure_acall,2, _SC("ca")}, + {_SC("pacall"),closure_pacall,2, _SC("ca")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("bindenv"),closure_bindenv,2, _SC("c x|y|t")}, + {_SC("getinfos"),closure_getinfos,1, _SC("c")}, {0,0} }; @@ -644,6 +714,7 @@ static SQInteger generator_getstatus(HSQUIRRELVM v) SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={ {_SC("getstatus"),generator_getstatus,1, _SC("g")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {0,0} }; @@ -657,7 +728,7 @@ static SQInteger thread_call(HSQUIRRELVM v) _thread(o)->Push(_thread(o)->_roottable); for(SQInteger i = 2; i<(nparams+1); i++) sq_move(_thread(o),v,i); - if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue))) { + if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue,SQFalse))) { sq_move(v,_thread(o),-1); return 1; } @@ -687,7 +758,7 @@ static SQInteger thread_wakeup(HSQUIRRELVM v) if(wakeupret) { sq_move(thread,v,2); } - if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,1))) { + if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,1,SQFalse))) { sq_move(v,thread,-1); sq_pop(thread,1); if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) { @@ -724,6 +795,7 @@ SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = { {_SC("wakeup"), thread_wakeup, -1, _SC("v")}, {_SC("getstatus"), thread_getstatus, 1, _SC("v")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {0,0}, }; @@ -741,11 +813,20 @@ static SQInteger class_setattributes(HSQUIRRELVM v) return SQ_ERROR; } +static SQInteger class_instance(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_createinstance(v,-1))) + return 1; + return SQ_ERROR; +} + SQRegFunction SQSharedState::_class_default_delegate_funcz[] = { {_SC("getattributes"), class_getattributes, 2, _SC("y.")}, {_SC("setattributes"), class_setattributes, 3, _SC("y..")}, {_SC("rawin"),container_rawexists,2, _SC("y")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("instance"),class_instance,1, _SC("y")}, {0,0} }; @@ -760,6 +841,7 @@ SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = { {_SC("getclass"), instance_getclass, 1, _SC("x")}, {_SC("rawin"),container_rawexists,2, _SC("x")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {0,0} }; @@ -773,6 +855,7 @@ static SQInteger weakref_ref(HSQUIRRELVM v) SQRegFunction SQSharedState::_weakref_default_delegate_funcz[] = { {_SC("ref"),weakref_ref,1, _SC("r")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {0,0} }; diff --git a/src/squirrel/squirrel/sqclass.cpp b/src/squirrel/squirrel/sqclass.cpp index 21d600695..1672f7cca 100644 --- a/src/squirrel/squirrel/sqclass.cpp +++ b/src/squirrel/squirrel/sqclass.cpp @@ -11,6 +11,7 @@ SQClass::SQClass(SQSharedState *ss,SQClass *base) { _base = base; _typetag = 0; + _hook = NULL; _metamethods.resize(MT_LAST); //size it to max size if(_base) { _defaultvalues.copy(base->_defaultvalues); @@ -42,7 +43,7 @@ SQClass::~SQClass() Finalize(); } -bool SQClass::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) +bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) { SQObjectPtr temp; if(_locked) @@ -52,9 +53,10 @@ bool SQClass::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) _defaultvalues[_member_idx(temp)].val = val; return true; } - if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) { + if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE || bstatic) { SQInteger mmidx; - if((mmidx = _sharedstate->GetMetaMethodIdxByName(key)) != -1) { + if((type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) && + (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) { _metamethods[mmidx] = val; } else { @@ -169,7 +171,7 @@ SQInstance::~SQInstance() Finalize(); } -bool SQInstance::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res) +bool SQInstance::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) { if(type(_class->_metamethods[mm]) != OT_NULL) { res = _class->_metamethods[mm]; diff --git a/src/squirrel/squirrel/sqclass.h b/src/squirrel/squirrel/sqclass.h index 3ef4f1940..460e591a0 100644 --- a/src/squirrel/squirrel/sqclass.h +++ b/src/squirrel/squirrel/sqclass.h @@ -36,7 +36,7 @@ public: return newclass; } ~SQClass(); - bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val); + bool NewSlot(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic); bool Get(const SQObjectPtr &key,SQObjectPtr &val) { if(_members->Get(key,val)) { if(_isfield(val)) { @@ -53,19 +53,24 @@ public: bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val); bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval); void Lock() { _locked = true; if(_base) _base->Lock(); } - void Release() { sq_delete(this, SQClass); } + void Release() { + if (_hook) { _hook(_typetag,0);} + sq_delete(this, SQClass); + } void Finalize(); +#ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable ** ); +#endif SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); SQInstance *CreateInstance(); SQTable *_members; - //SQTable *_properties; SQClass *_base; SQClassMemeberVec _defaultvalues; SQClassMemeberVec _methods; SQObjectPtrVec _metamethods; SQObjectPtr _attributes; SQUserPointer _typetag; + SQRELEASEHOOK _hook; bool _locked; }; @@ -120,9 +125,11 @@ public: SQ_FREE(this, size); } void Finalize(); +#ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable ** ); +#endif bool InstanceOf(SQClass *trg); - bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res); + bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); SQClass *_class; SQUserPointer _userpointer; diff --git a/src/squirrel/squirrel/sqclosure.h b/src/squirrel/squirrel/sqclosure.h index 8565621f5..7a5df1b3e 100644 --- a/src/squirrel/squirrel/sqclosure.h +++ b/src/squirrel/squirrel/sqclosure.h @@ -17,6 +17,13 @@ public: void Release(){ sq_delete(this,SQClosure); } + SQClosure *Clone() + { + SQClosure * ret = SQClosure::Create(_opt_ss(this),_funcproto(_function)); + ret->_env = _env; + ret->_outervalues.copy(_outervalues); + return ret; + } ~SQClosure() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); @@ -27,6 +34,7 @@ public: void Mark(SQCollectable **chain); void Finalize(){_outervalues.resize(0); } #endif + SQObjectPtr _env; SQObjectPtr _function; SQObjectPtrVec _outervalues; }; @@ -78,6 +86,16 @@ public: new (nc) SQNativeClosure(ss,func); return nc; } + SQNativeClosure *Clone() + { + SQNativeClosure * ret = SQNativeClosure::Create(_opt_ss(this),_function); + ret->_env = _env; + ret->_name = _name; + ret->_outervalues.copy(_outervalues); + ret->_typecheck = _typecheck; + ret->_nparamscheck = _nparamscheck; + return ret; + } ~SQNativeClosure() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); @@ -89,6 +107,7 @@ public: void Mark(SQCollectable **chain); void Finalize(){_outervalues.resize(0);} #endif + SQObjectPtr _env; SQFUNCTION _function; SQObjectPtr _name; SQObjectPtrVec _outervalues; diff --git a/src/squirrel/squirrel/sqcompiler.cpp b/src/squirrel/squirrel/sqcompiler.cpp index ed99a7353..464a0c0d0 100644 --- a/src/squirrel/squirrel/sqcompiler.cpp +++ b/src/squirrel/squirrel/sqcompiler.cpp @@ -303,7 +303,8 @@ public: case TK_MULEQ: oper = '*'; break; case TK_DIVEQ: oper = '/'; break; case TK_MODEQ: oper = '%'; break; - default: assert(0); break; + default: oper = 0; //shut up compiler + assert(0); break; }; if(deref) { SQInteger val = _fs->PopTarget(); @@ -636,9 +637,15 @@ public: _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); Lex(); break; - case TK_INTEGER: - _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue)); + case TK_INTEGER: { + if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits? + _fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue); + } + else { + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue)); + } Lex(); + } break; case TK_FLOAT: _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue)); @@ -727,11 +734,18 @@ public: while(_token != terminator) { bool hasattrs = false; + bool isstatic = false; //check if is an attribute - if(separator == ';' && _token == TK_ATTR_OPEN) { - _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex(); - ParseTableOrClass(',',TK_ATTR_CLOSE); - hasattrs = true; + if(separator == ';') { + if(_token == TK_ATTR_OPEN) { + _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex(); + ParseTableOrClass(',',TK_ATTR_CLOSE); + hasattrs = true; + } + if(_token == TK_STATIC) { + isstatic = true; + Lex(); + } } switch(_token) { case TK_FUNCTION: @@ -760,9 +774,10 @@ public: SQInteger key = _fs->PopTarget(); SQInteger attrs = hasattrs ? _fs->PopTarget():-1; assert(hasattrs && attrs == key-1 || !hasattrs); + unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0); SQInteger table = _fs->TopTarget(); //<AddInstruction(hasattrs?_OP_NEWSLOTA:_OP_NEWSLOT, _fs->PushTarget(), table, key, val); - _fs->PopTarget(); + _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); + //_fs->PopTarget(); } if(separator == _SC(',')) //hack recognizes a table from the separator _fs->SetIntructionParam(tpos, 1, nkeys); @@ -943,6 +958,7 @@ public: SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size(); _fs->_breaktargets.push_back(0); while(_token == TK_CASE) { + //_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one if(!bfirst) { _fs->AddInstruction(_OP_JMP, 0, 0); skipcondjmp = _fs->GetCurrentPos(); @@ -966,6 +982,7 @@ public: if(tonextcondjmp != -1) _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); if(_token == TK_DEFAULT) { + // _fs->AddLineInfos(_lex._currentline, _lineinfo); Lex(); Expect(_SC(':')); SQInteger stacksize = _fs->GetStackSize(); Statements(); diff --git a/src/squirrel/squirrel/sqcompiler.h b/src/squirrel/squirrel/sqcompiler.h index 71dbfa2d0..ea0a831f7 100644 --- a/src/squirrel/squirrel/sqcompiler.h +++ b/src/squirrel/squirrel/sqcompiler.h @@ -67,6 +67,7 @@ struct SQVM; #define TK_MODEQ 319 #define TK_ATTR_OPEN 320 #define TK_ATTR_CLOSE 321 +#define TK_STATIC 322 typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s); diff --git a/src/squirrel/squirrel/sqdebug.cpp b/src/squirrel/squirrel/sqdebug.cpp index 9612d06a9..732bd0173 100644 --- a/src/squirrel/squirrel/sqdebug.cpp +++ b/src/squirrel/squirrel/sqdebug.cpp @@ -31,6 +31,7 @@ SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si) si->funcname = _stringval(_nativeclosure(ci._closure)->_name); si->line = -1; break; + default: break; //shutup compiler } return SQ_OK; } @@ -41,7 +42,7 @@ void SQVM::Raise_Error(const SQChar *s, ...) { va_list vl; va_start(vl, s); - scvsprintf(_sp(rsl(scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl); + scvsprintf(_sp(rsl((SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl); va_end(vl); _lasterror = SQString::Create(_ss(this),_spval,-1); } diff --git a/src/squirrel/squirrel/sqfuncstate.cpp b/src/squirrel/squirrel/sqfuncstate.cpp index 9e160267a..b98670723 100644 --- a/src/squirrel/squirrel/sqfuncstate.cpp +++ b/src/squirrel/squirrel/sqfuncstate.cpp @@ -13,6 +13,7 @@ SQInstructionDesc g_InstrDesc[]={ {_SC("_OP_LINE")}, {_SC("_OP_LOAD")}, + {_SC("_OP_LOADINT")}, {_SC("_OP_DLOAD")}, {_SC("_OP_TAILCALL")}, {_SC("_OP_CALL")}, @@ -77,6 +78,7 @@ void DumpLiteral(SQObjectPtr &o) case OT_STRING: scprintf(_SC("\"%s\""),_stringval(o));break; case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break; case OT_INTEGER: scprintf(_SC("{%d}"),_integer(o));break; + default: assert(0); break; //shut up compiler } } @@ -211,7 +213,6 @@ SQInteger SQFuncState::GetNumericConstant(const SQFloat cons) SQInteger SQFuncState::GetConstant(const SQObject &cons) { - SQInteger n=0; SQObjectPtr val; if(!_table(_literals)->Get(cons,val)) { @@ -228,20 +229,19 @@ SQInteger SQFuncState::GetConstant(const SQObject &cons) void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3) { - _instructions[pos]._arg0=*((SQUnsignedInteger *)&arg0); - _instructions[pos]._arg1=*((SQUnsignedInteger *)&arg1); - _instructions[pos]._arg2=*((SQUnsignedInteger *)&arg2); - _instructions[pos]._arg3=*((SQUnsignedInteger *)&arg3); + _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0); + _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1); + _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2); + _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3); } void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val) { switch(arg){ - case 0:_instructions[pos]._arg0=*((SQUnsignedInteger *)&val);break; - case 1:_instructions[pos]._arg1=*((SQUnsignedInteger *)&val);break; - case 2:_instructions[pos]._arg2=*((SQUnsignedInteger *)&val);break; - case 3:_instructions[pos]._arg3=*((SQUnsignedInteger *)&val);break; - case 4:_instructions[pos]._arg1=*((SQUnsignedInteger *)&val);break; + case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break; + case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break; + case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break; + case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break; }; } @@ -482,7 +482,7 @@ void SQFuncState::AddInstruction(SQInstruction &i) SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len) { SQObjectPtr ns(SQString::Create(_sharedstate,s,len)); - _table(_strings)->NewSlot(ns,1); + _table(_strings)->NewSlot(ns,(SQInteger)1); return ns; } diff --git a/src/squirrel/squirrel/sqfuncstate.h b/src/squirrel/squirrel/sqfuncstate.h index c69a2f42d..df6d2e9ea 100644 --- a/src/squirrel/squirrel/sqfuncstate.h +++ b/src/squirrel/squirrel/sqfuncstate.h @@ -23,7 +23,6 @@ struct SQFuncState void SetStackSize(SQInteger n); void SnoozeOpt(){_optimization=false;} SQInteger GetCurrentPos(){return _instructions.size()-1;} - //SQInteger GetStringConstant(const SQChar *cons); SQInteger GetNumericConstant(const SQInteger cons); SQInteger GetNumericConstant(const SQFloat cons); SQInteger PushLocalVariable(const SQObject &name); @@ -63,10 +62,10 @@ struct SQFuncState SQInteger _nliterals; SQLineInfoVec _lineinfos; SQFuncState *_parent; - SQIntVec _breaktargets; //contains number of nested exception traps + SQIntVec _breaktargets; SQIntVec _continuetargets; SQInteger _lastline; - SQInteger _traps; + SQInteger _traps; //contains number of nested exception traps bool _optimization; SQSharedState *_sharedstate; sqvector _childstates; diff --git a/src/squirrel/squirrel/sqlexer.cpp b/src/squirrel/squirrel/sqlexer.cpp index 93bd577b6..7244e73ac 100644 --- a/src/squirrel/squirrel/sqlexer.cpp +++ b/src/squirrel/squirrel/sqlexer.cpp @@ -65,6 +65,7 @@ void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,Compile ADD_KEYWORD(vargv,TK_VARGV); ADD_KEYWORD(true,TK_TRUE); ADD_KEYWORD(false,TK_FALSE); + ADD_KEYWORD(static,TK_STATIC); _readf = rg; _up = up; @@ -84,7 +85,7 @@ void SQLexer::Next() SQInteger t = _readf(_up); if(t > MAX_CHAR) Error(_SC("Invalid character")); if(t != 0) { - _currdata = t; + _currdata = (LexChar)t; return; } _currdata = SQUIRREL_EOB; @@ -249,7 +250,7 @@ SQInteger SQLexer::Lex() } else { SQInteger c = CUR_CHAR; - if (sciscntrl(c)) Error(_SC("unexpected character(control)")); + if (sciscntrl((int)c)) Error(_SC("unexpected character(control)")); NEXT(); RETURN_TOKEN(c); } @@ -351,8 +352,28 @@ SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim) return TK_STRING_LITERAL; } -SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; } +void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res) +{ + *res = 0; + while(*s != 0) + { + if(scisdigit(*s)) *res = (*res)*16+((*s++)-'0'); + else if(scisxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10); + else { assert(0); } + } +} +void LexInteger(const SQChar *s,SQUnsignedInteger *res) +{ + *res = 0; + while(*s != 0) + { + *res = (*res)*10+((*s++)-'0'); + } +} + +SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; } +#define MAX_HEX_DIGITS (sizeof(SQInteger)*2) SQInteger SQLexer::ReadNumber() { #define TINT 1 @@ -360,7 +381,6 @@ SQInteger SQLexer::ReadNumber() #define THEX 3 #define TSCIENTIFIC 4 SQInteger type = TINT, firstchar = CUR_CHAR; - bool isfloat = false; SQChar *sTemp; INIT_TEMP_STRING(); NEXT(); @@ -371,10 +391,10 @@ SQInteger SQLexer::ReadNumber() APPEND_CHAR(CUR_CHAR); NEXT(); } - if(_longstr.size() > 8) Error(_SC("Hex number over 8 digits")); + if(_longstr.size() > MAX_HEX_DIGITS) Error(_SC("too many digits for an Hex number")); } else { - APPEND_CHAR(firstchar); + APPEND_CHAR((int)firstchar); while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) { if(CUR_CHAR == _SC('.')) type = TFLOAT; if(isexponent(CUR_CHAR)) { @@ -400,10 +420,10 @@ SQInteger SQLexer::ReadNumber() _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp); return TK_FLOAT; case TINT: - _nvalue = (SQInteger)scstrtol(&_longstr[0],&sTemp,10); + LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue); return TK_INTEGER; case THEX: - *((SQUnsignedInteger *)&_nvalue) = scstrtoul(&_longstr[0],&sTemp,16); + LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue); return TK_INTEGER; } return 0; @@ -411,7 +431,7 @@ SQInteger SQLexer::ReadNumber() SQInteger SQLexer::ReadID() { - SQInteger res, size = 0; + SQInteger res; INIT_TEMP_STRING(); do { APPEND_CHAR(CUR_CHAR); @@ -419,7 +439,7 @@ SQInteger SQLexer::ReadID() } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_')); TERMINATE_BUFFER(); res = GetIDType(&_longstr[0]); - if(res == TK_IDENTIFIER) { + if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) { _svalue = &_longstr[0]; } return res; diff --git a/src/squirrel/squirrel/sqlexer.h b/src/squirrel/squirrel/sqlexer.h index 750bbd0df..be3b188b3 100644 --- a/src/squirrel/squirrel/sqlexer.h +++ b/src/squirrel/squirrel/sqlexer.h @@ -2,9 +2,11 @@ #ifndef _SQLEXER_H_ #define _SQLEXER_H_ -#define MAX_STRING 2024 - - +#ifdef _UNICODE +typedef SQChar LexChar; +#else +typedef unsigned char LexChar; +#endif struct SQLexer { @@ -33,11 +35,7 @@ public: SQFloat _fvalue; SQLEXREADFUNC _readf; SQUserPointer _up; -#ifdef _UNICODE - SQChar _currdata; -#else - unsigned char _currdata; -#endif + LexChar _currdata; SQSharedState *_sharedstate; sqvector _longstr; CompilerErrorFunc _errfunc; diff --git a/src/squirrel/squirrel/sqobject.cpp b/src/squirrel/squirrel/sqobject.cpp index 92499c23e..f01ce9302 100644 --- a/src/squirrel/squirrel/sqobject.cpp +++ b/src/squirrel/squirrel/sqobject.cpp @@ -23,6 +23,19 @@ void SQString::Release() REMOVE_STRING(_sharedstate,this); } +SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + SQInteger idx = (SQInteger)TranslateIndex(refpos); + while(idx < _len){ + outkey = (SQInteger)idx; + outval = SQInteger(_val[idx]); + //return idx for the next iteration + return ++idx; + } + //nothing to iterate anymore + return -1; +} + SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx) { switch(type(idx)){ @@ -30,8 +43,8 @@ SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx) return 0; case OT_INTEGER: return (SQUnsignedInteger)_integer(idx); + default: assert(0); break; } - assert(0); return 0; } @@ -60,9 +73,9 @@ void SQWeakRef::Release() { sq_delete(this,SQWeakRef); } -bool SQDelegable::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res) { +bool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) { if(_delegate) { - return _delegate->Get((*_ss(this)->_metamethods)[mm],res); + return _delegate->Get((*_ss(v)->_metamethods)[mm],res); } return false; } @@ -167,7 +180,7 @@ const SQChar* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQU SQInteger SQFunctionProto::GetLine(SQInstruction *curr) { - SQInteger op=(curr-_instructions._vals); + SQInteger op = (SQInteger)(curr-_instructions._vals); SQInteger line=_lineinfos[0]._line; for(SQUnsignedInteger i=1;i<_lineinfos.size();i++){ if(_lineinfos[i]._op>=op) diff --git a/src/squirrel/squirrel/sqobject.h b/src/squirrel/squirrel/sqobject.h index 230ed4c21..c4489131b 100644 --- a/src/squirrel/squirrel/sqobject.h +++ b/src/squirrel/squirrel/sqobject.h @@ -27,7 +27,9 @@ enum SQMetaMethod{ MT_NEWSLOT=13, MT_DELSLOT=14, MT_TOSTRING=15, - MT_LAST = 16, + MT_NEWMEMBER=16, + MT_INHERITED=17, + MT_LAST = 18 }; #define MM_ADD _SC("_add") @@ -46,13 +48,15 @@ enum SQMetaMethod{ #define MM_NEWSLOT _SC("_newslot") #define MM_DELSLOT _SC("_delslot") #define MM_TOSTRING _SC("_tostring") +#define MM_NEWMEMBER _SC("_newmember") +#define MM_INHERITED _SC("_inherited") #define MINPOWER2 4 struct SQRefCounted { SQRefCounted() { _uiRef = 0; _weakref = NULL; } - ~SQRefCounted(); + virtual ~SQRefCounted(); SQWeakRef *GetWeakRef(SQObjectType type); SQUnsignedInteger _uiRef; struct SQWeakRef *_weakref; @@ -315,7 +319,7 @@ struct SQCollectable : public SQRefCounted { struct SQDelegable : public CHAINABLE_OBJ { bool SetDelegate(SQTable *m); - virtual bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res); + virtual bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); SQTable *_delegate; }; @@ -323,4 +327,5 @@ SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx); typedef sqvector SQObjectPtrVec; typedef sqvector SQIntVec; + #endif //_SQOBJECT_H_ diff --git a/src/squirrel/squirrel/sqopcodes.h b/src/squirrel/squirrel/sqopcodes.h index f34ca3786..2d0ffa6fa 100644 --- a/src/squirrel/squirrel/sqopcodes.h +++ b/src/squirrel/squirrel/sqopcodes.h @@ -3,7 +3,7 @@ #define _SQOPCODES_H_ #define MAX_FUNC_STACKSIZE 0xFF -#define MAX_LITERALS 0xFFFFFFFF +#define MAX_LITERALS ((SQInteger)0x7FFFFFFF) enum BitWiseOP { BW_AND = 0, @@ -24,65 +24,65 @@ enum SQOpcode { _OP_LINE= 0x00, _OP_LOAD= 0x01, - _OP_DLOAD= 0x02, - _OP_TAILCALL= 0x03, - _OP_CALL= 0x04, - _OP_PREPCALL= 0x05, - _OP_PREPCALLK= 0x06, - _OP_GETK= 0x07, - _OP_MOVE= 0x08, - _OP_NEWSLOT= 0x09, - _OP_DELETE= 0x0A, - _OP_SET= 0x0B, - _OP_GET= 0x0C, - _OP_EQ= 0x0D, - _OP_NE= 0x0E, - _OP_ARITH= 0x0F, - _OP_BITW= 0x10, - _OP_RETURN= 0x11, - _OP_LOADNULLS= 0x12, - _OP_LOADROOTTABLE= 0x13, - _OP_LOADBOOL= 0x14, - _OP_DMOVE= 0x15, - _OP_JMP= 0x16, - _OP_JNZ= 0x17, - _OP_JZ= 0x18, - _OP_LOADFREEVAR= 0x19, - _OP_VARGC= 0x1A, - _OP_GETVARGV= 0x1B, - _OP_NEWTABLE= 0x1C, - _OP_NEWARRAY= 0x1D, - _OP_APPENDARRAY= 0x1E, - _OP_GETPARENT= 0x1F, - _OP_COMPARITH= 0x20, - _OP_COMPARITHL= 0x21, - _OP_INC= 0x22, - _OP_INCL= 0x23, - _OP_PINC= 0x24, - _OP_PINCL= 0x25, - _OP_CMP= 0x26, - _OP_EXISTS= 0x27, - _OP_INSTANCEOF= 0x28, - _OP_AND= 0x29, - _OP_OR= 0x2A, - _OP_NEG= 0x2B, - _OP_NOT= 0x2C, - _OP_BWNOT= 0x2D, - _OP_CLOSURE= 0x2E, - _OP_YIELD= 0x2F, - _OP_RESUME= 0x30, - _OP_FOREACH= 0x31, - _OP_DELEGATE= 0x32, - _OP_CLONE= 0x33, - _OP_TYPEOF= 0x34, - _OP_PUSHTRAP= 0x35, - _OP_POPTRAP= 0x36, - _OP_THROW= 0x37, - _OP_CLASS= 0x38, - _OP_NEWSLOTA= 0x39, - - + _OP_LOADINT= 0x02, + _OP_DLOAD= 0x03, + _OP_TAILCALL= 0x04, + _OP_CALL= 0x05, + _OP_PREPCALL= 0x06, + _OP_PREPCALLK= 0x07, + _OP_GETK= 0x08, + _OP_MOVE= 0x09, + _OP_NEWSLOT= 0x0A, + _OP_DELETE= 0x0B, + _OP_SET= 0x0C, + _OP_GET= 0x0D, + _OP_EQ= 0x0E, + _OP_NE= 0x0F, + _OP_ARITH= 0x10, + _OP_BITW= 0x11, + _OP_RETURN= 0x12, + _OP_LOADNULLS= 0x13, + _OP_LOADROOTTABLE= 0x14, + _OP_LOADBOOL= 0x15, + _OP_DMOVE= 0x16, + _OP_JMP= 0x17, + _OP_JNZ= 0x18, + _OP_JZ= 0x19, + _OP_LOADFREEVAR= 0x1A, + _OP_VARGC= 0x1B, + _OP_GETVARGV= 0x1C, + _OP_NEWTABLE= 0x1D, + _OP_NEWARRAY= 0x1E, + _OP_APPENDARRAY= 0x1F, + _OP_GETPARENT= 0x20, + _OP_COMPARITH= 0x21, + _OP_COMPARITHL= 0x22, + _OP_INC= 0x23, + _OP_INCL= 0x24, + _OP_PINC= 0x25, + _OP_PINCL= 0x26, + _OP_CMP= 0x27, + _OP_EXISTS= 0x28, + _OP_INSTANCEOF= 0x29, + _OP_AND= 0x2A, + _OP_OR= 0x2B, + _OP_NEG= 0x2C, + _OP_NOT= 0x2D, + _OP_BWNOT= 0x2E, + _OP_CLOSURE= 0x2F, + _OP_YIELD= 0x30, + _OP_RESUME= 0x31, + _OP_FOREACH= 0x32, + _OP_DELEGATE= 0x33, + _OP_CLONE= 0x34, + _OP_TYPEOF= 0x35, + _OP_PUSHTRAP= 0x36, + _OP_POPTRAP= 0x37, + _OP_THROW= 0x38, + _OP_CLASS= 0x39, + _OP_NEWSLOTA= 0x3A }; + struct SQInstructionDesc { const SQChar *name; }; @@ -92,8 +92,8 @@ struct SQInstruction SQInstruction(){}; SQInstruction(SQOpcode _op,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0) { op = _op; - _arg0 = a0;_arg1 = a1; - _arg2 = a2;_arg3 = a3; + _arg0 = (unsigned char)a0;_arg1 = (SQInt32)a1; + _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3; } @@ -107,4 +107,7 @@ struct SQInstruction #include "squtils.h" typedef sqvector SQInstructionVec; +#define NEW_SLOT_ATTRIBUTES_FLAG 0x01 +#define NEW_SLOT_STATIC_FLAG 0x02 + #endif // _SQOPCODES_H_ diff --git a/src/squirrel/squirrel/sqstate.cpp b/src/squirrel/squirrel/sqstate.cpp index e2090953f..475afe96c 100644 --- a/src/squirrel/squirrel/sqstate.cpp +++ b/src/squirrel/squirrel/sqstate.cpp @@ -15,14 +15,15 @@ SQObjectPtr _null_; SQObjectPtr _true_(true); SQObjectPtr _false_(false); -SQObjectPtr _one_(1); -SQObjectPtr _minusone_(-1); +SQObjectPtr _one_((SQInteger)1); +SQObjectPtr _minusone_((SQInteger)-1); SQSharedState::SQSharedState() { _compilererrorhandler = NULL; _printfunc = NULL; _debuginfo = false; + _notifyallexceptions = false; } #define newsysstring(s) { \ @@ -139,9 +140,10 @@ void SQSharedState::Init() newmetamethod(MM_NEWSLOT); newmetamethod(MM_DELSLOT); newmetamethod(MM_TOSTRING); + newmetamethod(MM_NEWMEMBER); + newmetamethod(MM_INHERITED); _constructoridx = SQString::Create(this,_SC("constructor")); - _refs_table = SQTable::Create(this,0); _registry = SQTable::Create(this,0); _table_default_delegate=CreateDefaultDelegate(this,_table_default_delegate_funcz); _array_default_delegate=CreateDefaultDelegate(this,_array_default_delegate_funcz); @@ -159,10 +161,10 @@ void SQSharedState::Init() SQSharedState::~SQSharedState() { _constructoridx = _null_; - _table(_refs_table)->Finalize(); + _refs_table.Finalize(); _table(_registry)->Finalize(); _table(_metamethodsmap)->Finalize(); - _refs_table = _null_; +// _refs_table = _null_; _registry = _null_; _metamethodsmap = _null_; while(!_systemstrings->empty()){ @@ -234,6 +236,7 @@ void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) case OT_THREAD:_thread(o)->Mark(chain);break; case OT_CLASS:_class(o)->Mark(chain);break; case OT_INSTANCE:_instance(o)->Mark(chain);break; + default: break; //shutup compiler } } @@ -246,7 +249,7 @@ SQInteger SQSharedState::CollectGarbage(SQVM *vm) vms->Mark(&tchain); SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed(); - MarkObject(_refs_table,&tchain); + _refs_table.Mark(&tchain); MarkObject(_registry,&tchain); MarkObject(_metamethodsmap,&tchain); MarkObject(_table_default_delegate,&tchain); @@ -322,6 +325,147 @@ SQChar* SQSharedState::GetScratchPad(SQInteger size) return _scratchpad; } +RefTable::RefTable() +{ + AllocNodes(4); +} + +void RefTable::Finalize() +{ + RefNode *nodes = (RefNode *)&_buckets[_numofslots]; + for(SQUnsignedInteger n = 0; n < _numofslots; n++) { + nodes->obj = _null_; + nodes++; + } +} + +RefTable::~RefTable() +{ + SQ_FREE(_buckets,_buffersize); +} +#ifndef NO_GARBAGE_COLLECTOR +void RefTable::Mark(SQCollectable **chain) +{ + RefNode *nodes = (RefNode *)&_buckets[_numofslots]; + for(SQUnsignedInteger n = 0; n < _numofslots; n++) { + if(type(nodes->obj) != OT_NULL) { + SQSharedState::MarkObject(nodes->obj,chain); + } + nodes++; + } +} +#endif +void RefTable::AddRef(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,true); + ref->refs++; +} + +SQBool RefTable::Release(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,false); + if(ref) { + if(--ref->refs == 0) { + ref->obj = _null_; + if(prev) { + prev->next = ref->next; + } + else { + _buckets[mainpos] = ref->next; + } + ref->next = _freelist; + _freelist = ref; + _slotused--; + //<>test for shrink? + return SQTrue; + } + } + return SQFalse; +} + +void RefTable::Resize(SQUnsignedInteger size) +{ + RefNode **oldbuffer = _buckets; + RefNode *oldnodes = (RefNode *)&_buckets[_numofslots]; + SQUnsignedInteger oldnumofslots = _numofslots; + SQUnsignedInteger oldbuffersize = _buffersize; + AllocNodes(size); + //rehash + for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) { + if(type(oldnodes->obj) != OT_NULL) { + //add back; + assert(oldnodes->refs != 0); + RefNode *nn = Add(::HashObj(oldnodes->obj)&(_numofslots-1),oldnodes->obj); + nn->refs = oldnodes->refs; + oldnodes->obj = _null_; + } + oldnodes++; + } + SQ_FREE(oldbuffer,oldbuffersize); +} + +RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj) +{ + RefNode *t = _buckets[mainpos]; + RefNode *newnode = _freelist; + newnode->obj = obj; + _buckets[mainpos] = newnode; + _freelist = _freelist->next; + newnode->next = t; + assert(newnode->refs == 0); + _slotused++; + return newnode; +} + +RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add) +{ + RefNode *ref; + mainpos = ::HashObj(obj)&(_numofslots-1); + *prev = NULL; + for (ref = _buckets[mainpos]; ref; ) { + if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj)) + break; + *prev = ref; + ref = ref->next; + } + if(ref == NULL && add) { + if(_numofslots == _slotused) { + Resize(_numofslots*2); + } + ref = Add(mainpos,obj); + } + return ref; +} + +void RefTable::AllocNodes(SQUnsignedInteger size) +{ + RefNode **bucks; + RefNode *firstnode; + _buffersize = size * sizeof(RefNode *) + size * sizeof(RefNode); + bucks = (RefNode **)SQ_MALLOC(_buffersize); + firstnode = (RefNode *)&bucks[size]; + RefNode *temp = firstnode; + SQUnsignedInteger n; + for(n = 0; n < size - 1; n++) { + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) SQObjectPtr; + temp->next = temp+1; + temp++; + } + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) SQObjectPtr; + temp->next = NULL; + _freelist = firstnode; + _buckets = bucks; + _slotused = 0; + _numofslots = size; +} ////////////////////////////////////////////////////////////////////////// //StringTable /* @@ -330,19 +474,6 @@ SQChar* SQSharedState::GetScratchPad(SQInteger size) * http://www.lua.org/source/4.0.1/src_lstring.c.html */ -SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) -{ - SQInteger idx = (SQInteger)TranslateIndex(refpos); - while(idx < _len){ - outkey = (SQInteger)idx; - outval = SQInteger(_val[idx]); - //return idx for the next iteration - return ++idx; - } - //nothing to iterate anymore - return -1; -} - StringTable::StringTable() { AllocNodes(4); @@ -366,7 +497,7 @@ void StringTable::AllocNodes(SQInteger size) SQString *StringTable::Add(const SQChar *news,SQInteger len) { if(len<0) - len=scstrlen(news); + len = (SQInteger)scstrlen(news); SQHash h = ::_hashstr(news,len)&(_numofslots-1); SQString *s; for (s = _strings[h]; s; s = s->_next){ diff --git a/src/squirrel/squirrel/sqstate.h b/src/squirrel/squirrel/sqstate.h index 13aa71949..64892c4ad 100644 --- a/src/squirrel/squirrel/sqstate.h +++ b/src/squirrel/squirrel/sqstate.h @@ -13,10 +13,6 @@ struct StringTable { StringTable(); ~StringTable(); - //return a string obj if exists - //so when there is a table query, if the string doesn't exists in the global state - //it cannot be in a table so the result will be always null - //SQString *get(const SQChar *news); SQString *Add(const SQChar *,SQInteger len); void Remove(SQString *); private: @@ -27,6 +23,32 @@ private: SQUnsignedInteger _slotused; }; +struct RefTable { + struct RefNode { + SQObjectPtr obj; + SQUnsignedInteger refs; + struct RefNode *next; + }; + RefTable(); + ~RefTable(); + void AddRef(SQObject &obj); + SQBool Release(SQObject &obj); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + void Finalize(); +private: + RefNode *Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add); + RefNode *Add(SQHash mainpos,SQObject &obj); + void Resize(SQUnsignedInteger size); + void AllocNodes(SQUnsignedInteger size); + SQUnsignedInteger _numofslots; + SQUnsignedInteger _slotused; + SQUnsignedInteger _buffersize; + RefNode *_freelist; + RefNode **_buckets; +}; + #define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len) #define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr) @@ -49,7 +71,7 @@ public: SQObjectPtrVec *_systemstrings; SQObjectPtrVec *_types; StringTable *_stringtable; - SQObjectPtr _refs_table; + RefTable _refs_table; SQObjectPtr _registry; SQObjectPtr _constructoridx; #ifndef NO_GARBAGE_COLLECTOR @@ -80,6 +102,7 @@ public: SQCOMPILERERROR _compilererrorhandler; SQPRINTFUNCTION _printfunc; bool _debuginfo; + bool _notifyallexceptions; private: SQChar *_scratchpad; SQInteger _scratchpadsize; diff --git a/src/squirrel/squirrel/sqstring.h b/src/squirrel/squirrel/sqstring.h index 29ca9c284..235d19059 100644 --- a/src/squirrel/squirrel/sqstring.h +++ b/src/squirrel/squirrel/sqstring.h @@ -4,7 +4,7 @@ inline SQHash _hashstr (const SQChar *s, size_t l) { - SQHash h = l; /* seed */ + SQHash h = (SQHash)l; /* seed */ size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */ for (; l>=step; l-=step) h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++)); diff --git a/src/squirrel/squirrel/sqtable.cpp b/src/squirrel/squirrel/sqtable.cpp index 8eef4b825..4d9608070 100644 --- a/src/squirrel/squirrel/sqtable.cpp +++ b/src/squirrel/squirrel/sqtable.cpp @@ -20,7 +20,8 @@ SQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize) void SQTable::Remove(const SQObjectPtr &key) { - _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); + + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); if (n) { n->val = n->key = _null_; _usednodes--; @@ -81,7 +82,9 @@ SQTable *SQTable::Clone() bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) { - _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); + if(type(key) == OT_NULL) + return false; + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); if (n) { val = _realval(n->val); return true; @@ -90,7 +93,8 @@ bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) } bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) { - SQHash h = HashKey(key) & (_numofnodes - 1); + assert(type(key) != OT_NULL); + SQHash h = HashObj(key) & (_numofnodes - 1); _HashNode *n = _Get(key, h); if (n) { n->val = val; @@ -99,19 +103,27 @@ bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) _HashNode *mp = &_nodes[h]; n = mp; + //key not found I'll insert it //main pos is not free - if(type(mp->key)!=OT_NULL) { - - _HashNode *othern; /* main position of colliding node */ + if(type(mp->key) != OT_NULL) { n = _firstfree; /* get a free place */ - if (mp > n && (othern = &_nodes[h]) != mp){ + SQHash mph = HashObj(mp->key) & (_numofnodes - 1); + _HashNode *othern; /* main position of colliding node */ + + if (mp > n && (othern = &_nodes[mph]) != mp){ /* yes; move colliding node into free position */ - while (othern->next != mp) + while (othern->next != mp){ + assert(othern->next != NULL); othern = othern->next; /* find previous */ + } othern->next = n; /* redo the chain with `n' in place of `mp' */ - *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + n->key = mp->key; + n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */ + n->next = mp->next; + mp->key = _null_; + mp->val = _null_; mp->next = NULL; /* now `mp' is free */ } else{ @@ -124,7 +136,7 @@ bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) mp->key = key; for (;;) { /* correct `firstfree' */ - if (type(_firstfree->key) == OT_NULL) { + if (type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) { mp->val = val; _usednodes++; return true; /* OK; table still has a free place */ @@ -157,7 +169,7 @@ SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val) { - _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); if (n) { n->val = val; return true; diff --git a/src/squirrel/squirrel/sqtable.h b/src/squirrel/squirrel/sqtable.h index 8d90f7bf2..be6684348 100644 --- a/src/squirrel/squirrel/sqtable.h +++ b/src/squirrel/squirrel/sqtable.h @@ -9,13 +9,25 @@ #include "sqstring.h" -#define hashptr(p) (((SQHash)(reinterpret_cast(p))) >> 3) + +#define hashptr(p) ((SQHash)(((SQInteger)p) >> 3)) + +inline SQHash HashObj(const SQObjectPtr &key) +{ + switch(type(key)) { + case OT_STRING: return _string(key)->_hash; + case OT_FLOAT: return (SQHash)((SQInteger)_float(key)); + case OT_BOOL: case OT_INTEGER: return (SQHash)((SQInteger)_integer(key)); + default: return hashptr(key._unVal.pRefCounted); + } +} struct SQTable : public SQDelegable { private: struct _HashNode { + _HashNode() { next = NULL; } SQObjectPtr val; SQObjectPtr key; _HashNode *next; @@ -49,15 +61,6 @@ public: #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); #endif - inline SQHash HashKey(const SQObjectPtr &key) - { - switch(type(key)){ - case OT_STRING: return _string(key)->_hash; - case OT_FLOAT: return (SQHash)((SQInteger)_float(key)); - case OT_INTEGER: return (SQHash)((SQInteger)_integer(key)); - default: return hashptr(key._unVal.pRefCounted); - } - } inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash) { _HashNode *n = &_nodes[hash]; @@ -65,7 +68,7 @@ public: if(_rawval(n->key) == _rawval(key) && type(n->key) == type(key)){ return n; } - }while(n = n->next); + }while((n = n->next)); return NULL; } bool Get(const SQObjectPtr &key,SQObjectPtr &val); diff --git a/src/squirrel/squirrel/sqvm.cpp b/src/squirrel/squirrel/sqvm.cpp index 3137b0a9c..b13ae2434 100644 --- a/src/squirrel/squirrel/sqvm.cpp +++ b/src/squirrel/squirrel/sqvm.cpp @@ -82,6 +82,7 @@ SQVM::SQVM(SQSharedState *ss) _lasterror = _null_; _errorhandler = _null_; _debughook = _null_; + ci = NULL; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } @@ -112,6 +113,7 @@ bool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr case _SC('/'): mm=MT_DIV; break; case _SC('*'): mm=MT_MUL; break; case _SC('%'): mm=MT_MODULO; break; + default: mm = MT_ADD; assert(0); break; //shutup compiler } if(is_delegable(o1) && _delegable(o1)->_delegate) { Push(o1);Push(o2); @@ -140,8 +142,7 @@ bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o) return true; } } - return true; - + default:break; //shutup compiler } Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o)); return false; @@ -166,9 +167,11 @@ bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result) Push(o1);Push(o2); if(_delegable(o1)->_delegate)CallMetaMethod(_delegable(o1),MT_CMP,2,res); break; + default: break; //shutup compiler } if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; } - _RET_SUCCEED(_integer(res)); + _RET_SUCCEED(_integer(res)); + } else{ if(sq_isnumeric(o1) && sq_isnumeric(o2)){ @@ -235,49 +238,22 @@ void SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res) } } default: - scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),_rawval(o)); + scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o)); } res = SQString::Create(_ss(this),_spval); - return; } bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest) { - switch(type(obj)) - { - case OT_STRING: - switch(type(str)){ - case OT_STRING: { - SQInteger l=_string(str)->_len,ol=_string(obj)->_len; - SQChar *s=_sp(rsl(l+ol+1)); - memcpy(s,_stringval(str),rsl(l));memcpy(s+l,_stringval(obj),rsl(ol));s[l+ol]=_SC('\0'); - break; - } - case OT_FLOAT: - scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%g%s"),_float(str),_stringval(obj)); - break; - case OT_INTEGER: - scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%d%s"),_integer(str),_stringval(obj)); - break; - default: - Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj)); - return false; - } - dest=SQString::Create(_ss(this),_spval); - break; - case OT_FLOAT: - scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%g"),_stringval(str),_float(obj)); - dest=SQString::Create(_ss(this),_spval); - break; - case OT_INTEGER: - scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%d"),_stringval(str),_integer(obj)); - dest=SQString::Create(_ss(this),_spval); - break; - default: - Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj)); - return false; - } + SQObjectPtr a, b; + ToString(str, a); + ToString(obj, b); + SQInteger l = _string(a)->_len , ol = _string(b)->_len; + SQChar *s = _sp(rsl(l + ol + 1)); + memcpy(s, _stringval(a), rsl(l)); + memcpy(s + l, _stringval(b), rsl(ol)); + dest = SQString::Create(_ss(this), _spval, l + ol); return true; } @@ -347,10 +323,8 @@ extern SQInstructionDesc g_InstrDesc[]; bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger nargs,SQInteger stackbase,bool tailcall) { SQFunctionProto *func = _funcproto(closure->_function); - //const SQInteger outerssize = func->_outervalues.size(); - + const SQInteger paramssize = func->_parameters.size(); - const SQInteger oldtop = _top; const SQInteger newtop = stackbase + func->_stacksize; @@ -371,21 +345,27 @@ bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger nargs,SQInteg return false; } } - + + if(type(closure->_env) == OT_WEAKREF) { + _stack[stackbase] = _weakref(closure->_env)->_obj; + } + if (!tailcall) { - PUSH_CALLINFO(this, CallInfo()); - ci->_etraps = 0; - ci->_prevstkbase = stackbase - _stackbase; - ci->_target = target; - ci->_prevtop = _top - _stackbase; - ci->_ncalls = 1; - ci->_root = SQFalse; + CallInfo lc; + lc._etraps = 0; + lc._prevstkbase = stackbase - _stackbase; + lc._target = target; + lc._prevtop = _top - _stackbase; + lc._ncalls = 1; + lc._root = SQFalse; + PUSH_CALLINFO(this, lc); } else { ci->_ncalls++; + if(ci->_vargs.size) PopVarArgs(ci->_vargs); } ci->_vargs.size = (nargs - paramssize); - ci->_vargs.base = _vargsstack.size()-(nargs - paramssize); + ci->_vargs.base = _vargsstack.size()-(ci->_vargs.size); ci->_closure._unVal.pClosure = closure; ci->_closure._type = OT_CLOSURE; ci->_iv = &func->_instructions; @@ -406,7 +386,7 @@ bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval) if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) for(SQInteger i=0;i_ncalls;i++) CallDebugHook(_SC('r')); - + SQBool broot = ci->_root; SQInteger last_top = _top; SQInteger target = ci->_target; @@ -420,10 +400,12 @@ bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval) else retval = _null_; } else { - if (_arg0 != MAX_FUNC_STACKSIZE) - STK(target) = _stack[oldstackbase+_arg1]; - else - STK(target) = _null_; + if(target != -1) { //-1 is when a class contructor ret value has to be ignored + if (_arg0 != MAX_FUNC_STACKSIZE) + STK(target) = _stack[oldstackbase+_arg1]; + else + STK(target) = _null_; + } } while (last_top >= _top) _stack[last_top--].Null(); @@ -461,10 +443,10 @@ bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjec #define arg0 (_i_._arg0) #define arg1 (_i_._arg1) -#define sarg1 (*((SQInteger *)&_i_._arg1)) +#define sarg1 (*((SQInt32 *)&_i_._arg1)) #define arg2 (_i_._arg2) #define arg3 (_i_._arg3) -#define sarg3 (*((char *)&_i_._arg3)) +#define sarg3 ((SQInteger)*((signed char *)&_i_._arg3)) SQRESULT SQVM::Suspend() { @@ -530,8 +512,9 @@ bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr _generator(o1)->Resume(this, arg_2+1); _FINISH(false); } + default: + Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1)); } - Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1)); return false; //cannot be hit(just to avoid warnings) } @@ -566,7 +549,7 @@ bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func) { SQInteger nouters; SQClosure *closure = SQClosure::Create(_ss(this), func); - if(nouters = func->_outervalues.size()) { + if((nouters = func->_outervalues.size())) { closure->_outervalues.reserve(nouters); for(SQInteger i = 0; i_outervalues[i]; @@ -610,7 +593,7 @@ bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes { SQClass *base = NULL; SQObjectPtr attrs; - if(baseclass != MAX_LITERALS) { + if(baseclass != -1) { if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; } base = _class(_stack._vals[_stackbase + baseclass]); } @@ -618,6 +601,13 @@ bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes attrs = _stack._vals[_stackbase+attributes]; } target = SQClass::Create(_ss(this),base); + if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) { + int nparams = 2; + SQObjectPtr ret; + Push(target); Push(attrs); + Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false); + Pop(nparams); + } _class(target)->_attributes = attrs; return true; } @@ -642,7 +632,30 @@ bool SQVM::IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res) return true; } -bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, ExecutionType et) +bool SQVM::IsFalse(SQObjectPtr &o) +{ + if((type(o) & SQOBJECT_CANBEFALSE) && ( (type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0)) ) + || (_integer(o) == 0) ) { //OT_NULL|OT_INTEGER|OT_BOOL + return true; + } + return false; +} + +bool SQVM::GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target) +{ + switch(type(o)) { + case OT_TABLE: target = _table(o)->_delegate?SQObjectPtr(_table(o)->_delegate):_null_; + break; + case OT_CLASS: target = _class(o)->_base?_class(o)->_base:_null_; + break; + default: + Raise_Error(_SC("the %s type doesn't have a parent slot"), GetTypeName(o)); + return false; + } + return true; +} + +bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et) { if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } _nnativecalls++; @@ -684,6 +697,7 @@ exception_restore: CallDebugHook(_SC('l'),arg1); continue; case _OP_LOAD: TARGET = (*ci->_literals)[arg1]; continue; + case _OP_LOADINT: TARGET = (SQInteger)arg1; continue; case _OP_DLOAD: TARGET = (*ci->_literals)[arg1]; STK(arg2) = (*ci->_literals)[arg3];continue; case _OP_TAILCALL: temp_reg = STK(arg1); @@ -726,11 +740,20 @@ common_call: outres = temp_reg; return true; } - STK(ct_target) = temp_reg; + if(ct_target != -1) { //skip return value for contructors + STK(ct_target) = temp_reg; + } } break; case OT_CLASS:{ - _GUARD(CreateClassInstance(_class(temp_reg),arg3,_stackbase+arg2,STK(ct_target))); + SQObjectPtr inst; + _GUARD(CreateClassInstance(_class(temp_reg),inst,temp_reg)); + STK(ct_target) = inst; + ct_target = -1; //fakes return value target so that is not overwritten by the contructor + if(type(temp_reg) != OT_NULL) { + _stack[_stackbase+arg2] = inst; + goto common_call; //hard core spaghetti code(reissues the OP_CALL to invoke the contructor) + } } break; case OT_TABLE: @@ -782,7 +805,7 @@ common_prepcall: continue; case _OP_MOVE: TARGET = STK(arg1); continue; case _OP_NEWSLOT: - _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3))); + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false)); if(arg0 != arg3) TARGET = STK(arg3); continue; case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue; @@ -831,17 +854,7 @@ common_prepcall: case _OP_NEWTABLE: TARGET = SQTable::Create(_ss(this), arg1); continue; case _OP_NEWARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue; case _OP_APPENDARRAY: _array(STK(arg0))->Append(COND_LITERAL); continue; - case _OP_GETPARENT: - switch(type(STK(arg1))) { - case OT_TABLE: - TARGET = _table(STK(arg1))->_delegate?SQObjectPtr(_table(STK(arg1))->_delegate):_null_; - continue; - case OT_CLASS: TARGET = _class(STK(arg1))->_base?_class(STK(arg1))->_base:_null_; - continue; - } - Raise_Error(_SC("the %s type doesn't have a parent slot"), GetTypeName(STK(arg1))); - SQ_THROW(); - continue; + case _OP_GETPARENT: _GUARD(GETPARENT_OP(STK(arg1),TARGET)); continue; case _OP_COMPARITH: _GUARD(DerefInc(arg3, TARGET, STK((((SQUnsignedInteger)arg1&0xFFFF0000)>>16)), STK(arg2), STK(arg1&0x0000FFFF), false)); continue; case _OP_COMPARITHL: _GUARD(LOCAL_INC(arg3, TARGET, STK(arg1), STK(arg2))); continue; case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false));} continue; @@ -871,7 +884,8 @@ common_prepcall: case _OP_NOT: TARGET = (IsFalse(STK(arg1))?_true_:_false_); continue; case _OP_BWNOT: if(type(STK(arg1)) == OT_INTEGER) { - TARGET = SQInteger(~_integer(STK(arg1))); + SQInteger t = _integer(STK(arg1)); + TARGET = SQInteger(~t); continue; } Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1))); @@ -891,7 +905,7 @@ common_prepcall: } else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();} if(Return(arg0, arg1, temp_reg)){ - assert(traps==0); + assert(traps == 0); outres = temp_reg; return true; } @@ -917,18 +931,31 @@ common_prepcall: _etraps.push_back(SQExceptionTrap(_top,_stackbase, &ci->_iv->_vals[(ci->_ip-ci->_iv->_vals)+arg1], arg0)); traps++; ci->_etraps++; continue; - case _OP_POPTRAP:{ - for(SQInteger i=0; i_etraps--; - }} + } continue; case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue; case _OP_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue; case _OP_NEWSLOTA: - _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3))); - _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1)); - if(arg0 != arg3) TARGET = STK(arg3); + bool bstatic = (arg0&NEW_SLOT_STATIC_FLAG)?true:false; + if(type(STK(arg1)) == OT_CLASS) { + if(type(_class(STK(arg1))->_metamethods[MT_NEWMEMBER]) != OT_NULL ) { + Push(STK(arg1)); Push(STK(arg2)); Push(STK(arg3)); + Push((arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : _null_); + int nparams = 4; + if(Call(_class(STK(arg1))->_metamethods[MT_NEWMEMBER], nparams, _top - nparams, temp_reg,SQFalse)) { + Pop(nparams); + continue; + } + } + } + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),bstatic)); + if((arg0&NEW_SLOT_ATTRIBUTES_FLAG)) { + _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1)); + } continue; } @@ -941,6 +968,8 @@ exception_trap: SQInteger n = 0; SQInteger last_top = _top; if(ci) { + if(_ss(this)->_notifyallexceptions) CallErrorHandler(currerror); + if(traps) { do { if(ci->_etraps > 0) { @@ -960,12 +989,15 @@ exception_trap: PopVarArgs(ci->_vargs); POP_CALLINFO(this); n++; - }while(_callsstack.size()); + } while(_callsstack.size()); + } + else { + //call the hook + if(raiseerror && !_ss(this)->_notifyallexceptions) + CallErrorHandler(currerror); } - //call the hook - CallErrorHandler(currerror); //remove call stack until a C function is found or the cstack is empty - if(ci) do{ + if(ci) do { SQBool exitafterthisone = ci->_root; if(type(ci->_generator) == OT_GENERATOR) _generator(ci->_generator)->Kill(); _stackbase -= ci->_prevstkbase; @@ -973,7 +1005,7 @@ exception_trap: PopVarArgs(ci->_vargs); POP_CALLINFO(this); if( (ci && type(ci->_closure) != OT_CLOSURE) || exitafterthisone) break; - }while(_callsstack.size()); + } while(_callsstack.size()); while(last_top >= _top) _stack[last_top--].Null(); } @@ -983,16 +1015,14 @@ exception_trap: assert(0); } -bool SQVM::CreateClassInstance(SQClass *theclass, SQInteger nargs, SQInteger stackbase, SQObjectPtr &retval) +bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor) { - SQObjectPtr constr; - SQObjectPtr inst = theclass->CreateInstance(); - _stack[stackbase] = inst; - if(theclass->Get(_ss(this)->_constructoridx,constr)) { - if(!Call(constr,nargs,stackbase,constr)) - return false; + inst = theclass->CreateInstance(); + if(!theclass->Get(_ss(this)->_constructoridx,constructor)) { + //if(!Call(constr,nargs,stackbase,constr,false)) + // return false; + constructor = _null_; } - retval = inst; return true; } @@ -1001,7 +1031,7 @@ void SQVM::CallErrorHandler(SQObjectPtr &error) if(type(_errorhandler) != OT_NULL) { SQObjectPtr out; Push(_roottable); Push(error); - Call(_errorhandler, 2, _top-2, out); + Call(_errorhandler, 2, _top-2, out,SQFalse); Pop(2); } } @@ -1012,7 +1042,7 @@ void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline) SQInteger nparams=5; SQFunctionProto *func=_funcproto(_closure(ci->_closure)->_function); Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name); - Call(_debughook,nparams,_top-nparams,temp_reg); + Call(_debughook,nparams,_top-nparams,temp_reg,SQFalse); Pop(nparams); } @@ -1027,7 +1057,7 @@ bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackb } SQInteger tcs; - if(tcs = nclosure->_typecheck.size()) { + if((tcs = nclosure->_typecheck.size())) { for(SQInteger i = 0; i < nargs && i < tcs; i++) if((nclosure->_typecheck[i] != -1) && !(type(_stack[stackbase+i]) & nclosure->_typecheck[i])) { Raise_ParamTypeError(i,nclosure->_typecheck[i],type(_stack[stackbase+i])); @@ -1053,6 +1083,11 @@ bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackb for (SQInteger i = 0; i < outers; i++) { Push(nclosure->_outervalues[i]); } + + if(type(nclosure->_env) == OT_WEAKREF) { + _stack[stackbase] = _weakref(nclosure->_env)->_obj; + } + ci->_prevtop = (oldtop - oldstackbase); SQInteger ret = (nclosure->_function)(this); _nnativecalls--; @@ -1088,6 +1123,7 @@ bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest, case OT_INSTANCE: if(_instance(self)->Get(key,dest)) return true; break; + default:break; //shut up compiler } if(FallBackGet(self,key,dest,raw)) return true; @@ -1129,7 +1165,7 @@ bool SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPt case OT_STRING: if(sq_isnumeric(key)){ SQInteger n=tointeger(key); - if(abs(n)<_string(self)->_len){ + if(abs((int)n)<_string(self)->_len){ if(n<0)n=_string(self)->_len-n; dest=SQInteger(_stringval(self)[n]); return true; @@ -1214,27 +1250,29 @@ bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target) { SQObjectPtr temp_reg; + SQObjectPtr newobj; switch(type(self)){ case OT_TABLE: - target = _table(self)->Clone(); + newobj = _table(self)->Clone(); goto cloned_mt; case OT_INSTANCE: - target = _instance(self)->Clone(_ss(this)); + newobj = _instance(self)->Clone(_ss(this)); cloned_mt: - if(_delegable(target)->_delegate){ - Push(target); + if(_delegable(newobj)->_delegate){ + Push(newobj); Push(self); - CallMetaMethod(_delegable(target),MT_CLONED,2,temp_reg); + CallMetaMethod(_delegable(newobj),MT_CLONED,2,temp_reg); } + target = newobj; return true; case OT_ARRAY: - target=_array(self)->Clone(); + target = _array(self)->Clone(); return true; default: return false; } } -bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val) +bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) { if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; } switch(type(self)) { @@ -1251,7 +1289,7 @@ bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObject break;} case OT_CLASS: - if(!_class(self)->NewSlot(key,val)) { + if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) { if(_class(self)->_locked) { Raise_Error(_SC("trying to modify a class that has already been instantiated")); return false; @@ -1309,14 +1347,14 @@ bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr return true; } -bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres) +bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror) { #ifdef _DEBUG SQInteger prevstackbase = _stackbase; #endif switch(type(closure)) { case OT_CLOSURE: - return Execute(closure, _top - nparams, nparams, stackbase,outres); + return Execute(closure, _top - nparams, nparams, stackbase,outres,raiseerror); break; case OT_NATIVECLOSURE:{ bool suspend; @@ -1324,8 +1362,16 @@ SQInteger prevstackbase = _stackbase; } break; - case OT_CLASS: - return CreateClassInstance(_class(closure),nparams,stackbase,outres); + case OT_CLASS: { + SQObjectPtr constr; + SQObjectPtr temp; + CreateClassInstance(_class(closure),outres,constr); + if(type(constr) != OT_NULL) { + _stack[stackbase] = outres; + return Call(constr,nparams,stackbase,temp,raiseerror); + } + return true; + } break; default: return false; @@ -1341,8 +1387,8 @@ SQInteger prevstackbase = _stackbase; bool SQVM::CallMetaMethod(SQDelegable *del,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres) { SQObjectPtr closure; - if(del->GetMetaMethod(mm, closure)) { - if(Call(closure, nparams, _top - nparams, outres)) { + if(del->GetMetaMethod(this, mm, closure)) { + if(Call(closure, nparams, _top - nparams, outres, SQFalse)) { Pop(nparams); return true; } @@ -1360,6 +1406,21 @@ void SQVM::Remove(SQInteger n) { _top--; } +void SQVM::Pop() { + _stack[--_top] = _null_; +} + +void SQVM::Pop(SQInteger n) { + for(SQInteger i = 0; i < n; i++){ + _stack[--_top] = _null_; + } +} + +void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; } +SQObjectPtr &SQVM::Top() { return _stack[_top-1]; } +SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; } +SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; } +SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; } #ifdef _DEBUG_DUMP void SQVM::dumpstack(SQInteger stackbase,bool dumpall) @@ -1368,7 +1429,7 @@ void SQVM::dumpstack(SQInteger stackbase,bool dumpall) SQInteger n=0; scprintf(_SC("\n>>>>stack dump<<<<\n")); CallInfo &ci=_callsstack.back(); - scprintf(_SC("IP: %d\n"),ci._ip); + scprintf(_SC("IP: %p\n"),ci._ip); scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase); scprintf(_SC("prev top: %d\n"),ci._prevtop); for(SQInteger i=0;i CallInfoVec; public: enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM }; SQVM(SQSharedState *ss); ~SQVM(); bool Init(SQVM *friendvm, SQInteger stacksize); - bool Execute(SQObjectPtr &func, SQInteger target, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, ExecutionType et = ET_CALL); - //start a native call return when the NATIVE closure returns(returns true if the vm has been suspended) + bool Execute(SQObjectPtr &func, SQInteger target, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL); + //starts a native call return when the NATIVE closure returns bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger stackbase, bool tailcall, SQObjectPtr &retval,bool &suspend); - //start a SQUIRREL call in the same "Execution loop" + //starts a SQUIRREL call in the same "Execution loop" bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall); - bool CreateClassInstance(SQClass *theclass, SQInteger nargs, SQInteger stackbase, SQObjectPtr &retval); + bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor); //call a generic closure pure SQUIRREL or NATIVE - bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres); + bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror); SQRESULT Suspend(); void CallDebugHook(SQInteger type,SQInteger forcedline=0); @@ -73,7 +74,7 @@ public: bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, bool fetchroot); bool FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw); bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, bool fetchroot); - bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val); + bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val,bool bstatic); bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res); bool Clone(const SQObjectPtr &self, SQObjectPtr &target); bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res); @@ -94,19 +95,20 @@ public: bool ArithMetaMethod(SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest); bool Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval); //new stuff - inline bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); - inline bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); - inline bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1); - inline bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res); + _INLINE bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); + _INLINE bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); + _INLINE bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1); + _INLINE bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res); bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func); bool GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &idx,CallInfo *ci); bool CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs); + bool GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target); //return true if the loop is finished bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,bool &finished); bool DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2); - inline bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); - inline bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); - inline bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix); + _INLINE bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); + _INLINE bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); + _INLINE bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix); void PopVarArgs(VarArgs &vargs); #ifdef _DEBUG_DUMP void dumpstack(SQInteger stackbase=-1, bool dumpall = false); @@ -122,36 +124,21 @@ public: //stack functions for the api void Remove(SQInteger n); - inline bool IsFalse(SQObjectPtr &o) - { - if((type(o) & SQOBJECT_CANBEFALSE) && ( (type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0)) ) - || (_integer(o) == 0) ) { //OT_NULL|OT_INTEGER|OT_BOOL - return true; - } - return false; - } - inline void Pop() { - _stack[--_top] = _null_; - } - - inline void Pop(SQInteger n) { - for(SQInteger i = 0; i < n; i++){ - _stack[--_top] = _null_; - } - } - - inline void Push(const SQObjectPtr &o) { _stack[_top++] = o; } - inline SQObjectPtr &Top() { return _stack[_top-1]; } - inline SQObjectPtr &PopGet() { return _stack[--_top]; } - inline SQObjectPtr &GetUp(SQInteger n) { return _stack[_top+n]; } - inline SQObjectPtr &GetAt(SQInteger n) { return _stack[n]; } + bool IsFalse(SQObjectPtr &o); + + void Pop(); + void Pop(SQInteger n); + void Push(const SQObjectPtr &o); + SQObjectPtr &Top(); + SQObjectPtr &PopGet(); + SQObjectPtr &GetUp(SQInteger n); + SQObjectPtr &GetAt(SQInteger n); SQObjectPtrVec _stack; SQObjectPtrVec _vargsstack; SQInteger _top; SQInteger _stackbase; SQObjectPtr _roottable; - //SQObjectPtr _thrownerror; SQObjectPtr _lasterror; SQObjectPtr _errorhandler; SQObjectPtr _debughook; diff --git a/src/timer.cpp b/src/timer.cpp index 939b930e7..105ce7520 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -23,6 +23,7 @@ #include "timer.hpp" float game_time = 0; +float real_time = 0; Timer::Timer() : period(0), cycle_start(0), cyclic(false) diff --git a/src/timer.hpp b/src/timer.hpp index 340e8cebb..903ffa8e4 100644 --- a/src/timer.hpp +++ b/src/timer.hpp @@ -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 diff --git a/src/title.cpp b/src/title.cpp index edb44c6c3..fd8856b49 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -299,6 +299,7 @@ TitleScreen::leave() { Sector* sector = titlesession->get_current_sector(); sector->deactivate(); + Menu::set_current(NULL); } void diff --git a/src/video/glutil.hpp b/src/video/glutil.hpp index 54db31125..0ccb63006 100644 --- a/src/video/glutil.hpp +++ b/src/video/glutil.hpp @@ -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 #include -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 diff --git a/src/world.cpp b/src/world.cpp index 53fcdb716..8b68b0847 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -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 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; } diff --git a/src/world.hpp b/src/world.hpp index 891a43884..71095b8e3 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -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: diff --git a/src/worldmap/tux.cpp b/src/worldmap/tux.cpp index 2b070a567..40c132766 100644 --- a/src/worldmap/tux.cpp +++ b/src/worldmap/tux.cpp @@ -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; diff --git a/src/worldmap/worldmap.cpp b/src/worldmap/worldmap.cpp index d834fac1a..946b21f17 100644 --- a/src/worldmap/worldmap.cpp +++ b/src/worldmap/worldmap.cpp @@ -58,10 +58,9 @@ #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 diff --git a/src/worldmap/worldmap.hpp b/src/worldmap/worldmap.hpp index 2be401baa..1490b9ce0 100644 --- a/src/worldmap/worldmap.hpp +++ b/src/worldmap/worldmap.hpp @@ -105,6 +105,9 @@ private: Statistics total_stats; + typedef std::vector 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); diff --git a/tools/miniswig/create_docu.cpp b/tools/miniswig/create_docu.cpp index 3310e48d2..821dedb29 100644 --- a/tools/miniswig/create_docu.cpp +++ b/tools/miniswig/create_docu.cpp @@ -1,3 +1,5 @@ +#include + #include "tree.hpp" #include #include diff --git a/tools/miniswig/create_wrapper.cpp b/tools/miniswig/create_wrapper.cpp index e072b6fe3..62bfccc4d 100644 --- a/tools/miniswig/create_wrapper.cpp +++ b/tools/miniswig/create_wrapper.cpp @@ -1,3 +1,5 @@ +#include + #include "tree.hpp" #include #include diff --git a/tools/miniswig/lexer.ll b/tools/miniswig/lexer.ll index 42d7f648c..954138b07 100644 --- a/tools/miniswig/lexer.ll +++ b/tools/miniswig/lexer.ll @@ -1,4 +1,6 @@ %{ +#include + #include #include #include diff --git a/tools/miniswig/main.cpp b/tools/miniswig/main.cpp index cbb76f15a..8a5080198 100644 --- a/tools/miniswig/main.cpp +++ b/tools/miniswig/main.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include diff --git a/tools/miniswig/parser.yy b/tools/miniswig/parser.yy index a54c0afef..f992fc7a0 100644 --- a/tools/miniswig/parser.yy +++ b/tools/miniswig/parser.yy @@ -1,4 +1,5 @@ %{ +#include #include #include diff --git a/tools/miniswig/tree.cpp b/tools/miniswig/tree.cpp index 3d5413e38..848b30b09 100644 --- a/tools/miniswig/tree.cpp +++ b/tools/miniswig/tree.cpp @@ -1,3 +1,4 @@ +#include #include "tree.hpp" BasicType BasicType::VOID("void");