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
/* 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
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);
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 {
} 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);
}
(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")
(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)
(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);
+++ /dev/null
-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();
-}
//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);
//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);
//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);
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) {
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";
// load worldmap and wait till it is displayed
load_worldmap(state.world);
-fadeout_screen(0.5);
wait_for_screenswitch();
save_state();
#include "sound_source.hpp"
#include "stream_sound_source.hpp"
#include "log.hpp"
+#include "timer.hpp"
SoundManager* sound_manager = 0;
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(); ) {
#include "stream_sound_source.hpp"
#include "sound_manager.hpp"
#include "sound_file.hpp"
+#include "timer.hpp"
#include "log.hpp"
StreamSoundSource::StreamSoundSource()
}
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;
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;
{
this->fade_state = state;
this->fade_time = fade_time;
- this->fade_start_ticks = SDL_GetTicks();
+ this->fade_start_time = real_time;
}
bool
ALuint buffers[STREAMFRAGMENTS];
FadeState fade_state;
- Uint32 fade_start_ticks;
+ float fade_start_time;
float fade_time;
bool looping;
};
#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"
Console::~Console()
{
if(vm != NULL) {
- sq_release(ScriptManager::instance->get_vm(), &vm_object);
+ sq_release(Scripting::global_vm, &vm_object);
}
}
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);
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)
screenwidth = 800;
screenheight = 600;
+
+ enable_script_debugger = false;
}
Config::~Config()
/** 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;
};
#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;
last_menus.push_back(current_);
current_ = pmenu;
- current_->effect_ticks = SDL_GetTicks();
+ current_->effect_time = real_time;
}
void
{
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;
last_menus.clear();
if (menu)
- menu->effect_ticks = SDL_GetTicks();
+ menu->effect_time = real_time;
current_ = menu;
// just to be sure...
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];
for(std::vector<MenuItem*>::iterator i = items.begin();
i != items.end(); ++i)
delete *i;
+#ifdef DEBUG
+ assert(current_ != this);
+#else
+ if(current_ == this)
+ current_ = NULL;
+#endif
}
Menu::Menu()
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)
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);
}
}
void
Menu::event(const SDL_Event& event)
{
- if(effect_ticks != 0)
+ if(effect_time != 0)
return;
switch(event.type) {
/* input implementation variables */
int delete_character;
char mn_input_char;
- Uint32 menu_repeat_ticks;
+ float menu_repeat_time;
public:
static Font* default_font;
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;
#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"
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;
;
}
-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)
glLoadIdentity();
glTranslatef(0, 0, 0);
- check_gl_error();
+ check_gl_error("Setting up view matrices");
if(texture_manager != NULL)
texture_manager->reload_textures();
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) {
init_video();
Console::instance->init_graphics();
timelog("scripting");
- init_scripting();
-
+ Scripting::init_squirrel(config->enable_script_debugger);
timelog("resources");
load_shared();
timelog(0);
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();
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
#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"
MainLoop* main_loop = NULL;
MainLoop::MainLoop()
- : speed(1.0)
+ : speed(1.0), nextpop(false), nextpush(false)
{
+ using namespace Scripting;
+ TimeScheduler::instance = new TimeScheduler();
}
MainLoop::~MainLoop()
{
+ using namespace Scripting;
+ delete TimeScheduler::instance;
+ TimeScheduler::instance = NULL;
+
for(std::vector<Screen*>::iterator i = screen_stack.begin();
i != screen_stack.end(); ++i) {
delete *i;
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();
}
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();
}
}
+ 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);
#include <memory>
#include <vector>
+#include "scripting/thread_queue.hpp"
class Screen;
class Console;
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);
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;
log_warning << "Couldn't play '" << sample << "': " << e.what() << "" << std::endl;
delete sound_source;
sound_source = 0;
+ remove_me();
}
}
void
AmbientSound::update(float deltat)
-{
- if (latency--<=0) {
-
+{
+ if (latency-- <= 0) {
float px,py;
float rx,ry;
// Player position
-
px=Sector::current()->player->get_pos().x;
py=Sector::current()->player->get_pos().y;
// Relate to which point in the area
-
rx=px<position.x?position.x:
(px<position.x+dimension.x?px:position.x+dimension.x);
ry=py<position.y?position.y:
(py<position.y+dimension.y?py:position.y+dimension.y);
// calculate square of distance
-
float sqrdistance=(px-rx)*(px-rx)+(py-ry)*(py-ry);
-
sqrdistance-=distance_bias;
// inside the bias: full volume (distance 0)
-
if (sqrdistance<0)
sqrdistance=0;
// calculate target volume - will never become 0
-
targetvolume=1/(1+sqrdistance*distance_factor);
-
float rise=targetvolume/currentvolume;
// rise/fall half life?
-
currentvolume*=pow(rise,deltat*10);
currentvolume += 1e-6; // volume is at least 1e-6 (0 would never rise)
#include "lisp/writer.hpp"
#include "lisp/list_iterator.hpp"
#include "scripting/camera.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
#include "camera.hpp"
#include "player.hpp"
#include "tilemap.hpp"
#include <assert.h>
#include "video/drawing_context.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
#include "main.hpp"
static const float BORDER_SIZE = 75;
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
#include <config.h>
#include <typeinfo>
#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"
#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"
#include <iostream>
#include "resources.hpp"
#include "video/drawing_context.hpp"
-#include "scripting/wrapper_util.hpp"
+#include "scripting/squirrel_util.hpp"
#include "log.hpp"
TextObject::TextObject()
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-#include <config.h>
-
-#include "script_manager.hpp"
-
-#include <stdarg.h>
-#include <stdexcept>
-#include <sstream>
-#include <fstream>
-#include <sqstdaux.h>
-#include <sqstdblob.h>
-#include <sqstdmath.h>
-#include <sqstdstring.h>
-
-#include "timer.hpp"
-#include "console.hpp"
-#include "log.hpp"
-#include "scripting/wrapper.hpp"
-#include "scripting/wrapper_util.hpp"
-#include "scripting/squirrel_error.hpp"
-#include "physfs/physfs_stream.hpp"
-
-using namespace Scripting;
-
-ScriptManager* ScriptManager::instance = NULL;
-
-static void printfunc(HSQUIRRELVM, const char* str, ...)
-{
- char buf[4096];
- va_list arglist;
- va_start(arglist, str);
- vsprintf(buf, str, arglist);
- Console::output << (const char*) buf << std::flush;
- va_end(arglist);
-}
-
-ScriptManager::ScriptManager()
- : parent(NULL)
-{
- vm = sq_open(64);
- if(vm == 0)
- throw std::runtime_error("Couldn't initialize squirrel vm");
- sq_setforeignptr(vm, (SQUserPointer) this);
-
-#ifdef ENABLE_SQDBG
- debugger = NULL;
- /*
- debugger = sq_rdbg_init(vm, 1234, SQFalse);
- if(debugger == NULL)
- throw SquirrelError(vm, "Couldn't initialize suirrel remote debugger");
-
- sq_enabledebuginfo(vm, SQTrue);
- log_info << "Waiting for debug client..." << std::endl;
- if(!SQ_SUCCEEDED(sq_rdbg_waitforconnections(debugger))) {
- throw SquirrelError(vm, "Waiting for debug clients failed");
- }
- log_info << "debug client connected." << std::endl;
- */
-#endif
-
- // register squirrel libs
- sq_pushroottable(vm);
- if(sqstd_register_bloblib(vm) < 0)
- throw SquirrelError(vm, "Couldn't register blob lib");
- if(sqstd_register_mathlib(vm) < 0)
- throw SquirrelError(vm, "Couldn't register math lib");
- if(sqstd_register_stringlib(vm) < 0)
- throw SquirrelError(vm, "Couldn't register string lib");
- // register supertux API
- register_supertux_wrapper(vm);
- sq_pop(vm, 1);
-
- // register print function
- sq_setprintfunc(vm, printfunc);
- // register default error handlers
- sqstd_seterrorhandlers(vm);
-
- // try to load default script
- try {
- std::string filename = "scripts/default.nut";
- IFileStream stream(filename);
- Scripting::compile_and_run(vm, stream, filename);
- } catch(std::exception& e) {
- log_warning << "Couldn't load default.nut: " << e.what() << std::endl;
- }
-}
-
-ScriptManager::ScriptManager(ScriptManager* parent)
-{
-#ifdef ENABLE_SQDBG
- debugger = NULL;
-#endif
- this->parent = parent;
- vm = parent->vm;
- parent->childs.push_back(this);
-}
-
-ScriptManager::~ScriptManager()
-{
- for(SquirrelVMs::iterator i = squirrel_vms.begin();
- i != squirrel_vms.end(); ++i)
- sq_release(vm, &(i->vm_obj));
-
- if(parent != NULL) {
- parent->childs.erase(
- std::remove(parent->childs.begin(), parent->childs.end(), this),
- parent->childs.end());
- } else {
-#ifdef ENABLE_SQDBG
- sq_rdbg_shutdown(debugger);
-#endif
- sq_close(vm);
- }
-}
-
-HSQUIRRELVM
-ScriptManager::create_thread(bool leave_thread_on_stack)
-{
- HSQUIRRELVM new_vm = sq_newthread(vm, 64);
- if(new_vm == NULL)
- throw SquirrelError(vm, "Couldn't create new VM");
- sq_setforeignptr(new_vm, (SQUserPointer) this);
-
- // retrieve reference to thread from stack and increase refcounter
- HSQOBJECT vm_obj;
- sq_resetobject(&vm_obj);
- if(SQ_FAILED(sq_getstackobj(vm, -1, &vm_obj))) {
- throw SquirrelError(vm, "Couldn't get coroutine vm from stack");
- }
- sq_addref(vm, &vm_obj);
-
- if(!leave_thread_on_stack)
- sq_pop(vm, 1);
-
- squirrel_vms.push_back(SquirrelVM(new_vm, vm_obj));
-
- return new_vm;
-}
-
-void
-ScriptManager::update()
-{
-#ifdef ENABLE_SQDBG
- if(debugger != NULL)
- sq_rdbg_update(debugger);
-#endif
-
- for(SquirrelVMs::iterator i = squirrel_vms.begin(); i != squirrel_vms.end(); ) {
- SquirrelVM& squirrel_vm = *i;
- int vm_state = sq_getvmstate(squirrel_vm.vm);
-
- if(vm_state == SQ_VMSTATE_SUSPENDED
- && squirrel_vm.wakeup_time > 0
- && game_time >= squirrel_vm.wakeup_time) {
- squirrel_vm.waiting_for_events = WakeupData(NO_EVENT);
- squirrel_vm.wakeup_time = 0;
-
- try {
- if(SQ_FAILED(sq_wakeupvm(squirrel_vm.vm, false, false))) {
- throw SquirrelError(squirrel_vm.vm, "Couldn't resume script");
- }
- } catch(std::exception& e) {
- std::cerr << "Problem executing script: " << e.what() << "\n";
- sq_release(vm, &squirrel_vm.vm_obj);
- i = squirrel_vms.erase(i);
- continue;
- }
- }
-
- if (vm_state != SQ_VMSTATE_SUSPENDED) {
- sq_release(vm, &(squirrel_vm.vm_obj));
- i = squirrel_vms.erase(i);
- } else {
- ++i;
- }
- }
-}
-
-void
-ScriptManager::set_wakeup_event(HSQUIRRELVM vm, WakeupData event, float timeout)
-{
- assert(event.type >= 0 && event.type < WAKEUP_EVENT_COUNT);
- // find the VM in the list and update it
- for(SquirrelVMs::iterator i = squirrel_vms.begin();
- i != squirrel_vms.end(); ++i) {
- SquirrelVM& squirrel_vm = *i;
- if(squirrel_vm.vm == vm)
- {
- squirrel_vm.waiting_for_events = event;
-
- if(timeout < 0) {
- squirrel_vm.wakeup_time = -1;
- } else {
- squirrel_vm.wakeup_time = game_time + timeout;
- }
- return;
- }
- }
-}
-
-void
-ScriptManager::fire_wakeup_event(WakeupData event)
-{
- assert(event.type >= 0 && event.type < WAKEUP_EVENT_COUNT);
- for(SquirrelVMs::iterator i = squirrel_vms.begin();
- i != squirrel_vms.end(); ++i) {
- SquirrelVM& vm = *i;
- if(vm.waiting_for_events.type == event.type
- && vm.waiting_for_events.type != NO_EVENT) {
- vm.wakeup_time = game_time;
- break;
- }
- }
-
- for(std::vector<ScriptManager*>::iterator i = childs.begin();
- i != childs.end(); ++i) {
- ScriptManager* child = *i;
- child->fire_wakeup_event(event);
- }
-}
-
-void
-ScriptManager::set_wakeup_event(HSQUIRRELVM vm, WakeupEvent event, float timeout)
-{
- set_wakeup_event(vm, WakeupData(event), timeout);
-}
-
-void
-ScriptManager::fire_wakeup_event(WakeupEvent event)
-{
- fire_wakeup_event(WakeupData(event));
-}
-
-ScriptManager::SquirrelVM::SquirrelVM(HSQUIRRELVM arg_vm, HSQOBJECT arg_obj)
- : vm(arg_vm), vm_obj(arg_obj)
-{
- waiting_for_events = WakeupData(NO_EVENT);
- wakeup_time = 0;
-}
-
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-#ifndef __SCRIPT_MANAGER_H__
-#define __SCRIPT_MANAGER_H__
-
-#include <vector>
-#include <list>
-#include <squirrel.h>
-#include <iostream>
-#include "timer.hpp"
-#ifdef ENABLE_SQDBG
-#include <sqdbg/sqrdbg.h>
-#endif
-
-class GameObject;
-
-/**
- * This class is responsible for managing all running squirrel threads
- * (they are cooperative threads or coroutines)
- * It keeps a list of suspended scripts and receives wakeup events for them
- */
-class ScriptManager
-{
-public:
- ScriptManager();
- ScriptManager(ScriptManager* parent);
- ~ScriptManager();
-
- void update();
-
- /**
- * Creates a new thread and registers it with the script manager
- * (so it can suspend and register for wakeup events)
- */
- HSQUIRRELVM create_thread(bool leave_thread_on_stack = false);
-
- HSQUIRRELVM get_vm() const
- {
- return vm;
- }
-
- enum WakeupEvent {
- NO_EVENT,
- TIME,
- SCREEN_SWITCHED,
- WAKEUP_EVENT_COUNT
- };
-
- struct WakeupData {
- explicit WakeupData() : type(NO_EVENT) {}
- explicit WakeupData(WakeupEvent type_) : type(type_) {}
-
- WakeupEvent type;
-
- union {
- // GAMEOBJECT_DONE
- GameObject* game_object;
- };
- };
-
- void set_wakeup_event(HSQUIRRELVM vm, WakeupEvent event, float timeout = -1);
- void set_wakeup_event(HSQUIRRELVM vm, WakeupData event, float timeout = -1);
- void fire_wakeup_event(WakeupEvent event);
- void fire_wakeup_event(WakeupData event);
-
- // global (root) instance of the ScriptManager
- static ScriptManager* instance;
-
-private:
- class SquirrelVM
- {
- public:
- SquirrelVM(HSQUIRRELVM arg_vm, HSQOBJECT arg_obj);
-
- HSQUIRRELVM vm;
- HSQOBJECT vm_obj;
- float wakeup_time;
- WakeupData waiting_for_events;
- };
-
- typedef std::list<SquirrelVM> SquirrelVMs;
- SquirrelVMs squirrel_vms;
-
- HSQUIRRELVM vm;
- ScriptManager* parent;
- std::vector<ScriptManager*> childs;
-#ifdef ENABLE_SQDBG
- HSQREMOTEDBG debugger;
-#endif
-};
-
-#endif
-
#include "game_session.hpp"
#include "tinygettext/tinygettext.hpp"
#include "physfs/physfs_stream.hpp"
-#include "script_manager.hpp"
#include "resources.hpp"
#include "gettext.hpp"
#include "log.hpp"
#include "shrinkfade.hpp"
#include "object/camera.hpp"
#include "flip_level_transformer.hpp"
+#include "audio/sound_manager.hpp"
#include "squirrel_error.hpp"
-#include "wrapper_util.hpp"
+#include "squirrel_util.hpp"
+#include "time_scheduler.hpp"
namespace Scripting
{
int get_current_thread(HSQUIRRELVM vm)
{
- SQObject object;
- sq_resetobject(&object);
- object._unVal.pThread = vm;
- object._type = OT_THREAD;
- sq_pushobject(vm, object);
-
+ sq_pushobject(vm, vm_to_object(vm));
return 1;
}
void wait(HSQUIRRELVM vm, float seconds)
{
- SQUserPointer ptr = sq_getforeignptr(vm);
- ScriptManager* script_manager = reinterpret_cast<ScriptManager*> (ptr);
- script_manager->set_wakeup_event(vm, ScriptManager::TIME, seconds);
+ TimeScheduler::instance->schedule_thread(vm, game_time + seconds);
}
void wait_for_screenswitch(HSQUIRRELVM vm)
{
- SQUserPointer ptr = sq_getforeignptr(vm);
- ScriptManager* script_manager = reinterpret_cast<ScriptManager*> (ptr);
- script_manager->set_wakeup_event(vm, ScriptManager::SCREEN_SWITCHED);
+ main_loop->waiting_threads.add(vm);
}
void exit_screen()
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");
}
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;
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();
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#include <config.h>
-
-#include <string>
-#include <stdio.h>
-#include "sound.hpp"
-#include "resources.hpp"
-#include "audio/sound_manager.hpp"
-
-namespace Scripting
-{
-
- Sound::Sound()
- {}
-
- Sound::~Sound()
- {}
-
- void
- Sound::play_music(const std::string& filename)
- {
- sound_manager->play_music(filename);
- }
-
- void
- Sound::play(const std::string& name)
- {
- sound_manager->play(name);
- }
-}
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#ifndef __SOUND_H__
-#define __SOUND_H__
-
-namespace Scripting
-{
-
-/**
- * This class allows manipulating the sound output of the game
- */
-class Sound
-{
-public:
- void play_music(const std::string& musicfile);
- /**
- * Play a sound effect. The name should be without path or .wav extension
- */
- void play(const std::string& soundfile);
-
- ~Sound();
-
-#ifndef SCRIPTING_API
- Sound();
-#endif
-};
-
-}
-
-#endif
-
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
#include <config.h>
#include "squirrel_error.hpp"
{
sq_getstring(v, -1, &lasterr);
}
- sq_pop(v, 1);
msg << lasterr << ")";
+ sq_pop(v, 1);
this->message = msg.str();
}
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#include <config.h>
+
+#include <stdexcept>
+#include <sstream>
+#include <stdarg.h>
+#include <squirrel.h>
+#include <sqstdmath.h>
+#include <sqstdblob.h>
+#include <sqstdstring.h>
+#include <sqstdaux.h>
+#include <sqstdio.h>
+#include "squirrel_util.hpp"
+#include "log.hpp"
+#include "level.hpp"
+#include "physfs/physfs_stream.hpp"
+
+#ifdef ENABLE_SQDBG
+#include <sqdbg/sqrdbg.h>
+
+static HSQREMOTEDBG debugger = NULL;
+#endif
+
+namespace Scripting
+{
+
+HSQUIRRELVM global_vm = NULL;
+
+static void printfunc(HSQUIRRELVM, const char* str, ...)
+{
+ char buf[4096];
+ va_list arglist;
+ va_start(arglist, str);
+ vsprintf(buf, str, arglist);
+ Console::output << (const char*) buf << std::flush;
+ va_end(arglist);
+}
+
+void init_squirrel(bool enable_debugger)
+{
+ global_vm = sq_open(64);
+ if(global_vm == NULL)
+ throw std::runtime_error("Couldn't initialize squirrel vm");
+
+#ifdef ENABLE_SQDBG
+ if(enable_debugger) {
+ sq_enabledebuginfo(global_vm, SQTrue);
+ debugger = sq_rdbg_init(global_vm, 1234, SQFalse);
+ if(debugger == NULL)
+ throw SquirrelError(global_vm, "Couldn't initialize squirrel debugger");
+
+ sq_enabledebuginfo(global_vm, SQTrue);
+ log_info << "Waiting for debug client..." << std::endl;
+ if(SQ_FAILED(sq_rdbg_waitforconnections(debugger)))
+ throw SquirrelError(global_vm, "Waiting for debug clients failed");
+ log_info << "debug client connected." << std::endl;
+ }
+#endif
+
+ sq_pushroottable(global_vm);
+ if(sqstd_register_bloblib(global_vm) < 0)
+ throw SquirrelError(global_vm, "Couldn't register blob lib");
+ if(sqstd_register_mathlib(global_vm) < 0)
+ throw SquirrelError(global_vm, "Couldn't register math lib");
+ if(sqstd_register_stringlib(global_vm) < 0)
+ throw SquirrelError(global_vm, "Couldn't register string lib");
+ // register supertux API
+ register_supertux_wrapper(global_vm);
+
+ // TODO remove this at some point... it shoud just be functions not an object
+ expose_object(global_vm, -1, new Scripting::Level(), "Level", true);
+
+ sq_pop(global_vm, 1);
+
+ // register print function
+ sq_setprintfunc(global_vm, printfunc);
+ // register default error handlers
+ sqstd_seterrorhandlers(global_vm);
+
+ // try to load default script
+ try {
+ std::string filename = "scripts/default.nut";
+ IFileStream stream(filename);
+ Scripting::compile_and_run(global_vm, stream, filename);
+ } catch(std::exception& e) {
+ log_warning << "Couldn't load default.nut: " << e.what() << std::endl;
+ }
+}
+
+void exit_squirrel()
+{
+#ifdef ENABLE_SQDBG
+ if(debugger != NULL) {
+ sq_rdbg_shutdown(debugger);
+ debugger = NULL;
+ }
+#endif
+ sq_close(global_vm);
+ global_vm = NULL;
+}
+
+void update_debugger()
+{
+#ifdef ENABLE_SQDBG
+ if(debugger != NULL)
+ sq_rdbg_update(debugger);
+#endif
+}
+
+std::string squirrel2string(HSQUIRRELVM v, int i)
+{
+ std::ostringstream os;
+ switch(sq_gettype(v, i))
+ {
+ case OT_NULL:
+ os << "<null>";
+ break;
+ case OT_BOOL: {
+ SQBool p;
+ sq_getbool(v, i, &p);
+ if (p)
+ os << "true";
+ else
+ os << "false";
+ break;
+ }
+ case OT_INTEGER: {
+ int val;
+ sq_getinteger(v, i, &val);
+ os << val;
+ break;
+ }
+ case OT_FLOAT: {
+ float val;
+ sq_getfloat(v, i, &val);
+ os << val;
+ break;
+ }
+ case OT_STRING: {
+ const char* val;
+ sq_getstring(v, i, &val);
+ os << "\"" << val << "\"";
+ break;
+ }
+ case OT_TABLE: {
+ bool first = true;
+ os << "{";
+ sq_pushnull(v); //null iterator
+ while(SQ_SUCCEEDED(sq_next(v,i-1)))
+ {
+ if (!first) {
+ os << ", ";
+ }
+ first = false;
+
+ //here -1 is the value and -2 is the key
+ os << squirrel2string(v, -2) << " => "
+ << squirrel2string(v, -1);
+
+ sq_pop(v,2); //pops key and val before the nex iteration
+ }
+ sq_pop(v, 1);
+ os << "}";
+ break;
+ }
+ case OT_ARRAY: {
+ bool first = true;
+ os << "[";
+ sq_pushnull(v); //null iterator
+ while(SQ_SUCCEEDED(sq_next(v,i-1)))
+ {
+ if (!first) {
+ os << ", ";
+ }
+ first = false;
+
+ //here -1 is the value and -2 is the key
+ // we ignore the key, since that is just the index in an array
+ os << squirrel2string(v, -1);
+
+ sq_pop(v,2); //pops key and val before the nex iteration
+ }
+ sq_pop(v, 1);
+ os << "]";
+ break;
+ }
+ case OT_USERDATA:
+ os << "<userdata>";
+ break;
+ case OT_CLOSURE:
+ os << "<closure>";
+ break;
+ case OT_NATIVECLOSURE:
+ os << "<native closure>";
+ break;
+ case OT_GENERATOR:
+ os << "<generator>";
+ break;
+ case OT_USERPOINTER:
+ os << "userpointer";
+ break;
+ case OT_THREAD:
+ os << "<thread>";
+ break;
+ case OT_CLASS:
+ os << "<class>";
+ break;
+ case OT_INSTANCE:
+ os << "<instance>";
+ break;
+ case OT_WEAKREF:
+ os << "<weakref>";
+ break;
+ default:
+ os << "<unknown>";
+ break;
+ }
+ return os.str();
+}
+
+void print_squirrel_stack(HSQUIRRELVM v)
+{
+ printf("--------------------------------------------------------------\n");
+ int count = sq_gettop(v);
+ for(int i = 1; i <= count; ++i) {
+ printf("%d: ",i);
+ switch(sq_gettype(v, i))
+ {
+ case OT_NULL:
+ printf("null");
+ break;
+ case OT_INTEGER: {
+ int val;
+ sq_getinteger(v, i, &val);
+ printf("integer (%d)", val);
+ break;
+ }
+ case OT_FLOAT: {
+ float val;
+ sq_getfloat(v, i, &val);
+ printf("float (%f)", val);
+ break;
+ }
+ case OT_STRING: {
+ const char* val;
+ sq_getstring(v, i, &val);
+ printf("string (%s)", val);
+ break;
+ }
+ case OT_TABLE:
+ printf("table");
+ break;
+ case OT_ARRAY:
+ printf("array");
+ break;
+ case OT_USERDATA:
+ printf("userdata");
+ break;
+ case OT_CLOSURE:
+ printf("closure(function)");
+ break;
+ case OT_NATIVECLOSURE:
+ printf("native closure(C function)");
+ break;
+ case OT_GENERATOR:
+ printf("generator");
+ break;
+ case OT_USERPOINTER:
+ printf("userpointer");
+ break;
+ case OT_THREAD:
+ printf("thread");
+ break;
+ case OT_CLASS:
+ printf("class");
+ break;
+ case OT_INSTANCE:
+ printf("instance");
+ break;
+ case OT_WEAKREF:
+ printf("weakref");
+ break;
+ default:
+ printf("unknown?!?");
+ break;
+ }
+ printf("\n");
+ }
+ printf("--------------------------------------------------------------\n");
+}
+
+static SQInteger squirrel_read_char(SQUserPointer file)
+{
+ std::istream* in = reinterpret_cast<std::istream*> (file);
+ char c = in->get();
+ if(in->eof())
+ return 0;
+ return c;
+}
+
+void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
+{
+ if(SQ_FAILED(sq_compile(vm, squirrel_read_char, &in, sourcename.c_str(), true)))
+ throw SquirrelError(vm, "Couldn't parse script");
+}
+
+void compile_and_run(HSQUIRRELVM vm, std::istream& in,
+ const std::string& sourcename)
+{
+ compile_script(vm, in, sourcename);
+
+ int oldtop = sq_gettop(vm);
+
+ try {
+ sq_pushroottable(vm);
+ if(SQ_FAILED(sq_call(vm, 1, SQFalse, SQTrue)))
+ throw SquirrelError(vm, "Couldn't start script");
+ } catch(...) {
+ sq_settop(vm, oldtop);
+ throw;
+ }
+
+ // we can remove the closure in case the script was not suspended
+ if(sq_getvmstate(vm) != SQ_VMSTATE_SUSPENDED) {
+ sq_settop(vm, oldtop-1);
+ }
+}
+
+HSQOBJECT create_thread(HSQUIRRELVM vm)
+{
+ HSQUIRRELVM new_vm = sq_newthread(vm, 64);
+ if(new_vm == NULL)
+ throw SquirrelError(vm, "Couldn't create new VM");
+
+ HSQOBJECT vm_object;
+ sq_resetobject(&vm_object);
+ if(SQ_FAILED(sq_getstackobj(vm, -1, &vm_object)))
+ throw SquirrelError(vm, "Couldn't get squirrel thread from stack");
+ sq_addref(vm, &vm_object);
+
+ sq_pop(vm, 1);
+
+ return vm_object;
+}
+
+HSQOBJECT vm_to_object(HSQUIRRELVM vm)
+{
+ HSQOBJECT object;
+ sq_resetobject(&object);
+ object._unVal.pThread = vm;
+ object._type = OT_THREAD;
+
+ return object;
+}
+
+HSQUIRRELVM object_to_vm(HSQOBJECT object)
+{
+ if(object._type != OT_THREAD)
+ return NULL;
+
+ return object._unVal.pThread;
+}
+
+}
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#ifndef __SQUIRREL_UTIL_HPP__
+#define __SQUIRREL_UTIL_HPP__
+
+#include <squirrel.h>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include "wrapper.hpp"
+#include "squirrel_error.hpp"
+
+namespace Scripting
+{
+
+ extern HSQUIRRELVM global_vm;
+
+ void init_squirrel(bool enable_debugger);
+ void exit_squirrel();
+ void update_debugger();
+
+ std::string squirrel2string(HSQUIRRELVM vm, int i);
+ void print_squirrel_stack(HSQUIRRELVM vm);
+
+ HSQOBJECT create_thread(HSQUIRRELVM vm);
+ SQObject vm_to_object(HSQUIRRELVM vm);
+ HSQUIRRELVM object_to_vm(HSQOBJECT object);
+
+ void compile_script(HSQUIRRELVM vm, std::istream& in,
+ const std::string& sourcename);
+ void compile_and_run(HSQUIRRELVM vm, std::istream& in,
+ const std::string& sourcename);
+
+ template<typename T>
+ void expose_object(HSQUIRRELVM v, int table_idx, T* object,
+ const std::string& name, bool free = false)
+ {
+ sq_pushstring(v, name.c_str(), -1);
+ Scripting::create_squirrel_instance(v, object, free);
+
+ if(table_idx < 0)
+ table_idx -= 2;
+
+ // register instance in root table
+ if(SQ_FAILED(sq_createslot(v, table_idx))) {
+ std::ostringstream msg;
+ msg << "Couldn't register object '" << name << "' in squirrel table";
+ throw Scripting::SquirrelError(v, msg.str());
+ }
+ }
+
+ static inline void unexpose_object(HSQUIRRELVM v, int table_idx,
+ const std::string& name)
+ {
+ sq_pushstring(v, name.c_str(), name.length());
+
+ if(table_idx < 0)
+ table_idx -= 1;
+
+ if(SQ_FAILED(sq_deleteslot(v, table_idx, SQFalse))) {
+ std::ostringstream msg;
+ msg << "Couldn't unregister object '" << name << "' in squirrel root table";
+ throw Scripting::SquirrelError(v, msg.str());
+ }
+ }
+
+}
+
+#endif
--- /dev/null
+// $Id: wrapper_util.cpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+// SuperTux
+// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#include <config.h>
+
+#include "thread_queue.hpp"
+#include "squirrel_util.hpp"
+#include "log.hpp"
+
+namespace Scripting
+{
+
+ThreadQueue::ThreadQueue()
+{
+}
+
+ThreadQueue::~ThreadQueue()
+{
+}
+
+void
+ThreadQueue::add(HSQUIRRELVM vm)
+{
+ // create a weakref to the VM
+ HSQOBJECT vm_obj = vm_to_object(vm);
+ sq_pushobject(global_vm, vm_obj);
+ sq_weakref(global_vm, -1);
+
+ HSQOBJECT object;
+ if(SQ_FAILED(sq_getstackobj(global_vm, -1, &object))) {
+ sq_pop(global_vm, 2);
+ throw SquirrelError(global_vm, "Couldn't get thread weakref from vm");
+ }
+ sq_addref(global_vm, &object);
+ threads.push_back(object);
+
+ sq_pop(global_vm, 2);
+}
+
+void
+ThreadQueue::wakeup()
+{
+ // we traverse the list in reverse orders and use indices. This should be
+ // robust for scripts that add new entries to the list while we're traversing
+ // it
+ size_t i = threads.size() - 1;
+ size_t end = (size_t) 0 - 1;
+ size_t size_begin = threads.size();
+ while(i != end) {
+ HSQOBJECT object = threads[i];
+
+ sq_pushobject(global_vm, object);
+ sq_getweakrefval(global_vm, -1);
+
+ HSQUIRRELVM scheduled_vm;
+ if(sq_gettype(global_vm, -1) == OT_THREAD &&
+ SQ_SUCCEEDED(sq_getthread(global_vm, -1, &scheduled_vm))) {
+ if(SQ_FAILED(sq_wakeupvm(scheduled_vm, SQFalse, SQFalse, SQTrue))) {
+ log_warning << "Couldn't wakeup scheduled squirrel VM" << std::endl;
+ }
+ }
+
+ sq_release(global_vm, &object);
+ sq_pop(global_vm, 1);
+ i--;
+ }
+
+ threads.erase(threads.begin(), threads.begin() + size_begin);
+}
+
+}
+
--- /dev/null
+// $Id: wrapper_util.cpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+// SuperTux
+// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#ifndef __THREAD_QUEUE_HPP__
+#define __THREAD_QUEUE_HPP__
+
+#include <vector>
+#include <squirrel.h>
+
+namespace Scripting
+{
+
+/**
+ * Keeps a list of SquirrelThreads that wait for a wakeup event
+ */
+class ThreadQueue
+{
+public:
+ ThreadQueue();
+ virtual ~ThreadQueue();
+
+ /// adds a thread (actually a weakref to the thread)
+ void add(HSQUIRRELVM vm);
+ /// wakes up threads in the list
+ void wakeup();
+
+private:
+ typedef std::vector<HSQOBJECT> ThreadList;
+ ThreadList threads;
+};
+
+}
+
+#endif
+
--- /dev/null
+// $Id: script_manager.hpp 3379 2006-04-20 18:44:10Z matzebraun $
+//
+// SuperTux
+// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+#include <config.h>
+
+#include <algorithm>
+
+#include "time_scheduler.hpp"
+#include "squirrel_util.hpp"
+#include "squirrel_error.hpp"
+#include "log.hpp"
+
+namespace Scripting
+{
+
+TimeScheduler* TimeScheduler::instance = NULL;
+
+TimeScheduler::TimeScheduler()
+{
+}
+
+TimeScheduler::~TimeScheduler()
+{
+}
+
+void
+TimeScheduler::update(float time)
+{
+ while(!schedule.empty() && schedule.front().wakeup_time < time) {
+ HSQOBJECT thread_ref = schedule.front().thread_ref;
+
+ sq_pushobject(global_vm, thread_ref);
+ sq_getweakrefval(global_vm, -1);
+
+ HSQUIRRELVM scheduled_vm;
+ if(sq_gettype(global_vm, -1) == OT_THREAD &&
+ SQ_SUCCEEDED(sq_getthread(global_vm, -1, &scheduled_vm))) {
+ if(SQ_FAILED(sq_wakeupvm(scheduled_vm, SQFalse, SQFalse, SQTrue))) {
+ std::ostringstream msg;
+ msg << "Couldn't wakeup scheduled squirrel VM: ";
+ sq_getlasterror(scheduled_vm);
+ if(sq_gettype(scheduled_vm, -1) != OT_STRING) {
+ msg << "(no info)";
+ } else {
+ const char* lasterr;
+ sq_getstring(scheduled_vm, -1, &lasterr);
+ msg << lasterr;
+ }
+ log_warning << msg.str() << std::endl;
+ sq_pop(scheduled_vm, 1);
+ }
+ }
+
+ sq_release(global_vm, &thread_ref);
+ sq_pop(global_vm, 2);
+
+ pop_heap(schedule.begin(), schedule.end());
+ schedule.pop_back();
+ }
+}
+
+void
+TimeScheduler::schedule_thread(HSQUIRRELVM scheduled_vm, float time)
+{
+ // create a weakref to the VM
+ SQObject vm_obj = vm_to_object(scheduled_vm);
+ sq_pushobject(global_vm, vm_obj);
+ sq_weakref(global_vm, -1);
+
+ ScheduleEntry entry;
+ if(SQ_FAILED(sq_getstackobj(global_vm, -1, & entry.thread_ref))) {
+ sq_pop(global_vm, 2);
+ throw SquirrelError(global_vm, "Couldn't get thread weakref from vm");
+ }
+ entry.wakeup_time = time;
+
+ sq_addref(global_vm, & entry.thread_ref);
+ sq_pop(global_vm, 2);
+
+ schedule.push_back(entry);
+ std::push_heap(schedule.begin(), schedule.end());
+}
+
+}
+
--- /dev/null
+// $Id: script_manager.hpp 3379 2006-04-20 18:44:10Z matzebraun $
+//
+// SuperTux
+// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+#ifndef __TIME_SCHEDULER_HPP__
+#define __TIME_SCHEDULER_HPP__
+
+#include <vector>
+#include <squirrel.h>
+
+namespace Scripting
+{
+
+/**
+ * This class keeps a list of squirrel threads that are scheduled for a certain
+ * time. (the typical result of a wait() command in a squirrel script)
+ */
+class TimeScheduler
+{
+public:
+ TimeScheduler();
+ virtual ~TimeScheduler();
+
+ void update(float time);
+ void schedule_thread(HSQUIRRELVM vm, float time);
+
+ static TimeScheduler* instance;
+
+private:
+ struct ScheduleEntry {
+ /// weak reference to the squirrel vm object
+ HSQOBJECT thread_ref;
+ /// time when the thread should be woken up
+ float wakeup_time;
+
+ bool operator<(const ScheduleEntry& other) const
+ {
+ // we need the smallest value on top
+ return wakeup_time > other.wakeup_time;
+ }
+ };
+
+ typedef std::vector<ScheduleEntry> ScheduleHeap;
+ ScheduleHeap schedule;
+};
+
+}
+
+#endif
+
}
-static int Sound_release_hook(SQUserPointer ptr, int )
-{
- Scripting::Sound* _this = reinterpret_cast<Scripting::Sound*> (ptr);
- delete _this;
- return 0;
-}
-
-static int Sound_play_music_wrapper(HSQUIRRELVM vm)
-{
- Scripting::Sound* _this;
- if(SQ_FAILED(sq_getinstanceup(vm, 1, reinterpret_cast<SQUserPointer*> (&_this), 0))) {
- sq_throwerror(vm, _SC("'play_music' called without instance"));
- return SQ_ERROR;
- }
- const char* arg0;
- if(SQ_FAILED(sq_getstring(vm, 2, &arg0))) {
- sq_throwerror(vm, _SC("Argument 1 not a string"));
- return SQ_ERROR;
- }
-
- try {
- _this->play_music(arg0);
-
- return 0;
-
- } catch(std::exception& e) {
- sq_throwerror(vm, e.what());
- return SQ_ERROR;
- } catch(...) {
- sq_throwerror(vm, _SC("Unexpected exception while executing function 'play_music'"));
- return SQ_ERROR;
- }
-
-}
-
-static int Sound_play_wrapper(HSQUIRRELVM vm)
-{
- Scripting::Sound* _this;
- if(SQ_FAILED(sq_getinstanceup(vm, 1, reinterpret_cast<SQUserPointer*> (&_this), 0))) {
- sq_throwerror(vm, _SC("'play' called without instance"));
- return SQ_ERROR;
- }
- const char* arg0;
- if(SQ_FAILED(sq_getstring(vm, 2, &arg0))) {
- sq_throwerror(vm, _SC("Argument 1 not a string"));
- return SQ_ERROR;
- }
-
- try {
- _this->play(arg0);
-
- return 0;
-
- } catch(std::exception& e) {
- sq_throwerror(vm, e.what());
- return SQ_ERROR;
- } catch(...) {
- sq_throwerror(vm, _SC("Unexpected exception while executing function 'play'"));
- return SQ_ERROR;
- }
-
-}
-
static int Text_release_hook(SQUserPointer ptr, int )
{
Scripting::Text* _this = reinterpret_cast<Scripting::Text*> (ptr);
}
+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;
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;
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))) {
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) {
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);
#include "camera.hpp"
#include "level.hpp"
#include "scripted_object.hpp"
-#include "sound.hpp"
#include "text.hpp"
#include "functions.hpp"
#include "player.hpp"
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#include <config.h>
-
-#include <stdexcept>
-#include <sstream>
-#include "wrapper_util.hpp"
-
-namespace Scripting
-{
-
-std::string squirrel2string(HSQUIRRELVM v, int i)
-{
- std::ostringstream os;
- switch(sq_gettype(v, i))
- {
- case OT_NULL:
- os << "<null>";
- break;
- case OT_BOOL: {
- SQBool p;
- sq_getbool(v, i, &p);
- if (p)
- os << "true";
- else
- os << "false";
- break;
- }
- case OT_INTEGER: {
- int val;
- sq_getinteger(v, i, &val);
- os << val;
- break;
- }
- case OT_FLOAT: {
- float val;
- sq_getfloat(v, i, &val);
- os << val;
- break;
- }
- case OT_STRING: {
- const char* val;
- sq_getstring(v, i, &val);
- os << "\"" << val << "\"";
- break;
- }
- case OT_TABLE: {
- bool first = true;
- os << "{";
- sq_pushnull(v); //null iterator
- while(SQ_SUCCEEDED(sq_next(v,i-1)))
- {
- if (!first) {
- os << ", ";
- }
- first = false;
-
- //here -1 is the value and -2 is the key
- os << squirrel2string(v, -2) << " => "
- << squirrel2string(v, -1);
-
- sq_pop(v,2); //pops key and val before the nex iteration
- }
- sq_pop(v, 1);
- os << "}";
- break;
- }
- case OT_ARRAY: {
- bool first = true;
- os << "[";
- sq_pushnull(v); //null iterator
- while(SQ_SUCCEEDED(sq_next(v,i-1)))
- {
- if (!first) {
- os << ", ";
- }
- first = false;
-
- //here -1 is the value and -2 is the key
- // we ignore the key, since that is just the index in an array
- os << squirrel2string(v, -1);
-
- sq_pop(v,2); //pops key and val before the nex iteration
- }
- sq_pop(v, 1);
- os << "]";
- break;
- }
- case OT_USERDATA:
- os << "<userdata>";
- break;
- case OT_CLOSURE:
- os << "<closure (function)>";
- break;
- case OT_NATIVECLOSURE:
- os << "<native closure (C function)>";
- break;
- case OT_GENERATOR:
- os << "<generator>";
- break;
- case OT_USERPOINTER:
- os << "userpointer";
- break;
- case OT_THREAD:
- os << "<thread>";
- break;
- case OT_CLASS:
- os << "<class>";
- break;
- case OT_INSTANCE:
- os << "<instance>";
- break;
- default:
- os << "<unknown>";
- break;
- }
- return os.str();
-}
-
-void print_squirrel_stack(HSQUIRRELVM v)
-{
- printf("--------------------------------------------------------------\n");
- int count = sq_gettop(v);
- for(int i = 1; i <= count; ++i) {
- printf("%d: ",i);
- switch(sq_gettype(v, i))
- {
- case OT_NULL:
- printf("null");
- break;
- case OT_INTEGER: {
- int val;
- sq_getinteger(v, i, &val);
- printf("integer (%d)", val);
- break;
- }
- case OT_FLOAT: {
- float val;
- sq_getfloat(v, i, &val);
- printf("float (%f)", val);
- break;
- }
- case OT_STRING: {
- const char* val;
- sq_getstring(v, i, &val);
- printf("string (%s)", val);
- break;
- }
- case OT_TABLE:
- printf("table");
- break;
- case OT_ARRAY:
- printf("array");
- break;
- case OT_USERDATA:
- printf("userdata");
- break;
- case OT_CLOSURE:
- printf("closure(function)");
- break;
- case OT_NATIVECLOSURE:
- printf("native closure(C function)");
- break;
- case OT_GENERATOR:
- printf("generator");
- break;
- case OT_USERPOINTER:
- printf("userpointer");
- break;
- case OT_THREAD:
- printf("thread");
- break;
- case OT_CLASS:
- printf("class");
- break;
- case OT_INSTANCE:
- printf("instance");
- break;
- default:
- printf("unknown?!?");
- break;
- }
- printf("\n");
- }
- printf("--------------------------------------------------------------\n");
-}
-
-static SQInteger squirrel_read_char(SQUserPointer file)
-{
- std::istream* in = reinterpret_cast<std::istream*> (file);
- char c = in->get();
- if(in->eof())
- return 0;
- return c;
-}
-
-void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
-{
- if(SQ_FAILED(sq_compile(vm, squirrel_read_char, &in, sourcename.c_str(), true)))
- throw SquirrelError(vm, "Couldn't parse script");
-}
-
-void compile_and_run(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
-{
- compile_script(vm, in, sourcename);
-
- int oldtop = sq_gettop(vm);
-
- try {
- sq_pushroottable(vm);
- if(SQ_FAILED(sq_call(vm, 1, false)))
- throw SquirrelError(vm, "Couldn't start script");
- } catch(...) {
- sq_settop(vm, oldtop);
- throw;
- }
-
- sq_settop(vm, oldtop);
-}
-
-}
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#ifndef __WRAPPERUTIL_HPP__
-#define __WRAPPERUTIL_HPP__
-
-#include <squirrel.h>
-#include <sstream>
-#include <stdexcept>
-#include <string>
-#include "wrapper.hpp"
-#include "squirrel_error.hpp"
-
-namespace Scripting
-{
-
-std::string squirrel2string(HSQUIRRELVM vm, int i);
-void print_squirrel_stack(HSQUIRRELVM vm);
-void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename);
-void compile_and_run(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename);
-
-template<typename T>
-void expose_object(HSQUIRRELVM v, int table_idx, T* object,
- const std::string& name, bool free = false)
-{
- sq_pushstring(v, name.c_str(), -1);
- Scripting::create_squirrel_instance(v, object, free);
-
- if(table_idx < 0)
- table_idx -= 2;
-
- // register instance in root table
- if(SQ_FAILED(sq_createslot(v, table_idx))) {
- std::ostringstream msg;
- msg << "Couldn't register object '" << name << "' in squirrel table";
- throw Scripting::SquirrelError(v, msg.str());
- }
-}
-
-static inline void unexpose_object(HSQUIRRELVM v, int table_idx, const std::string& name)
-{
- sq_pushstring(v, name.c_str(), name.length());
-
- if(table_idx < 0)
- table_idx -= 1;
-
- if(SQ_FAILED(sq_deleteslot(v, table_idx, SQFalse))) {
- std::ostringstream msg;
- msg << "Couldn't unregister object '" << name << "' in squirrel root table";
- throw Scripting::SquirrelError(v, msg.str());
- }
-}
-
-}
-
-#endif
#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"
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);
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;
}
_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);
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)))
void
Sector::update(float elapsed_time)
{
- script_manager->update();
-
player->check_bounds(camera);
#if 0
{
ScriptInterface* interface = dynamic_cast<ScriptInterface*> (object);
if(interface != NULL) {
- HSQUIRRELVM vm = script_manager->get_vm();
+ HSQUIRRELVM vm = Scripting::global_vm;
sq_pushobject(vm, sector_table);
interface->expose(vm, -1);
sq_pop(vm, 1);
{
ScriptInterface* interface = dynamic_cast<ScriptInterface*> (object);
if(interface != NULL) {
- HSQUIRRELVM vm = script_manager->get_vm();
+ HSQUIRRELVM vm = Scripting::global_vm;
int oldtop = sq_gettop(vm);
sq_pushobject(vm, sector_table);
try {
#include <squirrel.h>
#include "direction.hpp"
-#include "script_manager.hpp"
#include "math/vector.hpp"
#include "video/drawing_context.hpp"
HSQOBJECT sector_table;
/// sector scripts
- std::auto_ptr<ScriptManager> script_manager;
+ typedef std::vector<HSQOBJECT> ScriptList;
+ ScriptList scripts;
public: // TODO make this private again
/// show collision rectangles of moving objects (for debugging)
#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)
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)
animation_loops(other.animation_loops),
action(other.action)
{
- last_ticks = SDL_GetTicks();
+ last_ticks = real_time;
}
Sprite::~Sprite()
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;
float frame;
int animation_loops;
- Uint32 last_ticks;
+ float last_ticks;
SpriteData::Action* action;
};
#define SQSTD_STREAM_TYPE_TAG 0x80000000\r
\r
struct SQStream {\r
- virtual ~SQStream() {}\r
virtual SQInteger Read(void *buffer, SQInteger size) = 0;\r
virtual SQInteger Write(void *buffer, SQInteger size) = 0;\r
virtual SQInteger Flush() = 0;\r
/*\r
-Copyright (c) 2003-2005 Alberto Demichelis\r
+Copyright (c) 2003-2006 Alberto Demichelis\r
\r
This software is provided 'as-is', without any \r
express or implied warranty. In no event will the \r
#define SQUIRREL_API extern\r
#endif\r
\r
-typedef float SQFloat;\r
+#ifdef _SQ64\r
+#ifdef _MSC_VER\r
+typedef __int64 SQInteger;\r
+typedef unsigned __int64 SQUnsignedInteger;\r
+typedef unsigned __int64 SQHash; /*should be the same size of a pointer*/\r
+#else\r
+typedef long SQInteger;\r
+typedef unsigned long SQUnsignedInteger;\r
+typedef unsigned long SQHash; /*should be the same size of a pointer*/\r
+#endif\r
+typedef int SQInt32; \r
+#else \r
typedef int SQInteger;\r
-typedef int SQInt32; //must be 32 bits(also on 64bits processors)\r
-typedef void* SQUserPointer;\r
+typedef int SQInt32; /*must be 32 bits(also on 64bits processors)*/\r
typedef unsigned int SQUnsignedInteger;\r
-typedef unsigned int SQHash; //should be the same size of a pointer\r
+typedef unsigned int SQHash; /*should be the same size of a pointer*/\r
+#endif\r
+\r
+typedef float SQFloat;\r
+typedef void* SQUserPointer;\r
typedef SQUnsignedInteger SQBool;\r
typedef SQInteger SQRESULT;\r
\r
#endif\r
\r
#ifdef SQUNICODE\r
-typedef unsigned short SQChar;\r
+#if defined(wchar_t) //this is if the compiler considers wchar_t as native type\r
+#define wchar_t unsigned short\r
+#endif\r
+typedef wchar_t SQChar;\r
#define _SC(a) L##a\r
#define scstrcmp wcscmp\r
#define scsprintf swprintf\r
#define scstrstr wcsstr\r
#define scisspace iswspace\r
#define scisdigit iswdigit\r
+#define scisxdigit iswxdigit\r
#define scisalpha iswalpha\r
#define sciscntrl iswcntrl\r
#define scisalnum iswalnum\r
#define scstrstr strstr\r
#define scisspace isspace\r
#define scisdigit isdigit\r
+#define scisxdigit isxdigit\r
#define sciscntrl iscntrl\r
#define scisalpha isalpha\r
#define scisalnum isalnum\r
#define MAX_CHAR 0xFF\r
#endif\r
\r
-#define SQUIRREL_VERSION _SC("Squirrel 2.0.5 stable")\r
-#define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2005 Alberto Demichelis")\r
+#define SQUIRREL_VERSION _SC("Squirrel 2.1 stable")\r
+#define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2006 Alberto Demichelis")\r
#define SQUIRREL_AUTHOR _SC("Alberto Demichelis")\r
\r
#define SQ_VMSTATE_IDLE 0\r
#define _RT_INSTANCE 0x00008000\r
#define _RT_WEAKREF 0x00010000\r
\r
-typedef enum {\r
+typedef enum tagSQObjectType{\r
OT_NULL = (_RT_NULL|SQOBJECT_CANBEFALSE),\r
OT_INTEGER = (_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE),\r
OT_FLOAT = (_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE),\r
SQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc);\r
SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v);\r
SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v);\r
-SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval);\r
+SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool raiseerror);\r
SQUIRREL_API SQInteger sq_getvmstate(HSQUIRRELVM v);\r
\r
/*compiler*/\r
SQUIRREL_API SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror);\r
SQUIRREL_API SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror);\r
-SQUIRREL_API void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo);\r
+SQUIRREL_API void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable);\r
+SQUIRREL_API void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable);\r
SQUIRREL_API void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f);\r
\r
/*stack operations*/\r
SQUIRREL_API void sq_newarray(HSQUIRRELVM v,SQInteger size);\r
SQUIRREL_API void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars);\r
SQUIRREL_API SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask);\r
+SQUIRREL_API SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx);\r
SQUIRREL_API void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len);\r
SQUIRREL_API void sq_pushfloat(HSQUIRRELVM v,SQFloat f);\r
SQUIRREL_API void sq_pushinteger(HSQUIRRELVM v,SQInteger n);\r
SQUIRREL_API void sq_pushnull(HSQUIRRELVM v);\r
SQUIRREL_API SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx);\r
SQUIRREL_API SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx);\r
+SQUIRREL_API SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx);\r
+SQUIRREL_API SQBool sq_instanceof(HSQUIRRELVM v);\r
SQUIRREL_API void sq_tostring(HSQUIRRELVM v,SQInteger idx);\r
+SQUIRREL_API void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b);\r
SQUIRREL_API SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c);\r
SQUIRREL_API SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i);\r
SQUIRREL_API SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f);\r
SQUIRREL_API SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx);\r
SQUIRREL_API SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx);\r
SQUIRREL_API void sq_weakref(HSQUIRRELVM v,SQInteger idx);\r
+SQUIRREL_API SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t);\r
\r
/*object manipulation*/\r
SQUIRREL_API void sq_pushroottable(HSQUIRRELVM v);\r
SQUIRREL_API void sq_pushregistrytable(HSQUIRRELVM v);\r
SQUIRREL_API SQRESULT sq_setroottable(HSQUIRRELVM v);\r
-SQUIRREL_API SQRESULT sq_createslot(HSQUIRRELVM v,SQInteger idx);\r
+/*SQUIRREL_API SQRESULT sq_createslot(HSQUIRRELVM v,SQInteger idx);*/\r
+SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic);\r
SQUIRREL_API SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval);\r
SQUIRREL_API SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx);\r
SQUIRREL_API SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx);\r
SQUIRREL_API SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx);\r
\r
/*calls*/\r
-SQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval);\r
-SQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval);\r
+SQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror);\r
+SQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror);\r
SQUIRREL_API const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx);\r
SQUIRREL_API const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval);\r
SQUIRREL_API SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err);\r
SQUIRREL_API SQBool sq_objtobool(HSQOBJECT *o);\r
SQUIRREL_API SQInteger sq_objtointeger(HSQOBJECT *o);\r
SQUIRREL_API SQFloat sq_objtofloat(HSQOBJECT *o);\r
+SQUIRREL_API SQRESULT sq_getobjtypetag(HSQOBJECT *o,SQUserPointer * typetag);\r
\r
/*GC*/\r
SQUIRREL_API SQInteger sq_collectgarbage(HSQUIRRELVM v);\r
#define sq_isweakref(o) ((o)._type==OT_WEAKREF)\r
#define sq_type(o) ((o)._type)\r
\r
+/* deprecated */\r
+#define sq_createslot(v,n) sq_newslot(v,n,SQFalse)\r
+\r
#define SQ_OK (0)\r
#define SQ_ERROR (-1)\r
\r
sq_createslot(_v,-3);\r
}\r
sq_rawset(_v,-3);\r
- if(SQ_SUCCEEDED(sq_call(_v,1,SQTrue))){\r
+ if(SQ_SUCCEEDED(sq_call(_v,1,SQTrue,SQTrue))){\r
if(SQ_SUCCEEDED(sqstd_getblob(_v,-1,(SQUserPointer*)&sz)))\r
SendChunk(sz);\r
}\r
/* see copyright notice in squirrel.h */\r
#include <squirrel.h>\r
#include <sqstdaux.h>\r
+#include <assert.h>\r
\r
void sqstd_printcallstack(HSQUIRRELVM v)\r
{\r
\r
for(level=0;level<10;level++){\r
seq=0;\r
- while(name=sq_getlocal(v,level,seq))\r
+ while((name = sq_getlocal(v,level,seq)))\r
{\r
seq++;\r
switch(sq_gettype(v,-1))\r
case OT_NATIVECLOSURE:\r
pf(v,_SC("[%s] NATIVECLOSURE\n"),name);\r
break;\r
+ case OT_GENERATOR:\r
+ pf(v,_SC("[%s] NATIVECLOSURE\n"),name);\r
+ break;\r
case OT_USERDATA:\r
pf(v,_SC("[%s] USERDATA\n"),name);\r
break;\r
case OT_INSTANCE:\r
pf(v,_SC("[%s] INSTANCE\n"),name);\r
break;\r
+ case OT_WEAKREF:\r
+ pf(v,_SC("[%s] INSTANCE\n"),name);\r
+ break;\r
+ case OT_BOOL:{\r
+ sq_getinteger(v,-1,&i);\r
+ pf(v,_SC("[%s] %s\n"),name,i?_SC("true"):_SC("false"));\r
+ }\r
+ break;\r
+ default: assert(0); break;\r
}\r
sq_pop(v,1);\r
}\r
\r
static void __swap_dword(unsigned int *n)\r
{\r
- *n=(SQUnsignedInteger)(((*n&0xFF000000)>>24) |\r
+ *n=(unsigned int)(((*n&0xFF000000)>>24) |\r
((*n&0x00FF0000)>>8) |\r
((*n&0x0000FF00)<<8) |\r
((*n&0x000000FF)<<24));\r
{\r
SQInteger i;\r
sq_getinteger(v,2,&i);\r
- __swap_dword((SQUnsignedInteger *)&i);\r
- sq_pushinteger(v,i);\r
+ unsigned int t4 = (unsigned int)i;\r
+ __swap_dword(&t4);\r
+ sq_pushinteger(v,(SQInteger)t4);\r
return 1;\r
}\r
\r
{\r
SQFloat f;\r
sq_getfloat(v,2,&f);\r
- __swap_dword((SQUnsignedInteger *)&f);\r
+ __swap_dword((unsigned int *)&f);\r
sq_pushfloat(v,f);\r
return 1;\r
}\r
sq_push(v,1); // push the this\r
sq_pushinteger(v,size); //size\r
SQBlob *blob = NULL;\r
- if(SQ_SUCCEEDED(sq_call(v,2,SQTrue))\r
+ if(SQ_SUCCEEDED(sq_call(v,2,SQTrue,SQFalse))\r
&& SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) {\r
sq_remove(v,-2);\r
sq_remove(v,-2);\r
_ptr = 0;\r
_owns = true;\r
}\r
- ~SQBlob() {\r
+ virtual ~SQBlob() {\r
sq_free(_buf, _allocated);\r
}\r
SQInteger Write(void *buffer, SQInteger size) {\r
case SQ_SEEK_SET: realorigin = SEEK_SET; break;\r
default: return -1; //failed\r
}\r
- return fseek((FILE *)file,offset,realorigin);\r
+ return fseek((FILE *)file,(long)offset,(int)realorigin);\r
}\r
\r
SQInteger sqstd_ftell(SQFILE file)\r
struct SQFile : public SQStream {\r
SQFile() { _handle = NULL; _owns = false;}\r
SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;}\r
- ~SQFile() { Close(); }\r
+ virtual ~SQFile() { Close(); }\r
bool Open(const SQChar *filename ,const SQChar *mode) {\r
Close();\r
- if(_handle = sqstd_fopen(filename,mode)) {\r
+ if( (_handle = sqstd_fopen(filename,mode)) ) {\r
_owns = true;\r
return true;\r
}\r
else{\r
sq_pushnull(v); //false\r
}\r
- if(SQ_SUCCEEDED( sq_call(v,3,SQTrue) )) {\r
+ if(SQ_SUCCEEDED( sq_call(v,3,SQTrue,SQFalse) )) {\r
sq_remove(v,-2);\r
return SQ_OK;\r
}\r
{\r
if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) {\r
sq_push(v,-2);\r
- SQInteger ntop = sq_gettop(v);\r
- if(SQ_SUCCEEDED(sq_call(v,1,retval))) {\r
+ if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) {\r
sq_remove(v,retval?-2:-1); //removes the closure\r
return 1;\r
}\r
return SQ_ERROR; //propagates the error\r
}\r
\r
+SQInteger _g_io_writeclosuretofile(HSQUIRRELVM v)\r
+{\r
+ const SQChar *filename;\r
+ sq_getstring(v,2,&filename);\r
+ if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,filename)))\r
+ return 1;\r
+ return SQ_ERROR; //propagates the error\r
+}\r
+\r
SQInteger _g_io_dofile(HSQUIRRELVM v)\r
{\r
const SQChar *filename;\r
static SQRegFunction iolib_funcs[]={\r
_DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")),\r
_DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")),\r
+ _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(".sc")),\r
{0,0}\r
};\r
\r
{\r
SQInteger i;\r
if(!sq_getinteger(v,2,&i))return sq_throwerror(v,_SC("invalid param"));\r
- srand(i);\r
+ srand((unsigned int)i);\r
return 0;\r
}\r
\r
{\r
SQInteger n;\r
sq_getinteger(v,2,&n);\r
- sq_pushinteger(v,(SQInteger)abs(n)); \r
+ sq_pushinteger(v,(SQInteger)abs((int)n)); \r
return 1; \r
}\r
\r
+++ /dev/null
-/* see copyright notice in squirrel.h */\r
-#include <squirrel.h>\r
-#include <string.h>\r
-#include <ctype.h>\r
-#include <setjmp.h>\r
-#include "sqstdstring.h"\r
-\r
-#ifdef _DEBUG\r
-#include <stdio.h>\r
-\r
-static const SQChar *g_nnames[] =\r
-{\r
- _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"),\r
- _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"),\r
- _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),\r
- _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")\r
-};\r
-\r
-#endif\r
-\r
-#define OP_GREEDY MAX_CHAR+1 // * + ? {n}\r
-#define OP_OR MAX_CHAR+2\r
-#define OP_EXPR MAX_CHAR+3 //parentesis ()\r
-#define OP_NOCAPEXPR MAX_CHAR+4 //parentesis (?:)\r
-#define OP_DOT MAX_CHAR+5\r
-#define OP_CLASS MAX_CHAR+6\r
-#define OP_CCLASS MAX_CHAR+7\r
-#define OP_NCLASS MAX_CHAR+8 //negates class the [^\r
-#define OP_RANGE MAX_CHAR+9\r
-#define OP_CHAR MAX_CHAR+10\r
-#define OP_EOL MAX_CHAR+11\r
-#define OP_BOL MAX_CHAR+12\r
-#define OP_WB MAX_CHAR+13\r
-\r
-#define SQREX_SYMBOL_ANY_CHAR '.'\r
-#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE '+'\r
-#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE '*'\r
-#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE '?'\r
-#define SQREX_SYMBOL_BRANCH '|'\r
-#define SQREX_SYMBOL_END_OF_STRING '$'\r
-#define SQREX_SYMBOL_BEGINNING_OF_STRING '^'\r
-#define SQREX_SYMBOL_ESCAPE_CHAR '\\'\r
-\r
-\r
-typedef int SQRexNodeType;\r
-\r
-typedef struct tagSQRexNode{\r
- SQRexNodeType type;\r
- SQInteger left;\r
- SQInteger right;\r
- SQInteger next;\r
-}SQRexNode;\r
-\r
-struct SQRex{\r
- const SQChar *_eol;\r
- const SQChar *_bol;\r
- const SQChar *_p;\r
- SQInteger _first;\r
- SQInteger _op;\r
- SQRexNode *_nodes;\r
- SQInteger _nallocated;\r
- SQInteger _nsize;\r
- SQInteger _nsubexpr;\r
- SQRexMatch *_matches;\r
- SQInteger _currsubexp;\r
- void *_jmpbuf;\r
- const SQChar **_error;\r
-};\r
-\r
-static SQInteger sqstd_rex_list(SQRex *exp);\r
-\r
-static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type)\r
-{\r
- SQRexNode n;\r
- n.type = type;\r
- n.next = n.right = n.left = -1;\r
- if(type == OP_EXPR)\r
- n.right = exp->_nsubexpr++;\r
- if(exp->_nallocated < (exp->_nsize + 1)) {\r
- SQInteger oldsize = exp->_nallocated;\r
- exp->_nallocated *= 2;\r
- exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode));\r
- }\r
- exp->_nodes[exp->_nsize++] = n;\r
- return (SQInteger)exp->_nsize - 1;\r
-}\r
-\r
-static void sqstd_rex_error(SQRex *exp,const SQChar *error)\r
-{\r
- if(exp->_error) *exp->_error = error;\r
- longjmp(*((jmp_buf*)exp->_jmpbuf),-1);\r
-}\r
-\r
-static void sqstd_rex_expect(SQRex *exp, SQInteger n){\r
- if((*exp->_p) != n) \r
- sqstd_rex_error(exp, _SC("expected paren"));\r
- exp->_p++;\r
-}\r
-\r
-static SQBool sqstd_rex_ischar(SQChar c)\r
-{\r
- switch(c) {\r
- case SQREX_SYMBOL_BRANCH:case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE:\r
- case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE:case SQREX_SYMBOL_GREEDY_ONE_OR_MORE:\r
- case SQREX_SYMBOL_BEGINNING_OF_STRING:case SQREX_SYMBOL_END_OF_STRING:\r
- case SQREX_SYMBOL_ANY_CHAR:case SQREX_SYMBOL_ESCAPE_CHAR:case '(':case ')':case '[':case '{': case '}':\r
- return SQFalse;\r
- }\r
- return SQTrue;\r
-}\r
-\r
-static SQChar sqstd_rex_escapechar(SQRex *exp)\r
-{\r
- if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){\r
- exp->_p++;\r
- switch(*exp->_p) {\r
- case 'v': exp->_p++; return '\v';\r
- case 'n': exp->_p++; return '\n';\r
- case 't': exp->_p++; return '\t';\r
- case 'r': exp->_p++; return '\r';\r
- case 'f': exp->_p++; return '\f';\r
- default: return (*exp->_p++);\r
- }\r
- } else if(!sqstd_rex_ischar(*exp->_p)) sqstd_rex_error(exp,_SC("letter expected"));\r
- return (*exp->_p++);\r
-}\r
-\r
-static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid)\r
-{\r
- SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS);\r
- exp->_nodes[n].left = classid;\r
- return n;\r
-}\r
-\r
-static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass)\r
-{\r
- if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) {\r
- exp->_p++;\r
- switch(*exp->_p) {\r
- case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n');\r
- case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t');\r
- case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r');\r
- case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f');\r
- case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v');\r
- case 'a': case 'A': case 'w': case 'W': case 's': case 'S': \r
- case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': \r
- case 'p': case 'P': case 'l': case 'u': \r
- {\r
- SQChar t = *exp->_p;\r
- exp->_p++; \r
- return sqstd_rex_charclass(exp,t);\r
- }\r
- case 'b': \r
- case 'B':\r
- if(!isclass) {\r
- SQInteger node = sqstd_rex_newnode(exp,OP_WB);\r
- exp->_nodes[node].left = *exp->_p;\r
- exp->_p++; \r
- return node;\r
- } //else default\r
- default: return sqstd_rex_newnode(exp,(*exp->_p++));\r
- }\r
- }\r
- else if(!sqstd_rex_ischar(*exp->_p)) {\r
- \r
- sqstd_rex_error(exp,_SC("letter expected"));\r
- }\r
- return sqstd_rex_newnode(exp,*exp->_p++);\r
-}\r
-static SQInteger sqstd_rex_class(SQRex *exp)\r
-{\r
- SQInteger ret = -1;\r
- SQInteger first = -1,chain;\r
- if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){\r
- ret = sqstd_rex_newnode(exp,OP_NCLASS);\r
- exp->_p++;\r
- }else ret = sqstd_rex_newnode(exp,OP_CLASS);\r
- \r
- if(*exp->_p == ']' || *exp->_p == '-'){\r
- first = *exp->_p;\r
- exp->_p++;\r
- }\r
- chain = ret;\r
- while(*exp->_p != ']' && exp->_p != exp->_eol) {\r
- if(*exp->_p == '-' && first != -1){ \r
- SQInteger r;\r
- if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range"));\r
- r = sqstd_rex_newnode(exp,OP_RANGE);\r
- if(first>*exp->_p) sqstd_rex_error(exp,_SC("invalid range"));\r
- if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC("cannot use character classes in ranges"));\r
- exp->_nodes[r].left = exp->_nodes[first].type;\r
- exp->_nodes[r].right = sqstd_rex_escapechar(exp);\r
- exp->_nodes[chain].next = r;\r
- chain = r;\r
- first = -1;\r
- }\r
- else{\r
- if(first!=-1){\r
- SQInteger c = first;\r
- exp->_nodes[chain].next = c;\r
- chain = c;\r
- first = sqstd_rex_charnode(exp,SQTrue);\r
- }\r
- else{\r
- first = sqstd_rex_charnode(exp,SQTrue);\r
- }\r
- }\r
- }\r
- if(first!=-1){\r
- SQInteger c = first;\r
- exp->_nodes[chain].next = c;\r
- chain = c;\r
- first = -1;\r
- }\r
- /* hack? */\r
- exp->_nodes[ret].left = exp->_nodes[ret].next;\r
- exp->_nodes[ret].next = -1;\r
- return ret;\r
-}\r
-\r
-static SQInteger sqstd_rex_parsenumber(SQRex *exp)\r
-{\r
- SQInteger ret = *exp->_p-'0';\r
- SQInteger positions = 10;\r
- exp->_p++;\r
- while(isdigit(*exp->_p)) {\r
- ret = ret*10+(*exp->_p++-'0');\r
- if(positions==1000000000) sqstd_rex_error(exp,_SC("overflow in numeric constant"));\r
- positions *= 10;\r
- };\r
- return ret;\r
-}\r
-\r
-static SQInteger sqstd_rex_element(SQRex *exp)\r
-{\r
- SQInteger ret;\r
- switch(*exp->_p)\r
- {\r
- case '(': {\r
- SQInteger expr;\r
- exp->_p++;\r
- \r
- \r
- if(*exp->_p =='?') {\r
- exp->_p++;\r
- sqstd_rex_expect(exp,':');\r
- expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR);\r
- }\r
- else\r
- expr = sqstd_rex_newnode(exp,OP_EXPR);\r
- exp->_nodes[expr].left = sqstd_rex_list(exp);\r
- ret = expr;\r
- sqstd_rex_expect(exp,')');\r
- }\r
- break;\r
- case '[':\r
- exp->_p++;\r
- ret = sqstd_rex_class(exp);\r
- sqstd_rex_expect(exp,']');\r
- break;\r
- case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break;\r
- case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break;\r
- default:\r
- ret = sqstd_rex_charnode(exp,SQFalse);\r
- break;\r
- }\r
- /* scope block */\r
- {\r
- SQInteger op;\r
- unsigned short p0 = 0, p1 = 0;\r
- switch(*exp->_p){\r
- case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; goto __end;\r
- case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; goto __end;\r
- case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; goto __end;\r
- case '{':{\r
- exp->_p++;\r
- if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC("number expected"));\r
- p0 = sqstd_rex_parsenumber(exp);\r
- switch(*exp->_p) {\r
- case '}':\r
- p1 = p0; exp->_p++;\r
- goto __end;\r
- case ',':\r
- exp->_p++;\r
- p1 = 0xFFFF;\r
- if(isdigit(*exp->_p)){\r
- p1 = sqstd_rex_parsenumber(exp);\r
- }\r
- sqstd_rex_expect(exp,'}');\r
- goto __end;\r
- default:\r
- sqstd_rex_error(exp,_SC(", or } expected"));\r
- }\r
- }\r
- __end: {\r
- SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY);\r
- op = OP_GREEDY;\r
- exp->_nodes[nnode].left = ret;\r
- exp->_nodes[nnode].right = ((p0)<<16)|p1;\r
- ret = nnode;\r
- }\r
- }\r
- }\r
- if(*exp->_p != SQREX_SYMBOL_BRANCH && *exp->_p != ')' && *exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE && *exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE && *exp->_p != '\0')\r
- exp->_nodes[ret].next = sqstd_rex_element(exp);\r
- return ret;\r
-}\r
-\r
-static SQInteger sqstd_rex_list(SQRex *exp)\r
-{\r
- SQInteger ret=-1,e;\r
- if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) {\r
- exp->_p++;\r
- ret = sqstd_rex_newnode(exp,OP_BOL);\r
- }\r
- e = sqstd_rex_element(exp);\r
- if(ret != -1) {\r
- exp->_nodes[ret].next = e;\r
- }\r
- else ret = e;\r
-\r
- if(*exp->_p == SQREX_SYMBOL_BRANCH) {\r
- SQInteger temp;\r
- exp->_p++;\r
- temp = sqstd_rex_newnode(exp,OP_OR);\r
- exp->_nodes[temp].left = ret;\r
- exp->_nodes[temp].right = sqstd_rex_list(exp);\r
- ret = temp;\r
- }\r
- return ret;\r
-}\r
-\r
-static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c)\r
-{\r
- switch(cclass) {\r
- case 'a': return isalpha(c)?SQTrue:SQFalse;\r
- case 'A': return !isalpha(c)?SQTrue:SQFalse;\r
- case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse;\r
- case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse;\r
- case 's': return isspace(c)?SQTrue:SQFalse;\r
- case 'S': return !isspace(c)?SQTrue:SQFalse;\r
- case 'd': return isdigit(c)?SQTrue:SQFalse;\r
- case 'D': return !isdigit(c)?SQTrue:SQFalse;\r
- case 'x': return isxdigit(c)?SQTrue:SQFalse;\r
- case 'X': return !isxdigit(c)?SQTrue:SQFalse;\r
- case 'c': return iscntrl(c)?SQTrue:SQFalse;\r
- case 'C': return !iscntrl(c)?SQTrue:SQFalse;\r
- case 'p': return ispunct(c)?SQTrue:SQFalse;\r
- case 'P': return !ispunct(c)?SQTrue:SQFalse;\r
- case 'l': return islower(c)?SQTrue:SQFalse;\r
- case 'u': return isupper(c)?SQTrue:SQFalse;\r
- }\r
- return SQFalse; /*cannot happen*/\r
-}\r
-\r
-static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQChar c)\r
-{\r
- do {\r
- switch(node->type) {\r
- case OP_RANGE:\r
- if(c >= node->left && c <= node->right) return SQTrue;\r
- break;\r
- case OP_CCLASS:\r
- if(sqstd_rex_matchcclass(node->left,c)) return SQTrue;\r
- break;\r
- default:\r
- if(c == node->type)return SQTrue;\r
- }\r
- } while((node->next != -1) && (node = &exp->_nodes[node->next]));\r
- return SQFalse;\r
-}\r
-\r
-static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str)\r
-{\r
- SQRexNodeType type = node->type;\r
- switch(type) {\r
- case OP_GREEDY: {\r
- SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;\r
- const SQChar *s=str, *good = str;\r
- while((nmaches == 0xFFFF || nmaches < p1) \r
- && (s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s))) {\r
- good=s;\r
- nmaches++;\r
- if(s >= exp->_eol)\r
- break;\r
- }\r
- if(p0 == p1 && p0 == nmaches) return good;\r
- else if(nmaches >= p0 && p1 == 0xFFFF) return good;\r
- else if(nmaches >= p0 && nmaches <= p1) return good;\r
- return NULL;\r
- }\r
- case OP_OR: {\r
- const SQChar *asd = str;\r
- SQRexNode *temp=&exp->_nodes[node->left];\r
- while(asd = sqstd_rex_matchnode(exp,temp,asd)) {\r
- if(temp->next != -1)\r
- temp = &exp->_nodes[temp->next];\r
- else\r
- return asd;\r
- }\r
- asd = str;\r
- temp = &exp->_nodes[node->right];\r
- while(asd = sqstd_rex_matchnode(exp,temp,asd)) {\r
- if(temp->next != -1)\r
- temp = &exp->_nodes[temp->next];\r
- else\r
- return asd;\r
- }\r
- return NULL;\r
- break;\r
- }\r
- case OP_EXPR:\r
- case OP_NOCAPEXPR:{\r
- SQRexNode *n = &exp->_nodes[node->left];\r
- const SQChar *cur = str;\r
- SQInteger capture = -1;\r
- if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {\r
- capture = exp->_currsubexp;\r
- exp->_matches[capture].begin = cur;\r
- exp->_currsubexp++;\r
- }\r
-\r
- do {\r
- if(!(cur = sqstd_rex_matchnode(exp,n,cur))) {\r
- if(capture != -1){\r
- exp->_matches[capture].begin = 0;\r
- exp->_matches[capture].len = 0;\r
- }\r
- return NULL;\r
- }\r
- } while((n->next != -1) && (n = &exp->_nodes[n->next]));\r
-\r
- if(capture != -1) \r
- exp->_matches[capture].len = cur - exp->_matches[capture].begin;\r
- return cur;\r
- } \r
- case OP_WB:\r
- if(str == exp->_bol && !isspace(*str)\r
- || (str == exp->_eol && !isspace(*(str-1)))\r
- || (!isspace(*str) && isspace(*(str+1)))\r
- || (isspace(*str) && !isspace(*(str+1))) ) {\r
- return (node->left == 'b')?str:NULL;\r
- }\r
- return (node->left == 'b')?NULL:str;\r
- case OP_BOL:\r
- if(str == exp->_bol) return str;\r
- return NULL;\r
- case OP_EOL:\r
- if(str == exp->_eol) return str;\r
- return NULL;\r
- case OP_DOT:\r
- *str++;\r
- return str;\r
- case OP_NCLASS:\r
- case OP_CLASS:\r
- if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) {\r
- *str++;\r
- return str;\r
- }\r
- return NULL;\r
- case OP_CCLASS:\r
- if(sqstd_rex_matchcclass(node->left,*str)) {\r
- *str++;\r
- return str;\r
- }\r
- return NULL;\r
- default: /* char */\r
- if(*str != node->type) return NULL;\r
- *str++;\r
- return str;\r
- }\r
- return NULL;\r
-}\r
-\r
-/* public api */\r
-SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error)\r
-{\r
- SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex));\r
- exp->_p = pattern;\r
- exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar);\r
- exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode));\r
- exp->_nsize = 0;\r
- exp->_matches = 0;\r
- exp->_nsubexpr = 0;\r
- exp->_first = sqstd_rex_newnode(exp,OP_EXPR);\r
- exp->_error = error;\r
- exp->_jmpbuf = sq_malloc(sizeof(jmp_buf));\r
- if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {\r
- exp->_nodes[exp->_first].left=sqstd_rex_list(exp);\r
- if(*exp->_p!='\0')\r
- sqstd_rex_error(exp,_SC("unexpected character"));\r
-#ifdef _DEBUG\r
- {\r
- SQInteger nsize,i;\r
- SQRexNode *t;\r
- nsize = exp->_nsize;\r
- t = &exp->_nodes[0];\r
- scprintf(_SC("\n"));\r
- for(i = 0;i < nsize; i++) {\r
- if(exp->_nodes[i].type>MAX_CHAR)\r
- scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);\r
- else\r
- scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);\r
- scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);\r
- }\r
- scprintf(_SC("\n"));\r
- }\r
-#endif\r
- exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch));\r
- memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch));\r
- }\r
- else{\r
- sqstd_rex_free(exp);\r
- return NULL;\r
- }\r
- return exp;\r
-}\r
-\r
-void sqstd_rex_free(SQRex *exp)\r
-{\r
- if(exp) {\r
- if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode));\r
- if(exp->_jmpbuf) sq_free(exp->_jmpbuf,sizeof(jmp_buf));\r
- if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch));\r
- sq_free(exp,sizeof(SQRex));\r
- }\r
-}\r
-\r
-SQBool sqstd_rex_match(SQRex* exp,const SQChar* text)\r
-{\r
- const SQChar* res = NULL;\r
- exp->_bol = text;\r
- exp->_eol = text + scstrlen(text);\r
- exp->_currsubexp = 0;\r
- res = sqstd_rex_matchnode(exp,exp->_nodes,text);\r
- if(res == NULL || res != exp->_eol)\r
- return SQFalse;\r
- return SQTrue;\r
-}\r
-\r
-SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end)\r
-{\r
- const SQChar *cur = NULL;\r
- SQInteger node = exp->_first;\r
- if(text_begin >= text_end) return SQFalse;\r
- exp->_bol = text_begin;\r
- exp->_eol = text_end;\r
- do {\r
- cur = text_begin;\r
- while(node != -1) {\r
- exp->_currsubexp = 0;\r
- cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur);\r
- if(!cur)\r
- break;\r
- node = exp->_nodes[node].next;\r
- }\r
- *text_begin++;\r
- } while(cur == NULL && text_begin != text_end);\r
-\r
- if(cur == NULL)\r
- return SQFalse;\r
-\r
- --text_begin;\r
-\r
- if(out_begin) *out_begin = text_begin;\r
- if(out_end) *out_end = cur;\r
- return SQTrue;\r
-}\r
-\r
-SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end)\r
-{\r
- return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);\r
-}\r
-\r
-SQInteger sqstd_rex_getsubexpcount(SQRex* exp)\r
-{\r
- return exp->_nsubexpr;\r
-}\r
-\r
-SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp)\r
-{\r
- if( n<0 || n >= exp->_nsubexpr) return SQFalse;\r
- *subexp = exp->_matches[n];\r
- return SQTrue;\r
-}\r
-\r
--- /dev/null
+/* see copyright notice in squirrel.h */\r
+#include <squirrel.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <setjmp.h>\r
+#include "sqstdstring.h"\r
+\r
+#ifdef _UINCODE\r
+#define scisprint iswprint\r
+#else\r
+#define scisprint isprint\r
+#endif\r
+\r
+#ifdef _DEBUG\r
+#include <stdio.h>\r
+\r
+static const SQChar *g_nnames[] =\r
+{\r
+ _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"),\r
+ _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"),\r
+ _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),\r
+ _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")\r
+};\r
+\r
+#endif\r
+\r
+#define OP_GREEDY MAX_CHAR+1 // * + ? {n}\r
+#define OP_OR MAX_CHAR+2\r
+#define OP_EXPR MAX_CHAR+3 //parentesis ()\r
+#define OP_NOCAPEXPR MAX_CHAR+4 //parentesis (?:)\r
+#define OP_DOT MAX_CHAR+5\r
+#define OP_CLASS MAX_CHAR+6\r
+#define OP_CCLASS MAX_CHAR+7\r
+#define OP_NCLASS MAX_CHAR+8 //negates class the [^\r
+#define OP_RANGE MAX_CHAR+9\r
+#define OP_CHAR MAX_CHAR+10\r
+#define OP_EOL MAX_CHAR+11\r
+#define OP_BOL MAX_CHAR+12\r
+#define OP_WB MAX_CHAR+13\r
+\r
+#define SQREX_SYMBOL_ANY_CHAR '.'\r
+#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE '+'\r
+#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE '*'\r
+#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE '?'\r
+#define SQREX_SYMBOL_BRANCH '|'\r
+#define SQREX_SYMBOL_END_OF_STRING '$'\r
+#define SQREX_SYMBOL_BEGINNING_OF_STRING '^'\r
+#define SQREX_SYMBOL_ESCAPE_CHAR '\\'\r
+\r
+\r
+typedef int SQRexNodeType;\r
+\r
+typedef struct tagSQRexNode{\r
+ SQRexNodeType type;\r
+ SQInteger left;\r
+ SQInteger right;\r
+ SQInteger next;\r
+}SQRexNode;\r
+\r
+struct SQRex{\r
+ const SQChar *_eol;\r
+ const SQChar *_bol;\r
+ const SQChar *_p;\r
+ SQInteger _first;\r
+ SQInteger _op;\r
+ SQRexNode *_nodes;\r
+ SQInteger _nallocated;\r
+ SQInteger _nsize;\r
+ SQInteger _nsubexpr;\r
+ SQRexMatch *_matches;\r
+ SQInteger _currsubexp;\r
+ void *_jmpbuf;\r
+ const SQChar **_error;\r
+};\r
+\r
+static SQInteger sqstd_rex_list(SQRex *exp);\r
+\r
+static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type)\r
+{\r
+ SQRexNode n;\r
+ n.type = type;\r
+ n.next = n.right = n.left = -1;\r
+ if(type == OP_EXPR)\r
+ n.right = exp->_nsubexpr++;\r
+ if(exp->_nallocated < (exp->_nsize + 1)) {\r
+ SQInteger oldsize = exp->_nallocated;\r
+ exp->_nallocated *= 2;\r
+ exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode));\r
+ }\r
+ exp->_nodes[exp->_nsize++] = n;\r
+ return (SQInteger)exp->_nsize - 1;\r
+}\r
+\r
+static void sqstd_rex_error(SQRex *exp,const SQChar *error)\r
+{\r
+ if(exp->_error) *exp->_error = error;\r
+ longjmp(*((jmp_buf*)exp->_jmpbuf),-1);\r
+}\r
+\r
+static void sqstd_rex_expect(SQRex *exp, SQInteger n){\r
+ if((*exp->_p) != n) \r
+ sqstd_rex_error(exp, _SC("expected paren"));\r
+ exp->_p++;\r
+}\r
+\r
+/*static SQBool sqstd_rex_ischar(SQChar c)\r
+{\r
+ switch(c) {\r
+ case SQREX_SYMBOL_BRANCH:case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE:\r
+ case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE:case SQREX_SYMBOL_GREEDY_ONE_OR_MORE:\r
+ case SQREX_SYMBOL_BEGINNING_OF_STRING:case SQREX_SYMBOL_END_OF_STRING:\r
+ case SQREX_SYMBOL_ANY_CHAR:case SQREX_SYMBOL_ESCAPE_CHAR:case '(':case ')':case '[':case '{': case '}':\r
+ return SQFalse;\r
+ }\r
+ return SQTrue;\r
+}*/\r
+\r
+static SQChar sqstd_rex_escapechar(SQRex *exp)\r
+{\r
+ if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){\r
+ exp->_p++;\r
+ switch(*exp->_p) {\r
+ case 'v': exp->_p++; return '\v';\r
+ case 'n': exp->_p++; return '\n';\r
+ case 't': exp->_p++; return '\t';\r
+ case 'r': exp->_p++; return '\r';\r
+ case 'f': exp->_p++; return '\f';\r
+ default: return (*exp->_p++);\r
+ }\r
+ } else if(!scisprint(*exp->_p)) sqstd_rex_error(exp,_SC("letter expected"));\r
+ return (*exp->_p++);\r
+}\r
+\r
+static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid)\r
+{\r
+ SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS);\r
+ exp->_nodes[n].left = classid;\r
+ return n;\r
+}\r
+\r
+static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass)\r
+{\r
+ if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) {\r
+ exp->_p++;\r
+ switch(*exp->_p) {\r
+ case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n');\r
+ case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t');\r
+ case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r');\r
+ case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f');\r
+ case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v');\r
+ case 'a': case 'A': case 'w': case 'W': case 's': case 'S': \r
+ case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': \r
+ case 'p': case 'P': case 'l': case 'u': \r
+ {\r
+ SQChar t = *exp->_p;\r
+ exp->_p++; \r
+ return sqstd_rex_charclass(exp,t);\r
+ }\r
+ case 'b': \r
+ case 'B':\r
+ if(!isclass) {\r
+ SQInteger node = sqstd_rex_newnode(exp,OP_WB);\r
+ exp->_nodes[node].left = *exp->_p;\r
+ exp->_p++; \r
+ return node;\r
+ } //else default\r
+ default: return sqstd_rex_newnode(exp,(*exp->_p++));\r
+ }\r
+ }\r
+ else if(!scisprint(*exp->_p)) {\r
+ \r
+ sqstd_rex_error(exp,_SC("letter expected"));\r
+ }\r
+ return sqstd_rex_newnode(exp,*exp->_p++);\r
+}\r
+static SQInteger sqstd_rex_class(SQRex *exp)\r
+{\r
+ SQInteger ret = -1;\r
+ SQInteger first = -1,chain;\r
+ if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){\r
+ ret = sqstd_rex_newnode(exp,OP_NCLASS);\r
+ exp->_p++;\r
+ }else ret = sqstd_rex_newnode(exp,OP_CLASS);\r
+ \r
+ if(*exp->_p == ']') sqstd_rex_error(exp,_SC("empty class"));\r
+ chain = ret;\r
+ while(*exp->_p != ']' && exp->_p != exp->_eol) {\r
+ if(*exp->_p == '-' && first != -1){ \r
+ SQInteger r;\r
+ if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range"));\r
+ r = sqstd_rex_newnode(exp,OP_RANGE);\r
+ if(first>*exp->_p) sqstd_rex_error(exp,_SC("invalid range"));\r
+ if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC("cannot use character classes in ranges"));\r
+ exp->_nodes[r].left = exp->_nodes[first].type;\r
+ exp->_nodes[r].right = sqstd_rex_escapechar(exp);\r
+ exp->_nodes[chain].next = r;\r
+ chain = r;\r
+ first = -1;\r
+ }\r
+ else{\r
+ if(first!=-1){\r
+ SQInteger c = first;\r
+ exp->_nodes[chain].next = c;\r
+ chain = c;\r
+ first = sqstd_rex_charnode(exp,SQTrue);\r
+ }\r
+ else{\r
+ first = sqstd_rex_charnode(exp,SQTrue);\r
+ }\r
+ }\r
+ }\r
+ if(first!=-1){\r
+ SQInteger c = first;\r
+ exp->_nodes[chain].next = c;\r
+ chain = c;\r
+ first = -1;\r
+ }\r
+ /* hack? */\r
+ exp->_nodes[ret].left = exp->_nodes[ret].next;\r
+ exp->_nodes[ret].next = -1;\r
+ return ret;\r
+}\r
+\r
+static SQInteger sqstd_rex_parsenumber(SQRex *exp)\r
+{\r
+ SQInteger ret = *exp->_p-'0';\r
+ SQInteger positions = 10;\r
+ exp->_p++;\r
+ while(isdigit(*exp->_p)) {\r
+ ret = ret*10+(*exp->_p++-'0');\r
+ if(positions==1000000000) sqstd_rex_error(exp,_SC("overflow in numeric constant"));\r
+ positions *= 10;\r
+ };\r
+ return ret;\r
+}\r
+\r
+static SQInteger sqstd_rex_element(SQRex *exp)\r
+{\r
+ SQInteger ret;\r
+ switch(*exp->_p)\r
+ {\r
+ case '(': {\r
+ SQInteger expr;\r
+ exp->_p++;\r
+ \r
+ \r
+ if(*exp->_p =='?') {\r
+ exp->_p++;\r
+ sqstd_rex_expect(exp,':');\r
+ expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR);\r
+ }\r
+ else\r
+ expr = sqstd_rex_newnode(exp,OP_EXPR);\r
+ exp->_nodes[expr].left = sqstd_rex_list(exp);\r
+ ret = expr;\r
+ sqstd_rex_expect(exp,')');\r
+ }\r
+ break;\r
+ case '[':\r
+ exp->_p++;\r
+ ret = sqstd_rex_class(exp);\r
+ sqstd_rex_expect(exp,']');\r
+ break;\r
+ case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break;\r
+ case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break;\r
+ default:\r
+ ret = sqstd_rex_charnode(exp,SQFalse);\r
+ break;\r
+ }\r
+ /* scope block */\r
+ {\r
+ SQInteger op;\r
+ unsigned short p0 = 0, p1 = 0;\r
+ switch(*exp->_p){\r
+ case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; goto __end;\r
+ case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; goto __end;\r
+ case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; goto __end;\r
+ case '{':{\r
+ exp->_p++;\r
+ if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC("number expected"));\r
+ p0 = (unsigned short)sqstd_rex_parsenumber(exp);\r
+ switch(*exp->_p) {\r
+ case '}':\r
+ p1 = p0; exp->_p++;\r
+ goto __end;\r
+ case ',':\r
+ exp->_p++;\r
+ p1 = 0xFFFF;\r
+ if(isdigit(*exp->_p)){\r
+ p1 = (unsigned short)sqstd_rex_parsenumber(exp);\r
+ }\r
+ sqstd_rex_expect(exp,'}');\r
+ goto __end;\r
+ default:\r
+ sqstd_rex_error(exp,_SC(", or } expected"));\r
+ }\r
+ }\r
+ __end: {\r
+ SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY);\r
+ op = OP_GREEDY;\r
+ exp->_nodes[nnode].left = ret;\r
+ exp->_nodes[nnode].right = ((p0)<<16)|p1;\r
+ ret = nnode;\r
+ }\r
+ }\r
+ }\r
+ if(*exp->_p != SQREX_SYMBOL_BRANCH && *exp->_p != ')' && *exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE && *exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE && *exp->_p != '\0')\r
+ exp->_nodes[ret].next = sqstd_rex_element(exp);\r
+ return ret;\r
+}\r
+\r
+static SQInteger sqstd_rex_list(SQRex *exp)\r
+{\r
+ SQInteger ret=-1,e;\r
+ if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) {\r
+ exp->_p++;\r
+ ret = sqstd_rex_newnode(exp,OP_BOL);\r
+ }\r
+ e = sqstd_rex_element(exp);\r
+ if(ret != -1) {\r
+ exp->_nodes[ret].next = e;\r
+ }\r
+ else ret = e;\r
+\r
+ if(*exp->_p == SQREX_SYMBOL_BRANCH) {\r
+ SQInteger temp;\r
+ exp->_p++;\r
+ temp = sqstd_rex_newnode(exp,OP_OR);\r
+ exp->_nodes[temp].left = ret;\r
+ exp->_nodes[temp].right = sqstd_rex_list(exp);\r
+ ret = temp;\r
+ }\r
+ return ret;\r
+}\r
+\r
+static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c)\r
+{\r
+ switch(cclass) {\r
+ case 'a': return isalpha(c)?SQTrue:SQFalse;\r
+ case 'A': return !isalpha(c)?SQTrue:SQFalse;\r
+ case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse;\r
+ case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse;\r
+ case 's': return isspace(c)?SQTrue:SQFalse;\r
+ case 'S': return !isspace(c)?SQTrue:SQFalse;\r
+ case 'd': return isdigit(c)?SQTrue:SQFalse;\r
+ case 'D': return !isdigit(c)?SQTrue:SQFalse;\r
+ case 'x': return isxdigit(c)?SQTrue:SQFalse;\r
+ case 'X': return !isxdigit(c)?SQTrue:SQFalse;\r
+ case 'c': return iscntrl(c)?SQTrue:SQFalse;\r
+ case 'C': return !iscntrl(c)?SQTrue:SQFalse;\r
+ case 'p': return ispunct(c)?SQTrue:SQFalse;\r
+ case 'P': return !ispunct(c)?SQTrue:SQFalse;\r
+ case 'l': return islower(c)?SQTrue:SQFalse;\r
+ case 'u': return isupper(c)?SQTrue:SQFalse;\r
+ }\r
+ return SQFalse; /*cannot happen*/\r
+}\r
+\r
+static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQChar c)\r
+{\r
+ do {\r
+ switch(node->type) {\r
+ case OP_RANGE:\r
+ if(c >= node->left && c <= node->right) return SQTrue;\r
+ break;\r
+ case OP_CCLASS:\r
+ if(sqstd_rex_matchcclass(node->left,c)) return SQTrue;\r
+ break;\r
+ default:\r
+ if(c == node->type)return SQTrue;\r
+ }\r
+ } while((node->next != -1) && (node = &exp->_nodes[node->next]));\r
+ return SQFalse;\r
+}\r
+\r
+static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str,SQRexNode *next)\r
+{\r
+ \r
+ SQRexNodeType type = node->type;\r
+ switch(type) {\r
+ case OP_GREEDY: {\r
+ //SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;\r
+ SQRexNode *greedystop = NULL;\r
+ SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;\r
+ const SQChar *s=str, *good = str;\r
+\r
+ if(node->next != -1) {\r
+ greedystop = &exp->_nodes[node->next];\r
+ }\r
+ else {\r
+ greedystop = next;\r
+ }\r
+\r
+ while((nmaches == 0xFFFF || nmaches < p1)) {\r
+\r
+ const SQChar *stop;\r
+ if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))\r
+ break;\r
+ nmaches++;\r
+ good=s;\r
+ if(greedystop) {\r
+ //checks that 0 matches satisfy the expression(if so skips)\r
+ //if not would always stop(for instance if is a '?')\r
+ if(greedystop->type != OP_GREEDY ||\r
+ (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))\r
+ {\r
+ SQRexNode *gnext = NULL;\r
+ if(greedystop->next != -1) {\r
+ gnext = &exp->_nodes[greedystop->next];\r
+ }else if(next && next->next != -1){\r
+ gnext = &exp->_nodes[next->next];\r
+ }\r
+ stop = sqstd_rex_matchnode(exp,greedystop,s,gnext);\r
+ if(stop) {\r
+ //if satisfied stop it\r
+ if(p0 == p1 && p0 == nmaches) break;\r
+ else if(nmaches >= p0 && p1 == 0xFFFF) break;\r
+ else if(nmaches >= p0 && nmaches <= p1) break;\r
+ }\r
+ }\r
+ }\r
+ \r
+ if(s >= exp->_eol)\r
+ break;\r
+ }\r
+ if(p0 == p1 && p0 == nmaches) return good;\r
+ else if(nmaches >= p0 && p1 == 0xFFFF) return good;\r
+ else if(nmaches >= p0 && nmaches <= p1) return good;\r
+ return NULL;\r
+ }\r
+ case OP_OR: {\r
+ const SQChar *asd = str;\r
+ SQRexNode *temp=&exp->_nodes[node->left];\r
+ while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {\r
+ if(temp->next != -1)\r
+ temp = &exp->_nodes[temp->next];\r
+ else\r
+ return asd;\r
+ }\r
+ asd = str;\r
+ temp = &exp->_nodes[node->right];\r
+ while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {\r
+ if(temp->next != -1)\r
+ temp = &exp->_nodes[temp->next];\r
+ else\r
+ return asd;\r
+ }\r
+ return NULL;\r
+ break;\r
+ }\r
+ case OP_EXPR:\r
+ case OP_NOCAPEXPR:{\r
+ SQRexNode *n = &exp->_nodes[node->left];\r
+ const SQChar *cur = str;\r
+ SQInteger capture = -1;\r
+ if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {\r
+ capture = exp->_currsubexp;\r
+ exp->_matches[capture].begin = cur;\r
+ exp->_currsubexp++;\r
+ }\r
+ \r
+ do {\r
+ SQRexNode *subnext = NULL;\r
+ if(n->next != -1) {\r
+ subnext = &exp->_nodes[n->next];\r
+ }else {\r
+ subnext = next;\r
+ }\r
+ if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) {\r
+ if(capture != -1){\r
+ exp->_matches[capture].begin = 0;\r
+ exp->_matches[capture].len = 0;\r
+ }\r
+ return NULL;\r
+ }\r
+ } while((n->next != -1) && (n = &exp->_nodes[n->next]));\r
+\r
+ if(capture != -1) \r
+ exp->_matches[capture].len = cur - exp->_matches[capture].begin;\r
+ return cur;\r
+ } \r
+ case OP_WB:\r
+ if(str == exp->_bol && !isspace(*str)\r
+ || (str == exp->_eol && !isspace(*(str-1)))\r
+ || (!isspace(*str) && isspace(*(str+1)))\r
+ || (isspace(*str) && !isspace(*(str+1))) ) {\r
+ return (node->left == 'b')?str:NULL;\r
+ }\r
+ return (node->left == 'b')?NULL:str;\r
+ case OP_BOL:\r
+ if(str == exp->_bol) return str;\r
+ return NULL;\r
+ case OP_EOL:\r
+ if(str == exp->_eol) return str;\r
+ return NULL;\r
+ case OP_DOT:{\r
+ *str++;\r
+ }\r
+ return str;\r
+ case OP_NCLASS:\r
+ case OP_CLASS:\r
+ if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) {\r
+ *str++;\r
+ return str;\r
+ }\r
+ return NULL;\r
+ case OP_CCLASS:\r
+ if(sqstd_rex_matchcclass(node->left,*str)) {\r
+ *str++;\r
+ return str;\r
+ }\r
+ return NULL;\r
+ default: /* char */\r
+ if(*str != node->type) return NULL;\r
+ *str++;\r
+ return str;\r
+ }\r
+ return NULL;\r
+}\r
+\r
+/* public api */\r
+SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error)\r
+{\r
+ SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex));\r
+ exp->_eol = exp->_bol = NULL;\r
+ exp->_p = pattern;\r
+ exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar);\r
+ exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode));\r
+ exp->_nsize = 0;\r
+ exp->_matches = 0;\r
+ exp->_nsubexpr = 0;\r
+ exp->_first = sqstd_rex_newnode(exp,OP_EXPR);\r
+ exp->_error = error;\r
+ exp->_jmpbuf = sq_malloc(sizeof(jmp_buf));\r
+ if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {\r
+ exp->_nodes[exp->_first].left=sqstd_rex_list(exp);\r
+ if(*exp->_p!='\0')\r
+ sqstd_rex_error(exp,_SC("unexpected character"));\r
+#ifdef _DEBUG\r
+ {\r
+ SQInteger nsize,i;\r
+ SQRexNode *t;\r
+ nsize = exp->_nsize;\r
+ t = &exp->_nodes[0];\r
+ scprintf(_SC("\n"));\r
+ for(i = 0;i < nsize; i++) {\r
+ if(exp->_nodes[i].type>MAX_CHAR)\r
+ scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);\r
+ else\r
+ scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);\r
+ scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);\r
+ }\r
+ scprintf(_SC("\n"));\r
+ }\r
+#endif\r
+ exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch));\r
+ memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch));\r
+ }\r
+ else{\r
+ sqstd_rex_free(exp);\r
+ return NULL;\r
+ }\r
+ return exp;\r
+}\r
+\r
+void sqstd_rex_free(SQRex *exp)\r
+{\r
+ if(exp) {\r
+ if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode));\r
+ if(exp->_jmpbuf) sq_free(exp->_jmpbuf,sizeof(jmp_buf));\r
+ if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch));\r
+ sq_free(exp,sizeof(SQRex));\r
+ }\r
+}\r
+\r
+SQBool sqstd_rex_match(SQRex* exp,const SQChar* text)\r
+{\r
+ const SQChar* res = NULL;\r
+ exp->_bol = text;\r
+ exp->_eol = text + scstrlen(text);\r
+ exp->_currsubexp = 0;\r
+ res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL);\r
+ if(res == NULL || res != exp->_eol)\r
+ return SQFalse;\r
+ return SQTrue;\r
+}\r
+\r
+SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end)\r
+{\r
+ const SQChar *cur = NULL;\r
+ SQInteger node = exp->_first;\r
+ if(text_begin >= text_end) return SQFalse;\r
+ exp->_bol = text_begin;\r
+ exp->_eol = text_end;\r
+ do {\r
+ cur = text_begin;\r
+ while(node != -1) {\r
+ exp->_currsubexp = 0;\r
+ cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL);\r
+ if(!cur)\r
+ break;\r
+ node = exp->_nodes[node].next;\r
+ }\r
+ *text_begin++;\r
+ } while(cur == NULL && text_begin != text_end);\r
+\r
+ if(cur == NULL)\r
+ return SQFalse;\r
+\r
+ --text_begin;\r
+\r
+ if(out_begin) *out_begin = text_begin;\r
+ if(out_end) *out_end = cur;\r
+ return SQTrue;\r
+}\r
+\r
+SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end)\r
+{\r
+ return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);\r
+}\r
+\r
+SQInteger sqstd_rex_getsubexpcount(SQRex* exp)\r
+{\r
+ return exp->_nsubexpr;\r
+}\r
+\r
+SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp)\r
+{\r
+ if( n<0 || n >= exp->_nsubexpr) return SQFalse;\r
+ *subexp = exp->_matches[n];\r
+ return SQTrue;\r
+}\r
+\r
if(!self->IsValid()) \\r
return sq_throwerror(v,_SC("the stream is invalid"));\r
\r
-SQInteger _stream_readstr(HSQUIRRELVM v)\r
-{\r
- SETUP_STREAM(v);\r
- SQInteger type = _SC('a'), size = 0;\r
- sq_getinteger(v, 2, &size);\r
- if(size <= 0) return sq_throwerror(v,_SC("invalid size"));\r
- if(sq_gettop(v) > 2)\r
- sq_getinteger(v, 3, &type);\r
- SQChar *dest = NULL;\r
- switch(type) {\r
- case _SC('a'): {\r
- char *temp;\r
- if(self->Read(sq_getscratchpad(v, size+1), size) != size)\r
- return sq_throwerror(v, _SC("io failure"));\r
-#ifdef _UNICODE\r
- temp = (char*) sq_getscratchpad(v, size + (size * sizeof(SQChar)));\r
- dest = (SQChar*) &temp[size];\r
- size = (SQInteger)mbstowcs(dest, (const char*)temp, size);\r
-#else\r
- temp = (char *) sq_getscratchpad(v, -1);\r
- dest = temp;\r
-#endif\r
- }\r
- break;\r
- case _SC('u'): {\r
- wchar_t *temp;\r
- if(self->Read(sq_getscratchpad(v, (size + 1) * sizeof(wchar_t)),size * sizeof(wchar_t)) != (size * sizeof(wchar_t)))\r
- return sq_throwerror(v, _SC("io failure"));\r
- \r
-#ifdef _UNICODE\r
- temp = (wchar_t*) sq_getscratchpad(v, -1);\r
- dest = (SQChar*) temp;\r
-#else\r
- temp = (wchar_t*) sq_getscratchpad(v,(size * 3) + (size * sizeof(wchar_t)));\r
- dest = (char*) &temp[size];\r
- size = (SQInteger)wcstombs(dest, (const wchar_t*)temp, size);\r
-#endif\r
- }\r
- break;\r
- default:\r
- return sq_throwerror(v, _SC("invalid coding"));\r
- }\r
-\r
- sq_pushstring(v, dest, size);\r
- return 1;\r
-}\r
-\r
SQInteger _stream_readblob(HSQUIRRELVM v)\r
{\r
SETUP_STREAM(v);\r
SQInteger format;\r
sq_getinteger(v, 2, &format);\r
switch(format) {\r
- case 'i': {\r
+ case 'l': {\r
SQInteger i;\r
SAFE_READN(&i, sizeof(i));\r
sq_pushinteger(v, i);\r
}\r
break;\r
+ case 'i': {\r
+ SQInt32 i;\r
+ SAFE_READN(&i, sizeof(i));\r
+ sq_pushinteger(v, i);\r
+ }\r
+ break;\r
case 's': {\r
short s;\r
SAFE_READN(&s, sizeof(short));\r
return 1;\r
}\r
\r
-SQInteger _stream_writestr(HSQUIRRELVM v)\r
-{\r
- SETUP_STREAM(v);\r
- const SQChar *str,*res;\r
- SQInteger trgformat = 'a',len = 0;\r
- sq_getstring(v,2,&str);\r
- len = sq_getsize(v,2);\r
- if(sq_gettop(v)>2)\r
- sq_getinteger(v,3,&trgformat);\r
- switch(trgformat)\r
- {\r
- case 'a':\r
-#ifdef _UNICODE\r
- res = sq_getscratchpad(v,len*3);\r
- len = (SQInteger) wcstombs((char *)res, (const wchar_t*)str, len);\r
-#else\r
- res = str;\r
-#endif\r
- self->Write((void *)res,len);\r
- break;\r
- case 'u':\r
-#ifdef _UNICODE\r
- res = str;\r
-#else\r
- res = sq_getscratchpad(v,len*sizeof(wchar_t));\r
- len = (SQInteger) mbstowcs((wchar_t*)res, str, len);\r
-#endif\r
- self->Write((void *)res,len*sizeof(wchar_t));\r
- break;\r
- default:\r
- return sq_throwerror(v,_SC("wrong encoding"));\r
- }\r
- \r
- return 0;\r
-}\r
-\r
SQInteger _stream_writeblob(HSQUIRRELVM v)\r
{\r
SQUserPointer data;\r
SQFloat tf;\r
sq_getinteger(v, 3, &format);\r
switch(format) {\r
- case 'i': {\r
+ case 'l': {\r
SQInteger i;\r
sq_getinteger(v, 2, &ti);\r
i = ti;\r
self->Write(&i, sizeof(SQInteger));\r
}\r
break;\r
+ case 'i': {\r
+ SQInt32 i;\r
+ sq_getinteger(v, 2, &ti);\r
+ i = (SQInt32)ti;\r
+ self->Write(&i, sizeof(SQInt32));\r
+ }\r
+ break;\r
case 's': {\r
short s;\r
sq_getinteger(v, 2, &ti);\r
- s = ti;\r
+ s = (short)ti;\r
self->Write(&s, sizeof(short));\r
}\r
break;\r
case 'w': {\r
unsigned short w;\r
sq_getinteger(v, 2, &ti);\r
- w = ti;\r
+ w = (unsigned short)ti;\r
self->Write(&w, sizeof(unsigned short));\r
}\r
break;\r
case 'c': {\r
char c;\r
sq_getinteger(v, 2, &ti);\r
- c = ti;\r
+ c = (char)ti;\r
self->Write(&c, sizeof(char));\r
}\r
break;\r
case 'b': {\r
unsigned char b;\r
sq_getinteger(v, 2, &ti);\r
- b = ti;\r
+ b = (unsigned char)ti;\r
self->Write(&b, sizeof(unsigned char));\r
}\r
break;\r
}\r
\r
static SQRegFunction _stream_methods[] = {\r
- _DECL_STREAM_FUNC(readstr,-2,_SC("xnn")),\r
_DECL_STREAM_FUNC(readblob,2,_SC("xn")),\r
_DECL_STREAM_FUNC(readn,2,_SC("xn")),\r
- _DECL_STREAM_FUNC(writestr,-2,_SC("xsn")),\r
_DECL_STREAM_FUNC(writeblob,-2,_SC("xx")),\r
_DECL_STREAM_FUNC(writen,3,_SC("xnn")),\r
_DECL_STREAM_FUNC(seek,-2,_SC("xnn")),\r
i++;\r
}\r
sq_createslot(v,-3);\r
+ sq_pushroottable(v);\r
+ sq_pushstring(v,_SC("stream"),-1);\r
+ sq_pushstring(v,_SC("std_stream"),-1);\r
+ sq_get(v,-4);\r
+ sq_createslot(v,-3);\r
+ sq_pop(v,1);\r
}\r
else {\r
sq_pop(v,1); //result\r
#ifndef _SQSTD_STREAM_H_\r
#define _SQSTD_STREAM_H_\r
\r
-SQInteger _stream_readstr(HSQUIRRELVM v);\r
SQInteger _stream_readblob(HSQUIRRELVM v);\r
SQInteger _stream_readline(HSQUIRRELVM v);\r
SQInteger _stream_readn(HSQUIRRELVM v);\r
-SQInteger _stream_writestr(HSQUIRRELVM v);\r
SQInteger _stream_writeblob(HSQUIRRELVM v);\r
SQInteger _stream_writen(HSQUIRRELVM v);\r
SQInteger _stream_seek(HSQUIRRELVM v);\r
#define scstrchr wcschr\r
#define scsnprintf wsnprintf\r
#define scatoi _wtoi\r
+#define scstrtok wcstok\r
#else\r
#define scstrchr strchr\r
#define scsnprintf snprintf\r
#define scatoi atoi\r
+#define scstrtok strtok\r
#endif\r
#define MAX_FORMAT_LEN 20\r
#define MAX_WFORMAT_LEN 3\r
sq_getstring(v,2,&format);\r
SQInteger allocated = (sq_getsize(v,2)+1)*sizeof(SQChar);\r
dest = sq_getscratchpad(v,allocated);\r
- SQInteger n = 0,i = 0, nparam = 3, w;\r
+ SQInteger n = 0,i = 0, nparam = 3, w = 0;\r
while(format[n] != '\0') {\r
if(format[n] != '%') {\r
assert(i < allocated);\r
return sq_throwerror(v,_SC("invalid format"));\r
}\r
n++;\r
- if((allocated-i) < addlen)\r
- allocated += addlen;\r
+ allocated += addlen;\r
dest = sq_getscratchpad(v,allocated);\r
switch(valtype) {\r
case 's': i += scsprintf(&dest[i],fmt,ts); break;\r
return 1;\r
}\r
\r
+static void __strip_l(const SQChar *str,const SQChar **start)\r
+{\r
+ const SQChar *t = str;\r
+ while(((*t) != '\0') && scisspace(*t)){ t++; }\r
+ *start = t;\r
+}\r
+\r
+static void __strip_r(const SQChar *str,SQInteger len,const SQChar **end)\r
+{\r
+ if(len == 0) {\r
+ *end = str;\r
+ return;\r
+ }\r
+ const SQChar *t = &str[len-1];\r
+ while(t != str && scisspace(*t)) { t--; }\r
+ *end = t+1;\r
+}\r
+\r
+static SQInteger _string_strip(HSQUIRRELVM v)\r
+{\r
+ const SQChar *str,*start,*end;\r
+ sq_getstring(v,2,&str);\r
+ SQInteger len = sq_getsize(v,2);\r
+ __strip_l(str,&start);\r
+ __strip_r(str,len,&end);\r
+ sq_pushstring(v,start,end - start);\r
+ return 1;\r
+}\r
+\r
+static SQInteger _string_lstrip(HSQUIRRELVM v)\r
+{\r
+ const SQChar *str,*start;\r
+ sq_getstring(v,2,&str);\r
+ __strip_l(str,&start);\r
+ sq_pushstring(v,start,-1);\r
+ return 1;\r
+}\r
+\r
+static SQInteger _string_rstrip(HSQUIRRELVM v)\r
+{\r
+ const SQChar *str,*end;\r
+ sq_getstring(v,2,&str);\r
+ SQInteger len = sq_getsize(v,2);\r
+ __strip_r(str,len,&end);\r
+ sq_pushstring(v,str,end - str);\r
+ return 1;\r
+}\r
+\r
+static SQInteger _string_split(HSQUIRRELVM v)\r
+{\r
+ const SQChar *str,*seps;\r
+ SQChar *stemp,*tok;\r
+ sq_getstring(v,2,&str);\r
+ sq_getstring(v,3,&seps);\r
+ if(sq_getsize(v,3) == 0) return sq_throwerror(v,_SC("empty separators string"));\r
+ SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar);\r
+ stemp = sq_getscratchpad(v,memsize);\r
+ memcpy(stemp,str,memsize);\r
+ tok = scstrtok(stemp,seps);\r
+ sq_newarray(v,0);\r
+ while( tok != NULL ) {\r
+ sq_pushstring(v,tok,-1);\r
+ sq_arrayappend(v,-2);\r
+ tok = scstrtok( NULL, seps );\r
+ }\r
+ return 1;\r
+}\r
+\r
#define SETUP_REX(v) \\r
SQRex *self = NULL; \\r
sq_getinstanceup(v,1,(SQUserPointer *)&self,0); \r
sq_getstring(v,2,&str);\r
if(sqstd_rex_match(self,str) == SQTrue)\r
{\r
- sq_pushinteger(v,1);\r
+ sq_pushbool(v,SQTrue);\r
return 1;\r
}\r
- return 0;\r
+ sq_pushbool(v,SQFalse);\r
+ return 1;\r
}\r
\r
static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end)\r
#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask}\r
static SQRegFunction stringlib_funcs[]={\r
_DECL_FUNC(format,-2,_SC(".s")),\r
+ _DECL_FUNC(strip,2,_SC(".s")),\r
+ _DECL_FUNC(lstrip,2,_SC(".s")),\r
+ _DECL_FUNC(rstrip,2,_SC(".s")),\r
+ _DECL_FUNC(split,3,_SC(".ss")),\r
{0,0}\r
};\r
\r
static SQInteger _system_date(HSQUIRRELVM v)\r
{\r
time_t t;\r
+ SQInteger it;\r
SQInteger format = 'l';\r
if(sq_gettop(v) > 1) {\r
- sq_getinteger(v,2,(SQInteger*)&t);\r
+ sq_getinteger(v,2,&it);\r
+ t = it;\r
if(sq_gettop(v) > 2) {\r
sq_getinteger(v,3,(SQInteger*)&format);\r
}\r
return SQ_ERROR;\r
}\r
\r
-void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo)\r
+void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable)\r
{\r
- _ss(v)->_debuginfo = debuginfo?true:false;\r
+ _ss(v)->_debuginfo = enable?true:false;\r
+}\r
+\r
+void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable)\r
+{\r
+ _ss(v)->_notifyallexceptions = enable?true:false;\r
}\r
\r
void sq_addref(HSQUIRRELVM v,HSQOBJECT *po)\r
{\r
- SQObjectPtr refs;\r
if(!ISREFCOUNTED(type(*po))) return;\r
- if(_table(_ss(v)->_refs_table)->Get(*po, refs)) {\r
- refs = _integer(refs) + 1;\r
- }\r
- else{\r
- refs = 1;\r
- }\r
- _table(_ss(v)->_refs_table)->NewSlot(*po, refs);\r
+ _ss(v)->_refs_table.AddRef(*po);\r
}\r
\r
SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po)\r
{\r
- SQObjectPtr refs;\r
if(!ISREFCOUNTED(type(*po))) return SQTrue;\r
- if(_table(_ss(v)->_refs_table)->Get(*po, refs)) {\r
- SQInteger n = _integer(refs) - 1;\r
- if(n <= 0) {\r
- _table(_ss(v)->_refs_table)->Remove(*po);\r
- sq_resetobject(po);\r
- }\r
- else {\r
- refs = n;_table(_ss(v)->_refs_table)->Set(*po, refs);\r
- return SQFalse;\r
- }\r
- }\r
- return SQTrue;\r
+ return _ss(v)->_refs_table.Release(*po);\r
}\r
\r
const SQChar *sq_objtostring(HSQOBJECT *o) \r
return SQ_OK;\r
}\r
\r
-SQInteger sq_instanceof(HSQUIRRELVM v)\r
+SQBool sq_instanceof(HSQUIRRELVM v)\r
{\r
SQObjectPtr &inst = stack_get(v,-1);\r
SQObjectPtr &cl = stack_get(v,-2);\r
if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS)\r
return sq_throwerror(v,_SC("invalid param type"));\r
- return _instance(inst)->InstanceOf(_class(cl))?1:0;\r
+ return _instance(inst)->InstanceOf(_class(cl))?SQTrue:SQFalse;\r
}\r
\r
SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx)\r
return SQ_OK;\r
}\r
\r
+SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx)\r
+{\r
+ SQObjectPtr &o = stack_get(v,idx);\r
+ if(!sq_isnativeclosure(o) &&\r
+ !sq_isclosure(o))\r
+ return sq_throwerror(v,_SC("the target is not a closure"));\r
+ SQObjectPtr &env = stack_get(v,-1);\r
+ if(!sq_istable(env) &&\r
+ !sq_isclass(env) &&\r
+ !sq_isinstance(env))\r
+ return sq_throwerror(v,_SC("invalid environment"));\r
+ SQObjectPtr w = _refcounted(env)->GetWeakRef(type(env));\r
+ SQObjectPtr ret;\r
+ if(sq_isclosure(o)) {\r
+ SQClosure *c = _closure(o)->Clone();\r
+ c->_env = w;\r
+ ret = c;\r
+ }\r
+ else { //then must be a native closure\r
+ SQNativeClosure *c = _nativeclosure(o)->Clone();\r
+ c->_env = w;\r
+ ret = c;\r
+ }\r
+ v->Pop();\r
+ v->Push(ret);\r
+ return SQ_OK;\r
+}\r
+\r
void sq_pushroottable(HSQUIRRELVM v)\r
{\r
v->Push(v->_roottable);\r
v->Push(res);\r
}\r
\r
+void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b)\r
+{\r
+ SQObjectPtr &o = stack_get(v, idx);\r
+ *b = v->IsFalse(o)?SQFalse:SQTrue;\r
+}\r
+\r
SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i)\r
{\r
SQObjectPtr &o = stack_get(v, idx);\r
return res;\r
}\r
\r
-SQRESULT sq_createslot(HSQUIRRELVM v, SQInteger idx)\r
+SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)\r
{\r
sq_aux_paramscheck(v, 3);\r
SQObjectPtr &self = stack_get(v, idx);\r
if(type(self) == OT_TABLE || type(self) == OT_CLASS) {\r
SQObjectPtr &key = v->GetUp(-2);\r
if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key"));\r
- v->NewSlot(self, key, v->GetUp(-1));\r
+ v->NewSlot(self, key, v->GetUp(-1),bstatic?true:false);\r
v->Pop(2);\r
}\r
return SQ_OK;\r
}\r
\r
+/*SQRESULT sq_createslot(HSQUIRRELVM v, SQInteger idx)\r
+{\r
+ sq_aux_paramscheck(v, 3);\r
+ SQObjectPtr &self = stack_get(v, idx);\r
+ if(type(self) == OT_TABLE || type(self) == OT_CLASS) {\r
+ SQObjectPtr &key = v->GetUp(-2);\r
+ if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key"));\r
+ v->NewSlot(self, key, v->GetUp(-1));\r
+ v->Pop(2);\r
+ }\r
+ return SQ_OK;\r
+}*/\r
+\r
SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval)\r
{\r
sq_aux_paramscheck(v, 2);\r
return SQ_OK;\r
break;\r
case OT_CLASS:\r
- _class(self)->NewSlot(v->GetUp(-2), v->GetUp(-1));\r
+ _class(self)->NewSlot(_ss(v), v->GetUp(-2), v->GetUp(-1),false);\r
v->Pop(2);\r
return SQ_OK;\r
break;\r
case OT_TABLE:\r
if(!_table(self)->_delegate)break;\r
v->Push(SQObjectPtr(_table(self)->_delegate));\r
- return SQ_OK;\r
break;\r
case OT_USERDATA:\r
if(!_userdata(self)->_delegate)break;\r
v->Push(SQObjectPtr(_userdata(self)->_delegate));\r
- return SQ_OK;\r
break;\r
+ default: return sq_throwerror(v,_SC("wrong type")); break;\r
}\r
- return sq_throwerror(v,_SC("wrong type"));\r
+ return SQ_OK;\r
+ \r
}\r
\r
SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx)\r
return NULL;\r
SQClosure *c=_closure(ci._closure);\r
SQFunctionProto *func=_funcproto(c->_function);\r
- return func->GetLocal(v,stackbase,idx,(ci._ip-func->_instructions._vals)-1);\r
+ return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions._vals)-1);\r
}\r
return NULL;\r
}\r
}\r
}\r
\r
-SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval)\r
+SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror)\r
{\r
if(type(v->GetUp(-1))==OT_GENERATOR){\r
v->Push(_null_); //retval\r
- if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),SQVM::ET_RESUME_GENERATOR))\r
+ if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),raiseerror,SQVM::ET_RESUME_GENERATOR))\r
{v->Raise_Error(v->_lasterror); return SQ_ERROR;}\r
if(!retval)\r
v->Pop();\r
return sq_throwerror(v,_SC("only generators can be resumed"));\r
}\r
\r
-SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval)\r
+SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror)\r
{\r
SQObjectPtr res;\r
- if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res)){\r
+ if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false)){\r
v->Pop(params);//pop closure and args\r
if(retval){\r
v->Push(res); return SQ_OK;\r
return v->Suspend();\r
}\r
\r
-SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval)\r
+SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval,SQBool raiseerror)\r
{\r
SQObjectPtr ret;\r
if(!v->_suspended)\r
v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval\r
v->Pop();\r
} else v->GetAt(v->_stackbase+v->_suspended_target)=_null_;\r
- if(!v->Execute(_null_,v->_top,-1,-1,ret,SQVM::ET_RESUME_VM))\r
+ if(!v->Execute(_null_,v->_top,-1,-1,ret,raiseerror,SQVM::ET_RESUME_VM))\r
return SQ_ERROR;\r
if(sq_getvmstate(v) == SQ_VMSTATE_IDLE) {\r
while (v->_top > 1) v->_stack[--v->_top] = _null_;\r
if(sq_gettop(v) >= 1){\r
SQObjectPtr &ud=stack_get(v,idx);\r
switch( type(ud) ) {\r
- case OT_USERDATA:\r
- _userdata(ud)->_hook = hook;\r
- break;\r
- case OT_INSTANCE:\r
- _instance(ud)->_hook = hook;\r
- break;\r
+ case OT_USERDATA: _userdata(ud)->_hook = hook; break;\r
+ case OT_INSTANCE: _instance(ud)->_hook = hook; break;\r
+ case OT_CLASS: _class(ud)->_hook = hook; break;\r
+ default: break; //shutup compiler\r
}\r
}\r
}\r
{\r
SQObjectPtr *o = NULL;\r
_GETSAFE_OBJ(v, -1, OT_CLOSURE,o);\r
- SQClosure *c=_closure(*o);\r
unsigned short tag = SQ_BYTECODE_STREAM_TAG;\r
if(w(up,&tag,2) != 2)\r
return sq_throwerror(v,_SC("io error"));\r
if(type(key) == OT_NULL) {\r
attrs = _class(*o)->_attributes;\r
v->Pop();\r
- v->Push(attrs);\r
+ v->Push(attrs); \r
return SQ_OK;\r
}\r
else if(_class(*o)->GetAttributes(key,attrs)) {\r
return sq_throwerror(v,_SC("wrong index"));\r
}\r
\r
+SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx)\r
+{\r
+ SQObjectPtr *o = NULL;\r
+ _GETSAFE_OBJ(v, idx, OT_CLASS,o);\r
+ if(_class(*o)->_base)\r
+ v->Push(SQObjectPtr(_class(*o)->_base));\r
+ else\r
+ v->Push(_null_);\r
+ return SQ_OK;\r
+}\r
+\r
SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx)\r
{\r
SQObjectPtr *o = NULL;\r
return SQ_OK;\r
}\r
\r
+SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t)\r
+{\r
+ SQSharedState *ss = _ss(v);\r
+ switch(t) {\r
+ case OT_TABLE: v->Push(ss->_table_default_delegate); break;\r
+ case OT_ARRAY: v->Push(ss->_array_default_delegate); break;\r
+ case OT_STRING: v->Push(ss->_string_default_delegate); break;\r
+ case OT_INTEGER: case OT_FLOAT: v->Push(ss->_number_default_delegate); break;\r
+ case OT_GENERATOR: v->Push(ss->_generator_default_delegate); break;\r
+ case OT_CLOSURE: case OT_NATIVECLOSURE: v->Push(ss->_closure_default_delegate); break;\r
+ case OT_THREAD: v->Push(ss->_thread_default_delegate); break;\r
+ case OT_CLASS: v->Push(ss->_class_default_delegate); break;\r
+ case OT_INSTANCE: v->Push(ss->_instance_default_delegate); break;\r
+ case OT_WEAKREF: v->Push(ss->_weakref_default_delegate); break;\r
+ default: return sq_throwerror(v,_SC("the type doesn't have a default delegate"));\r
+ }\r
+ return SQ_OK;\r
+}\r
+\r
SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx)\r
{\r
SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val;\r
sq_pushstring(v, _SC("locals"), -1);\r
sq_newtable(v);\r
seq=0;\r
- while (name = sq_getlocal(v, level, seq)) {\r
+ while ((name = sq_getlocal(v, level, seq))) {\r
sq_pushstring(v, name, -1);\r
sq_push(v, -2);\r
sq_createslot(v, -4);\r
sq_pushstring(v,_SC("_charsize_"),-1);\r
sq_pushinteger(v,sizeof(SQChar));\r
sq_createslot(v,-3);\r
+ sq_pushstring(v,_SC("_intsize_"),-1);\r
+ sq_pushinteger(v,sizeof(SQInteger));\r
+ sq_createslot(v,-3);\r
sq_pop(v,1);\r
}\r
\r
v->Push(SQObjectPtr(tointeger(o)));\r
break;\r
case OT_BOOL:\r
- v->Push(SQObjectPtr(_integer(o)?1:0));\r
+ v->Push(SQObjectPtr(_integer(o)?(SQInteger)1:(SQInteger)0));\r
break;\r
default:\r
v->Push(_null_);\r
static SQInteger number_delegate_tochar(HSQUIRRELVM v)\r
{\r
SQObject &o=stack_get(v,1);\r
- SQChar c=tointeger(o);\r
+ SQChar c = (SQChar)tointeger(o);\r
v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1));\r
return 1;\r
}\r
{_SC("rawdelete"),table_rawdelete,2, _SC("t")},\r
{_SC("rawin"),container_rawexists,2, _SC("t")},\r
{_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+ {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
{0,0}\r
};\r
\r
sq_pushroottable(v);\r
v->Push(a);\r
v->Push(b);\r
- if(SQ_FAILED(sq_call(v, 3, SQTrue))) {\r
+ if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) {\r
v->Raise_Error(_SC("compare func failed"));\r
return false;\r
}\r
\r
static SQInteger array_sort(HSQUIRRELVM v)\r
{\r
- //SQ_TRY {\r
SQInteger func = -1;\r
SQObjectPtr &o = stack_get(v,1);\r
SQObject &funcobj = stack_get(v,2);\r
{_SC("sort"),array_sort,-1, _SC("ac")},\r
{_SC("slice"),array_slice,-1, _SC("ann")},\r
{_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+ {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
{0,0}\r
};\r
\r
{_SC("len"),default_delegate_len,1, _SC("s")},\r
{_SC("tointeger"),default_delegate_tointeger,1, _SC("s")},\r
{_SC("tofloat"),default_delegate_tofloat,1, _SC("s")},\r
- {_SC("tostring"),default_delegate_tostring,1, _SC("s")},\r
+ {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
{_SC("slice"),string_slice,-1, _SC(" s n n")},\r
{_SC("find"),string_find,-2, _SC("s s n ")},\r
{_SC("tolower"),string_tolower,1, _SC("s")},\r
SQRegFunction SQSharedState::_number_default_delegate_funcz[]={\r
{_SC("tointeger"),default_delegate_tointeger,1, _SC("n|b")},\r
{_SC("tofloat"),default_delegate_tofloat,1, _SC("n|b")},\r
- {_SC("tostring"),default_delegate_tostring,1, _SC("n|b")},\r
+ {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
{_SC("tochar"),number_delegate_tochar,1, _SC("n|b")},\r
{_SC("weakref"),obj_delegate_weakref,1, NULL },\r
{0,0}\r
};\r
\r
//CLOSURE DEFAULT DELEGATE//////////////////////////\r
+static SQInteger closure_pcall(HSQUIRRELVM v)\r
+{\r
+ return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR;\r
+}\r
+\r
static SQInteger closure_call(HSQUIRRELVM v)\r
{\r
- return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue))?1:SQ_ERROR;\r
+ return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQTrue))?1:SQ_ERROR;\r
}\r
\r
-static SQInteger closure_acall(HSQUIRRELVM v)\r
+static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror)\r
{\r
SQArray *aparams=_array(stack_get(v,2));\r
SQInteger nparams=aparams->Size();\r
v->Push(stack_get(v,1));\r
for(SQInteger i=0;i<nparams;i++)v->Push(aparams->_values[i]);\r
- return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue))?1:SQ_ERROR;\r
+ return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue,raiseerror))?1:SQ_ERROR;\r
+}\r
+\r
+static SQInteger closure_acall(HSQUIRRELVM v)\r
+{\r
+ return _closure_acall(v,SQTrue);\r
+}\r
+\r
+static SQInteger closure_pacall(HSQUIRRELVM v)\r
+{\r
+ return _closure_acall(v,SQFalse);\r
+}\r
+\r
+static SQInteger closure_bindenv(HSQUIRRELVM v)\r
+{\r
+ if(SQ_FAILED(sq_bindenv(v,1)))\r
+ return SQ_ERROR;\r
+ return 1;\r
+}\r
+\r
+static SQInteger closure_getinfos(HSQUIRRELVM v) {\r
+ SQObject o = stack_get(v,1);\r
+ SQTable *res = SQTable::Create(_ss(v),4);\r
+ if(type(o) == OT_CLOSURE) {\r
+ SQFunctionProto *f = _funcproto(_closure(o)->_function);\r
+ SQInteger nparams = f->_parameters.size() + (f->_varparams?1:0);\r
+ SQObjectPtr params = SQArray::Create(_ss(v),nparams);\r
+ for(SQUnsignedInteger n = 0; n<f->_parameters.size(); n++) {\r
+ _array(params)->Set((SQInteger)n,f->_parameters[n]);\r
+ }\r
+ if(f->_varparams) {\r
+ _array(params)->Set(nparams-1,SQString::Create(_ss(v),_SC("..."),-1));\r
+ }\r
+ res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),false);\r
+ res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),f->_name);\r
+ res->NewSlot(SQString::Create(_ss(v),_SC("src"),-1),f->_sourcename);\r
+ res->NewSlot(SQString::Create(_ss(v),_SC("parameters"),-1),params);\r
+ res->NewSlot(SQString::Create(_ss(v),_SC("varargs"),-1),f->_varparams);\r
+ }\r
+ else { //OT_NATIVECLOSURE \r
+ SQNativeClosure *nc = _nativeclosure(o);\r
+ res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),true);\r
+ res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),nc->_name);\r
+ res->NewSlot(SQString::Create(_ss(v),_SC("paramscheck"),-1),nc->_nparamscheck);\r
+ SQObjectPtr typecheck;\r
+ if(nc->_typecheck.size() > 0) {\r
+ typecheck =\r
+ SQArray::Create(_ss(v), nc->_typecheck.size());\r
+ for(SQUnsignedInteger n = 0; n<nc->_typecheck.size(); n++) {\r
+ _array(typecheck)->Set((SQInteger)n,nc->_typecheck[n]);\r
+ }\r
+ }\r
+ res->NewSlot(SQString::Create(_ss(v),_SC("typecheck"),-1),typecheck);\r
+ }\r
+ v->Push(res);\r
+ return 1;\r
}\r
\r
+\r
SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={\r
{_SC("call"),closure_call,-1, _SC("c")},\r
+ {_SC("pcall"),closure_pcall,-1, _SC("c")},\r
{_SC("acall"),closure_acall,2, _SC("ca")},\r
+ {_SC("pacall"),closure_pacall,2, _SC("ca")},\r
{_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+ {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
+ {_SC("bindenv"),closure_bindenv,2, _SC("c x|y|t")},\r
+ {_SC("getinfos"),closure_getinfos,1, _SC("c")},\r
{0,0}\r
};\r
\r
SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={\r
{_SC("getstatus"),generator_getstatus,1, _SC("g")},\r
{_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+ {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
{0,0}\r
};\r
\r
_thread(o)->Push(_thread(o)->_roottable);\r
for(SQInteger i = 2; i<(nparams+1); i++)\r
sq_move(_thread(o),v,i);\r
- if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue))) {\r
+ if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue,SQFalse))) {\r
sq_move(v,_thread(o),-1);\r
return 1;\r
}\r
if(wakeupret) {\r
sq_move(thread,v,2);\r
}\r
- if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,1))) {\r
+ if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,1,SQFalse))) {\r
sq_move(v,thread,-1);\r
sq_pop(thread,1);\r
if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) {\r
{_SC("wakeup"), thread_wakeup, -1, _SC("v")},\r
{_SC("getstatus"), thread_getstatus, 1, _SC("v")},\r
{_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+ {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
{0,0},\r
};\r
\r
return SQ_ERROR;\r
}\r
\r
+static SQInteger class_instance(HSQUIRRELVM v)\r
+{\r
+ if(SQ_SUCCEEDED(sq_createinstance(v,-1)))\r
+ return 1;\r
+ return SQ_ERROR;\r
+}\r
+\r
SQRegFunction SQSharedState::_class_default_delegate_funcz[] = {\r
{_SC("getattributes"), class_getattributes, 2, _SC("y.")},\r
{_SC("setattributes"), class_setattributes, 3, _SC("y..")},\r
{_SC("rawin"),container_rawexists,2, _SC("y")},\r
{_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+ {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
+ {_SC("instance"),class_instance,1, _SC("y")},\r
{0,0}\r
};\r
\r
{_SC("getclass"), instance_getclass, 1, _SC("x")},\r
{_SC("rawin"),container_rawexists,2, _SC("x")},\r
{_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+ {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
{0,0}\r
};\r
\r
SQRegFunction SQSharedState::_weakref_default_delegate_funcz[] = {\r
{_SC("ref"),weakref_ref,1, _SC("r")},\r
{_SC("weakref"),obj_delegate_weakref,1, NULL },\r
+ {_SC("tostring"),default_delegate_tostring,1, _SC(".")},\r
{0,0}\r
};\r
\r
{\r
_base = base;\r
_typetag = 0;\r
+ _hook = NULL;\r
_metamethods.resize(MT_LAST); //size it to max size\r
if(_base) {\r
_defaultvalues.copy(base->_defaultvalues);\r
Finalize();\r
}\r
\r
-bool SQClass::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)\r
+bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)\r
{\r
SQObjectPtr temp;\r
if(_locked) \r
_defaultvalues[_member_idx(temp)].val = val;\r
return true;\r
}\r
- if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) {\r
+ if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE || bstatic) {\r
SQInteger mmidx;\r
- if((mmidx = _sharedstate->GetMetaMethodIdxByName(key)) != -1) {\r
+ if((type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) && \r
+ (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) {\r
_metamethods[mmidx] = val;\r
} \r
else {\r
Finalize();\r
}\r
\r
-bool SQInstance::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res)\r
+bool SQInstance::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res)\r
{\r
if(type(_class->_metamethods[mm]) != OT_NULL) {\r
res = _class->_metamethods[mm];\r
return newclass;\r
}\r
~SQClass();\r
- bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val);\r
+ bool NewSlot(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic);\r
bool Get(const SQObjectPtr &key,SQObjectPtr &val) {\r
if(_members->Get(key,val)) {\r
if(_isfield(val)) {\r
bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val);\r
bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval);\r
void Lock() { _locked = true; if(_base) _base->Lock(); }\r
- void Release() { sq_delete(this, SQClass); }\r
+ void Release() { \r
+ if (_hook) { _hook(_typetag,0);}\r
+ sq_delete(this, SQClass); \r
+ }\r
void Finalize();\r
+#ifndef NO_GARBAGE_COLLECTOR\r
void Mark(SQCollectable ** );\r
+#endif\r
SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);\r
SQInstance *CreateInstance();\r
SQTable *_members;\r
- //SQTable *_properties;\r
SQClass *_base;\r
SQClassMemeberVec _defaultvalues;\r
SQClassMemeberVec _methods;\r
SQObjectPtrVec _metamethods;\r
SQObjectPtr _attributes;\r
SQUserPointer _typetag;\r
+ SQRELEASEHOOK _hook;\r
bool _locked;\r
};\r
\r
SQ_FREE(this, size);\r
}\r
void Finalize();\r
+#ifndef NO_GARBAGE_COLLECTOR \r
void Mark(SQCollectable ** );\r
+#endif\r
bool InstanceOf(SQClass *trg);\r
- bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res);\r
+ bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res);\r
\r
SQClass *_class;\r
SQUserPointer _userpointer;\r
void Release(){\r
sq_delete(this,SQClosure);\r
}\r
+ SQClosure *Clone()\r
+ {\r
+ SQClosure * ret = SQClosure::Create(_opt_ss(this),_funcproto(_function));\r
+ ret->_env = _env;\r
+ ret->_outervalues.copy(_outervalues);\r
+ return ret;\r
+ }\r
~SQClosure()\r
{\r
REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\r
void Mark(SQCollectable **chain);\r
void Finalize(){_outervalues.resize(0); }\r
#endif\r
+ SQObjectPtr _env;\r
SQObjectPtr _function;\r
SQObjectPtrVec _outervalues;\r
};\r
new (nc) SQNativeClosure(ss,func);\r
return nc;\r
}\r
+ SQNativeClosure *Clone()\r
+ {\r
+ SQNativeClosure * ret = SQNativeClosure::Create(_opt_ss(this),_function);\r
+ ret->_env = _env;\r
+ ret->_name = _name;\r
+ ret->_outervalues.copy(_outervalues);\r
+ ret->_typecheck = _typecheck;\r
+ ret->_nparamscheck = _nparamscheck;\r
+ return ret;\r
+ }\r
~SQNativeClosure()\r
{\r
REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\r
void Mark(SQCollectable **chain);\r
void Finalize(){_outervalues.resize(0);}\r
#endif\r
+ SQObjectPtr _env;\r
SQFUNCTION _function;\r
SQObjectPtr _name;\r
SQObjectPtrVec _outervalues;\r
case TK_MULEQ: oper = '*'; break;\r
case TK_DIVEQ: oper = '/'; break;\r
case TK_MODEQ: oper = '%'; break;\r
- default: assert(0); break;\r
+ default: oper = 0; //shut up compiler\r
+ assert(0); break;\r
};\r
if(deref) {\r
SQInteger val = _fs->PopTarget();\r
_fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);\r
Lex();\r
break;\r
- case TK_INTEGER: \r
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue));\r
+ case TK_INTEGER: {\r
+ if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits?\r
+ _fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue);\r
+ }\r
+ else {\r
+ _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue));\r
+ }\r
Lex();\r
+ }\r
break;\r
case TK_FLOAT: \r
_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue));\r
\r
while(_token != terminator) {\r
bool hasattrs = false;\r
+ bool isstatic = false;\r
//check if is an attribute\r
- if(separator == ';' && _token == TK_ATTR_OPEN) {\r
- _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();\r
- ParseTableOrClass(',',TK_ATTR_CLOSE);\r
- hasattrs = true;\r
+ if(separator == ';') {\r
+ if(_token == TK_ATTR_OPEN) {\r
+ _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();\r
+ ParseTableOrClass(',',TK_ATTR_CLOSE);\r
+ hasattrs = true;\r
+ }\r
+ if(_token == TK_STATIC) {\r
+ isstatic = true;\r
+ Lex();\r
+ }\r
}\r
switch(_token) {\r
case TK_FUNCTION:\r
SQInteger key = _fs->PopTarget();\r
SQInteger attrs = hasattrs ? _fs->PopTarget():-1;\r
assert(hasattrs && attrs == key-1 || !hasattrs);\r
+ unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);\r
SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE\r
- _fs->AddInstruction(hasattrs?_OP_NEWSLOTA:_OP_NEWSLOT, _fs->PushTarget(), table, key, val);\r
- _fs->PopTarget();\r
+ _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);\r
+ //_fs->PopTarget();\r
}\r
if(separator == _SC(',')) //hack recognizes a table from the separator\r
_fs->SetIntructionParam(tpos, 1, nkeys);\r
SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();\r
_fs->_breaktargets.push_back(0);\r
while(_token == TK_CASE) {\r
+ //_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one\r
if(!bfirst) {\r
_fs->AddInstruction(_OP_JMP, 0, 0);\r
skipcondjmp = _fs->GetCurrentPos();\r
if(tonextcondjmp != -1)\r
_fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);\r
if(_token == TK_DEFAULT) {\r
+ // _fs->AddLineInfos(_lex._currentline, _lineinfo);\r
Lex(); Expect(_SC(':'));\r
SQInteger stacksize = _fs->GetStackSize();\r
Statements();\r
#define TK_MODEQ 319\r
#define TK_ATTR_OPEN 320\r
#define TK_ATTR_CLOSE 321\r
+#define TK_STATIC 322\r
\r
\r
typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s);\r
si->funcname = _stringval(_nativeclosure(ci._closure)->_name);\r
si->line = -1;\r
break;\r
+ default: break; //shutup compiler\r
}\r
return SQ_OK;\r
}\r
{\r
va_list vl;\r
va_start(vl, s);\r
- scvsprintf(_sp(rsl(scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl);\r
+ scvsprintf(_sp(rsl((SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl);\r
va_end(vl);\r
_lasterror = SQString::Create(_ss(this),_spval,-1);\r
}\r
SQInstructionDesc g_InstrDesc[]={\r
{_SC("_OP_LINE")},\r
{_SC("_OP_LOAD")},\r
+ {_SC("_OP_LOADINT")},\r
{_SC("_OP_DLOAD")},\r
{_SC("_OP_TAILCALL")},\r
{_SC("_OP_CALL")},\r
case OT_STRING: scprintf(_SC("\"%s\""),_stringval(o));break;\r
case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break;\r
case OT_INTEGER: scprintf(_SC("{%d}"),_integer(o));break;\r
+ default: assert(0); break; //shut up compiler\r
}\r
}\r
\r
\r
SQInteger SQFuncState::GetConstant(const SQObject &cons)\r
{\r
- SQInteger n=0;\r
SQObjectPtr val;\r
if(!_table(_literals)->Get(cons,val))\r
{\r
\r
void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)\r
{\r
- _instructions[pos]._arg0=*((SQUnsignedInteger *)&arg0);\r
- _instructions[pos]._arg1=*((SQUnsignedInteger *)&arg1);\r
- _instructions[pos]._arg2=*((SQUnsignedInteger *)&arg2);\r
- _instructions[pos]._arg3=*((SQUnsignedInteger *)&arg3);\r
+ _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0);\r
+ _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1);\r
+ _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2);\r
+ _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3);\r
}\r
\r
void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val)\r
{\r
switch(arg){\r
- case 0:_instructions[pos]._arg0=*((SQUnsignedInteger *)&val);break;\r
- case 1:_instructions[pos]._arg1=*((SQUnsignedInteger *)&val);break;\r
- case 2:_instructions[pos]._arg2=*((SQUnsignedInteger *)&val);break;\r
- case 3:_instructions[pos]._arg3=*((SQUnsignedInteger *)&val);break;\r
- case 4:_instructions[pos]._arg1=*((SQUnsignedInteger *)&val);break;\r
+ case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break;\r
+ case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break;\r
+ case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break;\r
+ case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break;\r
};\r
}\r
\r
SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len)\r
{\r
SQObjectPtr ns(SQString::Create(_sharedstate,s,len));\r
- _table(_strings)->NewSlot(ns,1);\r
+ _table(_strings)->NewSlot(ns,(SQInteger)1);\r
return ns;\r
}\r
\r
void SetStackSize(SQInteger n);\r
void SnoozeOpt(){_optimization=false;}\r
SQInteger GetCurrentPos(){return _instructions.size()-1;}\r
- //SQInteger GetStringConstant(const SQChar *cons);\r
SQInteger GetNumericConstant(const SQInteger cons);\r
SQInteger GetNumericConstant(const SQFloat cons);\r
SQInteger PushLocalVariable(const SQObject &name);\r
SQInteger _nliterals;\r
SQLineInfoVec _lineinfos;\r
SQFuncState *_parent;\r
- SQIntVec _breaktargets; //contains number of nested exception traps\r
+ SQIntVec _breaktargets;\r
SQIntVec _continuetargets;\r
SQInteger _lastline;\r
- SQInteger _traps;\r
+ SQInteger _traps; //contains number of nested exception traps\r
bool _optimization;\r
SQSharedState *_sharedstate;\r
sqvector<SQFuncState*> _childstates;\r
ADD_KEYWORD(vargv,TK_VARGV);\r
ADD_KEYWORD(true,TK_TRUE);\r
ADD_KEYWORD(false,TK_FALSE);\r
+ ADD_KEYWORD(static,TK_STATIC);\r
\r
_readf = rg;\r
_up = up;\r
SQInteger t = _readf(_up);\r
if(t > MAX_CHAR) Error(_SC("Invalid character"));\r
if(t != 0) {\r
- _currdata = t;\r
+ _currdata = (LexChar)t;\r
return;\r
}\r
_currdata = SQUIRREL_EOB;\r
}\r
else {\r
SQInteger c = CUR_CHAR;\r
- if (sciscntrl(c)) Error(_SC("unexpected character(control)"));\r
+ if (sciscntrl((int)c)) Error(_SC("unexpected character(control)"));\r
NEXT();\r
RETURN_TOKEN(c); \r
}\r
return TK_STRING_LITERAL;\r
}\r
\r
-SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; }\r
+void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res)\r
+{\r
+ *res = 0;\r
+ while(*s != 0)\r
+ {\r
+ if(scisdigit(*s)) *res = (*res)*16+((*s++)-'0');\r
+ else if(scisxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10);\r
+ else { assert(0); }\r
+ }\r
+}\r
\r
+void LexInteger(const SQChar *s,SQUnsignedInteger *res)\r
+{\r
+ *res = 0;\r
+ while(*s != 0)\r
+ {\r
+ *res = (*res)*10+((*s++)-'0');\r
+ }\r
+}\r
+\r
+SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; }\r
+#define MAX_HEX_DIGITS (sizeof(SQInteger)*2)\r
SQInteger SQLexer::ReadNumber()\r
{\r
#define TINT 1\r
#define THEX 3\r
#define TSCIENTIFIC 4\r
SQInteger type = TINT, firstchar = CUR_CHAR;\r
- bool isfloat = false;\r
SQChar *sTemp;\r
INIT_TEMP_STRING();\r
NEXT();\r
APPEND_CHAR(CUR_CHAR);\r
NEXT();\r
}\r
- if(_longstr.size() > 8) Error(_SC("Hex number over 8 digits"));\r
+ if(_longstr.size() > MAX_HEX_DIGITS) Error(_SC("too many digits for an Hex number"));\r
}\r
else {\r
- APPEND_CHAR(firstchar);\r
+ APPEND_CHAR((int)firstchar);\r
while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) {\r
if(CUR_CHAR == _SC('.')) type = TFLOAT;\r
if(isexponent(CUR_CHAR)) {\r
_fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp);\r
return TK_FLOAT;\r
case TINT:\r
- _nvalue = (SQInteger)scstrtol(&_longstr[0],&sTemp,10);\r
+ LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue);\r
return TK_INTEGER;\r
case THEX:\r
- *((SQUnsignedInteger *)&_nvalue) = scstrtoul(&_longstr[0],&sTemp,16);\r
+ LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);\r
return TK_INTEGER;\r
}\r
return 0;\r
\r
SQInteger SQLexer::ReadID()\r
{\r
- SQInteger res, size = 0;\r
+ SQInteger res;\r
INIT_TEMP_STRING();\r
do {\r
APPEND_CHAR(CUR_CHAR);\r
} while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_'));\r
TERMINATE_BUFFER();\r
res = GetIDType(&_longstr[0]);\r
- if(res == TK_IDENTIFIER) {\r
+ if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) {\r
_svalue = &_longstr[0];\r
}\r
return res;\r
#ifndef _SQLEXER_H_\r
#define _SQLEXER_H_\r
\r
-#define MAX_STRING 2024\r
-\r
-\r
+#ifdef _UNICODE\r
+typedef SQChar LexChar;\r
+#else\r
+typedef unsigned char LexChar;\r
+#endif\r
\r
struct SQLexer\r
{\r
SQFloat _fvalue;\r
SQLEXREADFUNC _readf;\r
SQUserPointer _up;\r
-#ifdef _UNICODE\r
- SQChar _currdata;\r
-#else\r
- unsigned char _currdata;\r
-#endif\r
+ LexChar _currdata;\r
SQSharedState *_sharedstate;\r
sqvector<SQChar> _longstr;\r
CompilerErrorFunc _errfunc;\r
REMOVE_STRING(_sharedstate,this);\r
}\r
\r
+SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)\r
+{\r
+ SQInteger idx = (SQInteger)TranslateIndex(refpos);\r
+ while(idx < _len){\r
+ outkey = (SQInteger)idx;\r
+ outval = SQInteger(_val[idx]);\r
+ //return idx for the next iteration\r
+ return ++idx;\r
+ }\r
+ //nothing to iterate anymore\r
+ return -1;\r
+}\r
+\r
SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx)\r
{\r
switch(type(idx)){\r
return 0;\r
case OT_INTEGER:\r
return (SQUnsignedInteger)_integer(idx);\r
+ default: assert(0); break;\r
}\r
- assert(0);\r
return 0;\r
}\r
\r
sq_delete(this,SQWeakRef);\r
}\r
\r
-bool SQDelegable::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res) {\r
+bool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) {\r
if(_delegate) {\r
- return _delegate->Get((*_ss(this)->_metamethods)[mm],res);\r
+ return _delegate->Get((*_ss(v)->_metamethods)[mm],res);\r
}\r
return false;\r
}\r
\r
SQInteger SQFunctionProto::GetLine(SQInstruction *curr)\r
{\r
- SQInteger op=(curr-_instructions._vals);\r
+ SQInteger op = (SQInteger)(curr-_instructions._vals);\r
SQInteger line=_lineinfos[0]._line;\r
for(SQUnsignedInteger i=1;i<_lineinfos.size();i++){\r
if(_lineinfos[i]._op>=op)\r
MT_NEWSLOT=13,\r
MT_DELSLOT=14,\r
MT_TOSTRING=15,\r
- MT_LAST = 16,\r
+ MT_NEWMEMBER=16,\r
+ MT_INHERITED=17,\r
+ MT_LAST = 18\r
};\r
\r
#define MM_ADD _SC("_add")\r
#define MM_NEWSLOT _SC("_newslot")\r
#define MM_DELSLOT _SC("_delslot")\r
#define MM_TOSTRING _SC("_tostring")\r
+#define MM_NEWMEMBER _SC("_newmember")\r
+#define MM_INHERITED _SC("_inherited")\r
\r
#define MINPOWER2 4\r
\r
struct SQRefCounted\r
{\r
SQRefCounted() { _uiRef = 0; _weakref = NULL; }\r
- ~SQRefCounted();\r
+ virtual ~SQRefCounted();\r
SQWeakRef *GetWeakRef(SQObjectType type);\r
SQUnsignedInteger _uiRef;\r
struct SQWeakRef *_weakref;\r
\r
struct SQDelegable : public CHAINABLE_OBJ {\r
bool SetDelegate(SQTable *m);\r
- virtual bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res);\r
+ virtual bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res);\r
SQTable *_delegate;\r
};\r
\r
typedef sqvector<SQObjectPtr> SQObjectPtrVec;\r
typedef sqvector<SQInteger> SQIntVec;\r
\r
+\r
#endif //_SQOBJECT_H_\r
#define _SQOPCODES_H_\r
\r
#define MAX_FUNC_STACKSIZE 0xFF\r
-#define MAX_LITERALS 0xFFFFFFFF\r
+#define MAX_LITERALS ((SQInteger)0x7FFFFFFF)\r
\r
enum BitWiseOP {\r
BW_AND = 0,\r
{\r
_OP_LINE= 0x00, \r
_OP_LOAD= 0x01,\r
- _OP_DLOAD= 0x02,\r
- _OP_TAILCALL= 0x03, \r
- _OP_CALL= 0x04, \r
- _OP_PREPCALL= 0x05, \r
- _OP_PREPCALLK= 0x06, \r
- _OP_GETK= 0x07, \r
- _OP_MOVE= 0x08, \r
- _OP_NEWSLOT= 0x09, \r
- _OP_DELETE= 0x0A, \r
- _OP_SET= 0x0B, \r
- _OP_GET= 0x0C,\r
- _OP_EQ= 0x0D,\r
- _OP_NE= 0x0E,\r
- _OP_ARITH= 0x0F,\r
- _OP_BITW= 0x10,\r
- _OP_RETURN= 0x11, \r
- _OP_LOADNULLS= 0x12, \r
- _OP_LOADROOTTABLE= 0x13,\r
- _OP_LOADBOOL= 0x14,\r
- _OP_DMOVE= 0x15, \r
- _OP_JMP= 0x16, \r
- _OP_JNZ= 0x17, \r
- _OP_JZ= 0x18, \r
- _OP_LOADFREEVAR= 0x19, \r
- _OP_VARGC= 0x1A, \r
- _OP_GETVARGV= 0x1B, \r
- _OP_NEWTABLE= 0x1C, \r
- _OP_NEWARRAY= 0x1D, \r
- _OP_APPENDARRAY= 0x1E, \r
- _OP_GETPARENT= 0x1F, \r
- _OP_COMPARITH= 0x20, \r
- _OP_COMPARITHL= 0x21, \r
- _OP_INC= 0x22, \r
- _OP_INCL= 0x23, \r
- _OP_PINC= 0x24, \r
- _OP_PINCL= 0x25, \r
- _OP_CMP= 0x26,\r
- _OP_EXISTS= 0x27, \r
- _OP_INSTANCEOF= 0x28,\r
- _OP_AND= 0x29,\r
- _OP_OR= 0x2A,\r
- _OP_NEG= 0x2B,\r
- _OP_NOT= 0x2C,\r
- _OP_BWNOT= 0x2D, \r
- _OP_CLOSURE= 0x2E, \r
- _OP_YIELD= 0x2F, \r
- _OP_RESUME= 0x30,\r
- _OP_FOREACH= 0x31,\r
- _OP_DELEGATE= 0x32,\r
- _OP_CLONE= 0x33,\r
- _OP_TYPEOF= 0x34,\r
- _OP_PUSHTRAP= 0x35,\r
- _OP_POPTRAP= 0x36,\r
- _OP_THROW= 0x37,\r
- _OP_CLASS= 0x38,\r
- _OP_NEWSLOTA= 0x39,\r
- \r
- \r
+ _OP_LOADINT= 0x02,\r
+ _OP_DLOAD= 0x03,\r
+ _OP_TAILCALL= 0x04, \r
+ _OP_CALL= 0x05, \r
+ _OP_PREPCALL= 0x06, \r
+ _OP_PREPCALLK= 0x07, \r
+ _OP_GETK= 0x08, \r
+ _OP_MOVE= 0x09, \r
+ _OP_NEWSLOT= 0x0A, \r
+ _OP_DELETE= 0x0B, \r
+ _OP_SET= 0x0C, \r
+ _OP_GET= 0x0D,\r
+ _OP_EQ= 0x0E,\r
+ _OP_NE= 0x0F,\r
+ _OP_ARITH= 0x10,\r
+ _OP_BITW= 0x11,\r
+ _OP_RETURN= 0x12, \r
+ _OP_LOADNULLS= 0x13, \r
+ _OP_LOADROOTTABLE= 0x14,\r
+ _OP_LOADBOOL= 0x15,\r
+ _OP_DMOVE= 0x16, \r
+ _OP_JMP= 0x17, \r
+ _OP_JNZ= 0x18, \r
+ _OP_JZ= 0x19, \r
+ _OP_LOADFREEVAR= 0x1A, \r
+ _OP_VARGC= 0x1B, \r
+ _OP_GETVARGV= 0x1C, \r
+ _OP_NEWTABLE= 0x1D, \r
+ _OP_NEWARRAY= 0x1E, \r
+ _OP_APPENDARRAY= 0x1F, \r
+ _OP_GETPARENT= 0x20, \r
+ _OP_COMPARITH= 0x21, \r
+ _OP_COMPARITHL= 0x22, \r
+ _OP_INC= 0x23, \r
+ _OP_INCL= 0x24, \r
+ _OP_PINC= 0x25, \r
+ _OP_PINCL= 0x26, \r
+ _OP_CMP= 0x27,\r
+ _OP_EXISTS= 0x28, \r
+ _OP_INSTANCEOF= 0x29,\r
+ _OP_AND= 0x2A,\r
+ _OP_OR= 0x2B,\r
+ _OP_NEG= 0x2C,\r
+ _OP_NOT= 0x2D,\r
+ _OP_BWNOT= 0x2E, \r
+ _OP_CLOSURE= 0x2F, \r
+ _OP_YIELD= 0x30, \r
+ _OP_RESUME= 0x31,\r
+ _OP_FOREACH= 0x32,\r
+ _OP_DELEGATE= 0x33,\r
+ _OP_CLONE= 0x34,\r
+ _OP_TYPEOF= 0x35,\r
+ _OP_PUSHTRAP= 0x36,\r
+ _OP_POPTRAP= 0x37,\r
+ _OP_THROW= 0x38,\r
+ _OP_CLASS= 0x39,\r
+ _OP_NEWSLOTA= 0x3A\r
}; \r
+\r
struct SQInstructionDesc { \r
const SQChar *name; \r
}; \r
SQInstruction(){};\r
SQInstruction(SQOpcode _op,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0)\r
{ op = _op;\r
- _arg0 = a0;_arg1 = a1;\r
- _arg2 = a2;_arg3 = a3;\r
+ _arg0 = (unsigned char)a0;_arg1 = (SQInt32)a1;\r
+ _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3;\r
}\r
\r
\r
#include "squtils.h"\r
typedef sqvector<SQInstruction> SQInstructionVec;\r
\r
+#define NEW_SLOT_ATTRIBUTES_FLAG 0x01\r
+#define NEW_SLOT_STATIC_FLAG 0x02\r
+\r
#endif // _SQOPCODES_H_\r
SQObjectPtr _null_;\r
SQObjectPtr _true_(true);\r
SQObjectPtr _false_(false);\r
-SQObjectPtr _one_(1);\r
-SQObjectPtr _minusone_(-1);\r
+SQObjectPtr _one_((SQInteger)1);\r
+SQObjectPtr _minusone_((SQInteger)-1);\r
\r
SQSharedState::SQSharedState()\r
{\r
_compilererrorhandler = NULL;\r
_printfunc = NULL;\r
_debuginfo = false;\r
+ _notifyallexceptions = false;\r
}\r
\r
#define newsysstring(s) { \\r
newmetamethod(MM_NEWSLOT);\r
newmetamethod(MM_DELSLOT);\r
newmetamethod(MM_TOSTRING);\r
+ newmetamethod(MM_NEWMEMBER);\r
+ newmetamethod(MM_INHERITED);\r
\r
_constructoridx = SQString::Create(this,_SC("constructor"));\r
- _refs_table = SQTable::Create(this,0);\r
_registry = SQTable::Create(this,0);\r
_table_default_delegate=CreateDefaultDelegate(this,_table_default_delegate_funcz);\r
_array_default_delegate=CreateDefaultDelegate(this,_array_default_delegate_funcz);\r
SQSharedState::~SQSharedState()\r
{\r
_constructoridx = _null_;\r
- _table(_refs_table)->Finalize();\r
+ _refs_table.Finalize();\r
_table(_registry)->Finalize();\r
_table(_metamethodsmap)->Finalize();\r
- _refs_table = _null_;\r
+// _refs_table = _null_;\r
_registry = _null_;\r
_metamethodsmap = _null_;\r
while(!_systemstrings->empty()){\r
case OT_THREAD:_thread(o)->Mark(chain);break;\r
case OT_CLASS:_class(o)->Mark(chain);break;\r
case OT_INSTANCE:_instance(o)->Mark(chain);break;\r
+ default: break; //shutup compiler\r
}\r
}\r
\r
\r
vms->Mark(&tchain);\r
SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed();\r
- MarkObject(_refs_table,&tchain);\r
+ _refs_table.Mark(&tchain);\r
MarkObject(_registry,&tchain);\r
MarkObject(_metamethodsmap,&tchain);\r
MarkObject(_table_default_delegate,&tchain);\r
return _scratchpad;\r
}\r
\r
+RefTable::RefTable()\r
+{\r
+ AllocNodes(4);\r
+}\r
+\r
+void RefTable::Finalize()\r
+{\r
+ RefNode *nodes = (RefNode *)&_buckets[_numofslots];\r
+ for(SQUnsignedInteger n = 0; n < _numofslots; n++) {\r
+ nodes->obj = _null_;\r
+ nodes++;\r
+ }\r
+}\r
+\r
+RefTable::~RefTable()\r
+{\r
+ SQ_FREE(_buckets,_buffersize);\r
+}\r
+#ifndef NO_GARBAGE_COLLECTOR\r
+void RefTable::Mark(SQCollectable **chain)\r
+{\r
+ RefNode *nodes = (RefNode *)&_buckets[_numofslots];\r
+ for(SQUnsignedInteger n = 0; n < _numofslots; n++) {\r
+ if(type(nodes->obj) != OT_NULL) {\r
+ SQSharedState::MarkObject(nodes->obj,chain);\r
+ }\r
+ nodes++;\r
+ }\r
+}\r
+#endif\r
+void RefTable::AddRef(SQObject &obj)\r
+{\r
+ SQHash mainpos;\r
+ RefNode *prev;\r
+ RefNode *ref = Get(obj,mainpos,&prev,true);\r
+ ref->refs++;\r
+}\r
+\r
+SQBool RefTable::Release(SQObject &obj)\r
+{\r
+ SQHash mainpos;\r
+ RefNode *prev;\r
+ RefNode *ref = Get(obj,mainpos,&prev,false);\r
+ if(ref) {\r
+ if(--ref->refs == 0) {\r
+ ref->obj = _null_;\r
+ if(prev) {\r
+ prev->next = ref->next;\r
+ }\r
+ else {\r
+ _buckets[mainpos] = ref->next;\r
+ }\r
+ ref->next = _freelist;\r
+ _freelist = ref;\r
+ _slotused--;\r
+ //<<FIXME>>test for shrink?\r
+ return SQTrue;\r
+ }\r
+ }\r
+ return SQFalse;\r
+}\r
+\r
+void RefTable::Resize(SQUnsignedInteger size)\r
+{\r
+ RefNode **oldbuffer = _buckets;\r
+ RefNode *oldnodes = (RefNode *)&_buckets[_numofslots];\r
+ SQUnsignedInteger oldnumofslots = _numofslots;\r
+ SQUnsignedInteger oldbuffersize = _buffersize;\r
+ AllocNodes(size);\r
+ //rehash\r
+ for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {\r
+ if(type(oldnodes->obj) != OT_NULL) {\r
+ //add back;\r
+ assert(oldnodes->refs != 0);\r
+ RefNode *nn = Add(::HashObj(oldnodes->obj)&(_numofslots-1),oldnodes->obj);\r
+ nn->refs = oldnodes->refs; \r
+ oldnodes->obj = _null_;\r
+ }\r
+ oldnodes++;\r
+ }\r
+ SQ_FREE(oldbuffer,oldbuffersize);\r
+}\r
+\r
+RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)\r
+{\r
+ RefNode *t = _buckets[mainpos];\r
+ RefNode *newnode = _freelist;\r
+ newnode->obj = obj;\r
+ _buckets[mainpos] = newnode;\r
+ _freelist = _freelist->next;\r
+ newnode->next = t;\r
+ assert(newnode->refs == 0);\r
+ _slotused++;\r
+ return newnode;\r
+}\r
+\r
+RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)\r
+{\r
+ RefNode *ref;\r
+ mainpos = ::HashObj(obj)&(_numofslots-1);\r
+ *prev = NULL;\r
+ for (ref = _buckets[mainpos]; ref; ) {\r
+ if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))\r
+ break;\r
+ *prev = ref;\r
+ ref = ref->next;\r
+ }\r
+ if(ref == NULL && add) {\r
+ if(_numofslots == _slotused) {\r
+ Resize(_numofslots*2);\r
+ }\r
+ ref = Add(mainpos,obj);\r
+ }\r
+ return ref;\r
+}\r
+\r
+void RefTable::AllocNodes(SQUnsignedInteger size)\r
+{\r
+ RefNode **bucks;\r
+ RefNode *firstnode;\r
+ _buffersize = size * sizeof(RefNode *) + size * sizeof(RefNode);\r
+ bucks = (RefNode **)SQ_MALLOC(_buffersize);\r
+ firstnode = (RefNode *)&bucks[size];\r
+ RefNode *temp = firstnode;\r
+ SQUnsignedInteger n;\r
+ for(n = 0; n < size - 1; n++) {\r
+ bucks[n] = NULL;\r
+ temp->refs = 0;\r
+ new (&temp->obj) SQObjectPtr;\r
+ temp->next = temp+1;\r
+ temp++;\r
+ }\r
+ bucks[n] = NULL;\r
+ temp->refs = 0;\r
+ new (&temp->obj) SQObjectPtr;\r
+ temp->next = NULL;\r
+ _freelist = firstnode;\r
+ _buckets = bucks;\r
+ _slotused = 0;\r
+ _numofslots = size;\r
+}\r
//////////////////////////////////////////////////////////////////////////\r
//StringTable\r
/*\r
* http://www.lua.org/source/4.0.1/src_lstring.c.html\r
*/\r
\r
-SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)\r
-{\r
- SQInteger idx = (SQInteger)TranslateIndex(refpos);\r
- while(idx < _len){\r
- outkey = (SQInteger)idx;\r
- outval = SQInteger(_val[idx]);\r
- //return idx for the next iteration\r
- return ++idx;\r
- }\r
- //nothing to iterate anymore\r
- return -1;\r
-}\r
-\r
StringTable::StringTable()\r
{\r
AllocNodes(4);\r
SQString *StringTable::Add(const SQChar *news,SQInteger len)\r
{\r
if(len<0)\r
- len=scstrlen(news);\r
+ len = (SQInteger)scstrlen(news);\r
SQHash h = ::_hashstr(news,len)&(_numofslots-1);\r
SQString *s;\r
for (s = _strings[h]; s; s = s->_next){\r
{\r
StringTable();\r
~StringTable();\r
- //return a string obj if exists\r
- //so when there is a table query, if the string doesn't exists in the global state\r
- //it cannot be in a table so the result will be always null\r
- //SQString *get(const SQChar *news);\r
SQString *Add(const SQChar *,SQInteger len);\r
void Remove(SQString *);\r
private:\r
SQUnsignedInteger _slotused;\r
};\r
\r
+struct RefTable {\r
+ struct RefNode {\r
+ SQObjectPtr obj;\r
+ SQUnsignedInteger refs;\r
+ struct RefNode *next;\r
+ };\r
+ RefTable();\r
+ ~RefTable();\r
+ void AddRef(SQObject &obj);\r
+ SQBool Release(SQObject &obj);\r
+#ifndef NO_GARBAGE_COLLECTOR\r
+ void Mark(SQCollectable **chain);\r
+#endif\r
+ void Finalize();\r
+private:\r
+ RefNode *Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add);\r
+ RefNode *Add(SQHash mainpos,SQObject &obj);\r
+ void Resize(SQUnsignedInteger size);\r
+ void AllocNodes(SQUnsignedInteger size);\r
+ SQUnsignedInteger _numofslots;\r
+ SQUnsignedInteger _slotused;\r
+ SQUnsignedInteger _buffersize;\r
+ RefNode *_freelist;\r
+ RefNode **_buckets;\r
+};\r
+\r
#define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len)\r
#define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr)\r
\r
SQObjectPtrVec *_systemstrings;\r
SQObjectPtrVec *_types;\r
StringTable *_stringtable;\r
- SQObjectPtr _refs_table;\r
+ RefTable _refs_table;\r
SQObjectPtr _registry;\r
SQObjectPtr _constructoridx;\r
#ifndef NO_GARBAGE_COLLECTOR\r
SQCOMPILERERROR _compilererrorhandler;\r
SQPRINTFUNCTION _printfunc;\r
bool _debuginfo;\r
+ bool _notifyallexceptions;\r
private:\r
SQChar *_scratchpad;\r
SQInteger _scratchpadsize;\r
\r
inline SQHash _hashstr (const SQChar *s, size_t l)\r
{\r
- SQHash h = l; /* seed */\r
+ SQHash h = (SQHash)l; /* seed */\r
size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */\r
for (; l>=step; l-=step)\r
h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++));\r
\r
void SQTable::Remove(const SQObjectPtr &key)\r
{\r
- _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1));\r
+ \r
+ _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));\r
if (n) {\r
n->val = n->key = _null_;\r
_usednodes--;\r
\r
bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val)\r
{\r
- _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1));\r
+ if(type(key) == OT_NULL)\r
+ return false;\r
+ _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));\r
if (n) {\r
val = _realval(n->val);\r
return true;\r
}\r
bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)\r
{\r
- SQHash h = HashKey(key) & (_numofnodes - 1);\r
+ assert(type(key) != OT_NULL);\r
+ SQHash h = HashObj(key) & (_numofnodes - 1);\r
_HashNode *n = _Get(key, h);\r
if (n) {\r
n->val = val;\r
_HashNode *mp = &_nodes[h];\r
n = mp;\r
\r
+\r
//key not found I'll insert it\r
//main pos is not free\r
\r
- if(type(mp->key)!=OT_NULL) {\r
-\r
- _HashNode *othern; /* main position of colliding node */\r
+ if(type(mp->key) != OT_NULL) {\r
n = _firstfree; /* get a free place */\r
- if (mp > n && (othern = &_nodes[h]) != mp){\r
+ SQHash mph = HashObj(mp->key) & (_numofnodes - 1);\r
+ _HashNode *othern; /* main position of colliding node */\r
+ \r
+ if (mp > n && (othern = &_nodes[mph]) != mp){\r
/* yes; move colliding node into free position */\r
- while (othern->next != mp)\r
+ while (othern->next != mp){\r
+ assert(othern->next != NULL);\r
othern = othern->next; /* find previous */\r
+ }\r
othern->next = n; /* redo the chain with `n' in place of `mp' */\r
- *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */\r
+ n->key = mp->key;\r
+ n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */\r
+ n->next = mp->next;\r
+ mp->key = _null_;\r
+ mp->val = _null_;\r
mp->next = NULL; /* now `mp' is free */\r
}\r
else{\r
mp->key = key;\r
\r
for (;;) { /* correct `firstfree' */\r
- if (type(_firstfree->key) == OT_NULL) {\r
+ if (type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) {\r
mp->val = val;\r
_usednodes++;\r
return true; /* OK; table still has a free place */\r
\r
bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val)\r
{\r
- _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1));\r
+ _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));\r
if (n) {\r
n->val = val;\r
return true;\r
\r
#include "sqstring.h"\r
\r
-#define hashptr(p) (((SQHash)(reinterpret_cast<long>(p))) >> 3)\r
+\r
+#define hashptr(p) ((SQHash)(((SQInteger)p) >> 3))\r
+\r
+inline SQHash HashObj(const SQObjectPtr &key)\r
+{\r
+ switch(type(key)) {\r
+ case OT_STRING: return _string(key)->_hash;\r
+ case OT_FLOAT: return (SQHash)((SQInteger)_float(key));\r
+ case OT_BOOL: case OT_INTEGER: return (SQHash)((SQInteger)_integer(key));\r
+ default: return hashptr(key._unVal.pRefCounted);\r
+ }\r
+}\r
\r
struct SQTable : public SQDelegable \r
{\r
private:\r
struct _HashNode\r
{\r
+ _HashNode() { next = NULL; }\r
SQObjectPtr val;\r
SQObjectPtr key;\r
_HashNode *next;\r
#ifndef NO_GARBAGE_COLLECTOR \r
void Mark(SQCollectable **chain);\r
#endif\r
- inline SQHash HashKey(const SQObjectPtr &key)\r
- {\r
- switch(type(key)){\r
- case OT_STRING: return _string(key)->_hash;\r
- case OT_FLOAT: return (SQHash)((SQInteger)_float(key));\r
- case OT_INTEGER: return (SQHash)((SQInteger)_integer(key));\r
- default: return hashptr(key._unVal.pRefCounted);\r
- }\r
- }\r
inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash)\r
{\r
_HashNode *n = &_nodes[hash];\r
if(_rawval(n->key) == _rawval(key) && type(n->key) == type(key)){\r
return n;\r
}\r
- }while(n = n->next);\r
+ }while((n = n->next));\r
return NULL;\r
}\r
bool Get(const SQObjectPtr &key,SQObjectPtr &val);\r
_lasterror = _null_;\r
_errorhandler = _null_;\r
_debughook = _null_;\r
+ ci = NULL;\r
INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);\r
}\r
\r
case _SC('/'): mm=MT_DIV; break;\r
case _SC('*'): mm=MT_MUL; break;\r
case _SC('%'): mm=MT_MODULO; break;\r
+ default: mm = MT_ADD; assert(0); break; //shutup compiler\r
}\r
if(is_delegable(o1) && _delegable(o1)->_delegate) {\r
Push(o1);Push(o2);\r
return true;\r
}\r
}\r
- return true;\r
-\r
+ default:break; //shutup compiler\r
}\r
Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o));\r
return false;\r
Push(o1);Push(o2);\r
if(_delegable(o1)->_delegate)CallMetaMethod(_delegable(o1),MT_CMP,2,res);\r
break;\r
+ default: break; //shutup compiler\r
}\r
if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; }\r
- _RET_SUCCEED(_integer(res));\r
+ _RET_SUCCEED(_integer(res));\r
+ \r
}\r
else{\r
if(sq_isnumeric(o1) && sq_isnumeric(o2)){\r
}\r
}\r
default:\r
- scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),_rawval(o));\r
+ scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o));\r
}\r
res = SQString::Create(_ss(this),_spval);\r
- return;\r
}\r
\r
\r
bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest)\r
{\r
- switch(type(obj))\r
- {\r
- case OT_STRING:\r
- switch(type(str)){\r
- case OT_STRING: {\r
- SQInteger l=_string(str)->_len,ol=_string(obj)->_len;\r
- SQChar *s=_sp(rsl(l+ol+1));\r
- memcpy(s,_stringval(str),rsl(l));memcpy(s+l,_stringval(obj),rsl(ol));s[l+ol]=_SC('\0');\r
- break;\r
- }\r
- case OT_FLOAT:\r
- scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%g%s"),_float(str),_stringval(obj));\r
- break;\r
- case OT_INTEGER:\r
- scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%d%s"),_integer(str),_stringval(obj));\r
- break;\r
- default:\r
- Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj));\r
- return false;\r
- }\r
- dest=SQString::Create(_ss(this),_spval);\r
- break;\r
- case OT_FLOAT:\r
- scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%g"),_stringval(str),_float(obj));\r
- dest=SQString::Create(_ss(this),_spval);\r
- break;\r
- case OT_INTEGER:\r
- scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%d"),_stringval(str),_integer(obj));\r
- dest=SQString::Create(_ss(this),_spval);\r
- break;\r
- default:\r
- Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj));\r
- return false;\r
- }\r
+ SQObjectPtr a, b;\r
+ ToString(str, a);\r
+ ToString(obj, b);\r
+ SQInteger l = _string(a)->_len , ol = _string(b)->_len;\r
+ SQChar *s = _sp(rsl(l + ol + 1));\r
+ memcpy(s, _stringval(a), rsl(l)); \r
+ memcpy(s + l, _stringval(b), rsl(ol));\r
+ dest = SQString::Create(_ss(this), _spval, l + ol);\r
return true;\r
}\r
\r
bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger nargs,SQInteger stackbase,bool tailcall)\r
{\r
SQFunctionProto *func = _funcproto(closure->_function);\r
- //const SQInteger outerssize = func->_outervalues.size();\r
-\r
+ \r
const SQInteger paramssize = func->_parameters.size();\r
- const SQInteger oldtop = _top;\r
const SQInteger newtop = stackbase + func->_stacksize;\r
\r
\r
return false;\r
}\r
}\r
- \r
+\r
+ if(type(closure->_env) == OT_WEAKREF) {\r
+ _stack[stackbase] = _weakref(closure->_env)->_obj;\r
+ }\r
+\r
if (!tailcall) {\r
- PUSH_CALLINFO(this, CallInfo());\r
- ci->_etraps = 0;\r
- ci->_prevstkbase = stackbase - _stackbase;\r
- ci->_target = target;\r
- ci->_prevtop = _top - _stackbase;\r
- ci->_ncalls = 1;\r
- ci->_root = SQFalse;\r
+ CallInfo lc;\r
+ lc._etraps = 0;\r
+ lc._prevstkbase = stackbase - _stackbase;\r
+ lc._target = target;\r
+ lc._prevtop = _top - _stackbase;\r
+ lc._ncalls = 1;\r
+ lc._root = SQFalse;\r
+ PUSH_CALLINFO(this, lc);\r
}\r
else {\r
ci->_ncalls++;\r
+ if(ci->_vargs.size) PopVarArgs(ci->_vargs);\r
}\r
ci->_vargs.size = (nargs - paramssize);\r
- ci->_vargs.base = _vargsstack.size()-(nargs - paramssize);\r
+ ci->_vargs.base = _vargsstack.size()-(ci->_vargs.size);\r
ci->_closure._unVal.pClosure = closure;\r
ci->_closure._type = OT_CLOSURE;\r
ci->_iv = &func->_instructions;\r
if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure))\r
for(SQInteger i=0;i<ci->_ncalls;i++)\r
CallDebugHook(_SC('r'));\r
- \r
+ \r
SQBool broot = ci->_root;\r
SQInteger last_top = _top;\r
SQInteger target = ci->_target;\r
else retval = _null_;\r
}\r
else {\r
- if (_arg0 != MAX_FUNC_STACKSIZE)\r
- STK(target) = _stack[oldstackbase+_arg1];\r
- else\r
- STK(target) = _null_;\r
+ if(target != -1) { //-1 is when a class contructor ret value has to be ignored\r
+ if (_arg0 != MAX_FUNC_STACKSIZE)\r
+ STK(target) = _stack[oldstackbase+_arg1];\r
+ else\r
+ STK(target) = _null_;\r
+ }\r
}\r
\r
while (last_top >= _top) _stack[last_top--].Null();\r
\r
#define arg0 (_i_._arg0)\r
#define arg1 (_i_._arg1)\r
-#define sarg1 (*((SQInteger *)&_i_._arg1))\r
+#define sarg1 (*((SQInt32 *)&_i_._arg1))\r
#define arg2 (_i_._arg2)\r
#define arg3 (_i_._arg3)\r
-#define sarg3 (*((char *)&_i_._arg3))\r
+#define sarg3 ((SQInteger)*((signed char *)&_i_._arg3))\r
\r
SQRESULT SQVM::Suspend()\r
{\r
_generator(o1)->Resume(this, arg_2+1);\r
_FINISH(false);\r
}\r
+ default: \r
+ Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1));\r
}\r
- Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1));\r
return false; //cannot be hit(just to avoid warnings)\r
}\r
\r
{\r
SQInteger nouters;\r
SQClosure *closure = SQClosure::Create(_ss(this), func);\r
- if(nouters = func->_outervalues.size()) {\r
+ if((nouters = func->_outervalues.size())) {\r
closure->_outervalues.reserve(nouters);\r
for(SQInteger i = 0; i<nouters; i++) {\r
SQOuterVar &v = func->_outervalues[i];\r
{\r
SQClass *base = NULL;\r
SQObjectPtr attrs;\r
- if(baseclass != MAX_LITERALS) {\r
+ if(baseclass != -1) {\r
if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; }\r
base = _class(_stack._vals[_stackbase + baseclass]);\r
}\r
attrs = _stack._vals[_stackbase+attributes];\r
}\r
target = SQClass::Create(_ss(this),base);\r
+ if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) {\r
+ int nparams = 2;\r
+ SQObjectPtr ret;\r
+ Push(target); Push(attrs);\r
+ Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false);\r
+ Pop(nparams);\r
+ }\r
_class(target)->_attributes = attrs;\r
return true;\r
}\r
return true;\r
}\r
\r
-bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, ExecutionType et)\r
+bool SQVM::IsFalse(SQObjectPtr &o)\r
+{\r
+ if((type(o) & SQOBJECT_CANBEFALSE) && ( (type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0)) )\r
+ || (_integer(o) == 0) ) { //OT_NULL|OT_INTEGER|OT_BOOL\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+bool SQVM::GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target)\r
+{\r
+ switch(type(o)) {\r
+ case OT_TABLE: target = _table(o)->_delegate?SQObjectPtr(_table(o)->_delegate):_null_;\r
+ break;\r
+ case OT_CLASS: target = _class(o)->_base?_class(o)->_base:_null_;\r
+ break;\r
+ default:\r
+ Raise_Error(_SC("the %s type doesn't have a parent slot"), GetTypeName(o));\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+\r
+bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et)\r
{\r
if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; }\r
_nnativecalls++;\r
CallDebugHook(_SC('l'),arg1);\r
continue;\r
case _OP_LOAD: TARGET = (*ci->_literals)[arg1]; continue;\r
+ case _OP_LOADINT: TARGET = (SQInteger)arg1; continue;\r
case _OP_DLOAD: TARGET = (*ci->_literals)[arg1]; STK(arg2) = (*ci->_literals)[arg3];continue;\r
case _OP_TAILCALL:\r
temp_reg = STK(arg1);\r
outres = temp_reg;\r
return true;\r
}\r
- STK(ct_target) = temp_reg;\r
+ if(ct_target != -1) { //skip return value for contructors\r
+ STK(ct_target) = temp_reg;\r
+ }\r
}\r
break;\r
case OT_CLASS:{\r
- _GUARD(CreateClassInstance(_class(temp_reg),arg3,_stackbase+arg2,STK(ct_target)));\r
+ SQObjectPtr inst;\r
+ _GUARD(CreateClassInstance(_class(temp_reg),inst,temp_reg));\r
+ STK(ct_target) = inst;\r
+ ct_target = -1; //fakes return value target so that is not overwritten by the contructor\r
+ if(type(temp_reg) != OT_NULL) {\r
+ _stack[_stackbase+arg2] = inst;\r
+ goto common_call; //hard core spaghetti code(reissues the OP_CALL to invoke the contructor)\r
+ }\r
}\r
break;\r
case OT_TABLE:\r
continue;\r
case _OP_MOVE: TARGET = STK(arg1); continue;\r
case _OP_NEWSLOT:\r
- _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3)));\r
+ _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false));\r
if(arg0 != arg3) TARGET = STK(arg3);\r
continue;\r
case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue;\r
case _OP_NEWTABLE: TARGET = SQTable::Create(_ss(this), arg1); continue;\r
case _OP_NEWARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue;\r
case _OP_APPENDARRAY: _array(STK(arg0))->Append(COND_LITERAL); continue;\r
- case _OP_GETPARENT:\r
- switch(type(STK(arg1))) {\r
- case OT_TABLE: \r
- TARGET = _table(STK(arg1))->_delegate?SQObjectPtr(_table(STK(arg1))->_delegate):_null_;\r
- continue;\r
- case OT_CLASS: TARGET = _class(STK(arg1))->_base?_class(STK(arg1))->_base:_null_;\r
- continue;\r
- }\r
- Raise_Error(_SC("the %s type doesn't have a parent slot"), GetTypeName(STK(arg1)));\r
- SQ_THROW();\r
- continue;\r
+ case _OP_GETPARENT: _GUARD(GETPARENT_OP(STK(arg1),TARGET)); continue;\r
case _OP_COMPARITH: _GUARD(DerefInc(arg3, TARGET, STK((((SQUnsignedInteger)arg1&0xFFFF0000)>>16)), STK(arg2), STK(arg1&0x0000FFFF), false)); continue;\r
case _OP_COMPARITHL: _GUARD(LOCAL_INC(arg3, TARGET, STK(arg1), STK(arg2))); continue;\r
case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false));} continue;\r
case _OP_NOT: TARGET = (IsFalse(STK(arg1))?_true_:_false_); continue;\r
case _OP_BWNOT:\r
if(type(STK(arg1)) == OT_INTEGER) {\r
- TARGET = SQInteger(~_integer(STK(arg1)));\r
+ SQInteger t = _integer(STK(arg1));\r
+ TARGET = SQInteger(~t);\r
continue;\r
}\r
Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1)));\r
}\r
else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();}\r
if(Return(arg0, arg1, temp_reg)){\r
- assert(traps==0);\r
+ assert(traps == 0);\r
outres = temp_reg;\r
return true;\r
}\r
_etraps.push_back(SQExceptionTrap(_top,_stackbase, &ci->_iv->_vals[(ci->_ip-ci->_iv->_vals)+arg1], arg0)); traps++;\r
ci->_etraps++;\r
continue;\r
- case _OP_POPTRAP:{\r
- for(SQInteger i=0; i<arg0; i++) {\r
+ case _OP_POPTRAP:\r
+ for(SQInteger i = 0; i < arg0; i++) {\r
_etraps.pop_back(); traps--;\r
ci->_etraps--;\r
- }}\r
+ }\r
continue;\r
case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue;\r
case _OP_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue;\r
case _OP_NEWSLOTA:\r
- _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3)));\r
- _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1));\r
- if(arg0 != arg3) TARGET = STK(arg3);\r
+ bool bstatic = (arg0&NEW_SLOT_STATIC_FLAG)?true:false;\r
+ if(type(STK(arg1)) == OT_CLASS) {\r
+ if(type(_class(STK(arg1))->_metamethods[MT_NEWMEMBER]) != OT_NULL ) {\r
+ Push(STK(arg1)); Push(STK(arg2)); Push(STK(arg3));\r
+ Push((arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : _null_);\r
+ int nparams = 4;\r
+ if(Call(_class(STK(arg1))->_metamethods[MT_NEWMEMBER], nparams, _top - nparams, temp_reg,SQFalse)) {\r
+ Pop(nparams);\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+ _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),bstatic));\r
+ if((arg0&NEW_SLOT_ATTRIBUTES_FLAG)) {\r
+ _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1));\r
+ }\r
continue;\r
}\r
\r
SQInteger n = 0;\r
SQInteger last_top = _top;\r
if(ci) {\r
+ if(_ss(this)->_notifyallexceptions) CallErrorHandler(currerror);\r
+\r
if(traps) {\r
do {\r
if(ci->_etraps > 0) {\r
PopVarArgs(ci->_vargs);\r
POP_CALLINFO(this);\r
n++;\r
- }while(_callsstack.size());\r
+ } while(_callsstack.size());\r
+ }\r
+ else {\r
+ //call the hook\r
+ if(raiseerror && !_ss(this)->_notifyallexceptions)\r
+ CallErrorHandler(currerror);\r
}\r
- //call the hook\r
- CallErrorHandler(currerror);\r
//remove call stack until a C function is found or the cstack is empty\r
- if(ci) do{\r
+ if(ci) do {\r
SQBool exitafterthisone = ci->_root;\r
if(type(ci->_generator) == OT_GENERATOR) _generator(ci->_generator)->Kill();\r
_stackbase -= ci->_prevstkbase;\r
PopVarArgs(ci->_vargs);\r
POP_CALLINFO(this);\r
if( (ci && type(ci->_closure) != OT_CLOSURE) || exitafterthisone) break;\r
- }while(_callsstack.size());\r
+ } while(_callsstack.size());\r
\r
while(last_top >= _top) _stack[last_top--].Null();\r
}\r
assert(0);\r
}\r
\r
-bool SQVM::CreateClassInstance(SQClass *theclass, SQInteger nargs, SQInteger stackbase, SQObjectPtr &retval)\r
+bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor)\r
{\r
- SQObjectPtr constr;\r
- SQObjectPtr inst = theclass->CreateInstance();\r
- _stack[stackbase] = inst;\r
- if(theclass->Get(_ss(this)->_constructoridx,constr)) {\r
- if(!Call(constr,nargs,stackbase,constr))\r
- return false;\r
+ inst = theclass->CreateInstance();\r
+ if(!theclass->Get(_ss(this)->_constructoridx,constructor)) {\r
+ //if(!Call(constr,nargs,stackbase,constr,false))\r
+ // return false;\r
+ constructor = _null_;\r
}\r
- retval = inst;\r
return true;\r
}\r
\r
if(type(_errorhandler) != OT_NULL) {\r
SQObjectPtr out;\r
Push(_roottable); Push(error);\r
- Call(_errorhandler, 2, _top-2, out);\r
+ Call(_errorhandler, 2, _top-2, out,SQFalse);\r
Pop(2);\r
}\r
}\r
SQInteger nparams=5;\r
SQFunctionProto *func=_funcproto(_closure(ci->_closure)->_function);\r
Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name);\r
- Call(_debughook,nparams,_top-nparams,temp_reg);\r
+ Call(_debughook,nparams,_top-nparams,temp_reg,SQFalse);\r
Pop(nparams);\r
}\r
\r
}\r
\r
SQInteger tcs;\r
- if(tcs = nclosure->_typecheck.size()) {\r
+ if((tcs = nclosure->_typecheck.size())) {\r
for(SQInteger i = 0; i < nargs && i < tcs; i++)\r
if((nclosure->_typecheck[i] != -1) && !(type(_stack[stackbase+i]) & nclosure->_typecheck[i])) {\r
Raise_ParamTypeError(i,nclosure->_typecheck[i],type(_stack[stackbase+i]));\r
for (SQInteger i = 0; i < outers; i++) {\r
Push(nclosure->_outervalues[i]);\r
}\r
+\r
+ if(type(nclosure->_env) == OT_WEAKREF) {\r
+ _stack[stackbase] = _weakref(nclosure->_env)->_obj;\r
+ }\r
+\r
ci->_prevtop = (oldtop - oldstackbase);\r
SQInteger ret = (nclosure->_function)(this);\r
_nnativecalls--;\r
case OT_INSTANCE:\r
if(_instance(self)->Get(key,dest)) return true;\r
break;\r
+ default:break; //shut up compiler\r
}\r
if(FallBackGet(self,key,dest,raw)) return true;\r
\r
case OT_STRING:\r
if(sq_isnumeric(key)){\r
SQInteger n=tointeger(key);\r
- if(abs(n)<_string(self)->_len){\r
+ if(abs((int)n)<_string(self)->_len){\r
if(n<0)n=_string(self)->_len-n;\r
dest=SQInteger(_stringval(self)[n]);\r
return true;\r
bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target)\r
{\r
SQObjectPtr temp_reg;\r
+ SQObjectPtr newobj;\r
switch(type(self)){\r
case OT_TABLE:\r
- target = _table(self)->Clone();\r
+ newobj = _table(self)->Clone();\r
goto cloned_mt;\r
case OT_INSTANCE:\r
- target = _instance(self)->Clone(_ss(this));\r
+ newobj = _instance(self)->Clone(_ss(this));\r
cloned_mt:\r
- if(_delegable(target)->_delegate){\r
- Push(target);\r
+ if(_delegable(newobj)->_delegate){\r
+ Push(newobj);\r
Push(self);\r
- CallMetaMethod(_delegable(target),MT_CLONED,2,temp_reg);\r
+ CallMetaMethod(_delegable(newobj),MT_CLONED,2,temp_reg);\r
}\r
+ target = newobj;\r
return true;\r
case OT_ARRAY: \r
- target=_array(self)->Clone();\r
+ target = _array(self)->Clone();\r
return true;\r
default: return false;\r
}\r
}\r
\r
-bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val)\r
+bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)\r
{\r
if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; }\r
switch(type(self)) {\r
\r
break;}\r
case OT_CLASS: \r
- if(!_class(self)->NewSlot(key,val)) {\r
+ if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) {\r
if(_class(self)->_locked) {\r
Raise_Error(_SC("trying to modify a class that has already been instantiated"));\r
return false;\r
return true;\r
}\r
\r
-bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres)\r
+bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror)\r
{\r
#ifdef _DEBUG\r
SQInteger prevstackbase = _stackbase;\r
#endif\r
switch(type(closure)) {\r
case OT_CLOSURE:\r
- return Execute(closure, _top - nparams, nparams, stackbase,outres);\r
+ return Execute(closure, _top - nparams, nparams, stackbase,outres,raiseerror);\r
break;\r
case OT_NATIVECLOSURE:{\r
bool suspend;\r
\r
}\r
break;\r
- case OT_CLASS:\r
- return CreateClassInstance(_class(closure),nparams,stackbase,outres);\r
+ case OT_CLASS: {\r
+ SQObjectPtr constr;\r
+ SQObjectPtr temp;\r
+ CreateClassInstance(_class(closure),outres,constr);\r
+ if(type(constr) != OT_NULL) {\r
+ _stack[stackbase] = outres;\r
+ return Call(constr,nparams,stackbase,temp,raiseerror);\r
+ }\r
+ return true;\r
+ }\r
break;\r
default:\r
return false;\r
bool SQVM::CallMetaMethod(SQDelegable *del,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres)\r
{\r
SQObjectPtr closure;\r
- if(del->GetMetaMethod(mm, closure)) {\r
- if(Call(closure, nparams, _top - nparams, outres)) {\r
+ if(del->GetMetaMethod(this, mm, closure)) {\r
+ if(Call(closure, nparams, _top - nparams, outres, SQFalse)) {\r
Pop(nparams);\r
return true;\r
}\r
_top--;\r
}\r
\r
+void SQVM::Pop() {\r
+ _stack[--_top] = _null_;\r
+}\r
+\r
+void SQVM::Pop(SQInteger n) {\r
+ for(SQInteger i = 0; i < n; i++){\r
+ _stack[--_top] = _null_;\r
+ }\r
+}\r
+\r
+void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; }\r
+SQObjectPtr &SQVM::Top() { return _stack[_top-1]; }\r
+SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; }\r
+SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; }\r
+SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; }\r
\r
#ifdef _DEBUG_DUMP\r
void SQVM::dumpstack(SQInteger stackbase,bool dumpall)\r
SQInteger n=0;\r
scprintf(_SC("\n>>>>stack dump<<<<\n"));\r
CallInfo &ci=_callsstack.back();\r
- scprintf(_SC("IP: %d\n"),ci._ip);\r
+ scprintf(_SC("IP: %p\n"),ci._ip);\r
scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase);\r
scprintf(_SC("prev top: %d\n"),ci._prevtop);\r
for(SQInteger i=0;i<size;i++){\r
}\r
}\r
\r
+\r
+\r
#endif\r
SQInteger _extarget;\r
};\r
\r
+#define _INLINE \r
\r
#define STK(a) _stack._vals[_stackbase+(a)]\r
#define TARGET _stack._vals[_stackbase+arg0]\r
SQBool _root;\r
VarArgs _vargs;\r
};\r
-\r
+ \r
typedef sqvector<CallInfo> CallInfoVec;\r
public:\r
enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM };\r
SQVM(SQSharedState *ss);\r
~SQVM();\r
bool Init(SQVM *friendvm, SQInteger stacksize);\r
- bool Execute(SQObjectPtr &func, SQInteger target, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, ExecutionType et = ET_CALL);\r
- //start a native call return when the NATIVE closure returns(returns true if the vm has been suspended)\r
+ bool Execute(SQObjectPtr &func, SQInteger target, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL);\r
+ //starts a native call return when the NATIVE closure returns\r
bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger stackbase, bool tailcall, SQObjectPtr &retval,bool &suspend);\r
- //start a SQUIRREL call in the same "Execution loop"\r
+ //starts a SQUIRREL call in the same "Execution loop"\r
bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall);\r
- bool CreateClassInstance(SQClass *theclass, SQInteger nargs, SQInteger stackbase, SQObjectPtr &retval);\r
+ bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor);\r
//call a generic closure pure SQUIRREL or NATIVE\r
- bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres);\r
+ bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror);\r
SQRESULT Suspend();\r
\r
void CallDebugHook(SQInteger type,SQInteger forcedline=0);\r
bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, bool fetchroot);\r
bool FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw);\r
bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, bool fetchroot);\r
- bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val);\r
+ bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val,bool bstatic);\r
bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res);\r
bool Clone(const SQObjectPtr &self, SQObjectPtr &target);\r
bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res);\r
bool ArithMetaMethod(SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest);\r
bool Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval);\r
//new stuff\r
- inline bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\r
- inline bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\r
- inline bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1);\r
- inline bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res);\r
+ _INLINE bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\r
+ _INLINE bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\r
+ _INLINE bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1);\r
+ _INLINE bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res);\r
bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func);\r
bool GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &idx,CallInfo *ci);\r
bool CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs);\r
+ bool GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target);\r
//return true if the loop is finished\r
bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,bool &finished);\r
bool DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2);\r
- inline bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);\r
- inline bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);\r
- inline bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix);\r
+ _INLINE bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);\r
+ _INLINE bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);\r
+ _INLINE bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix);\r
void PopVarArgs(VarArgs &vargs);\r
#ifdef _DEBUG_DUMP\r
void dumpstack(SQInteger stackbase=-1, bool dumpall = false);\r
//stack functions for the api\r
void Remove(SQInteger n);\r
\r
- inline bool IsFalse(SQObjectPtr &o)\r
- {\r
- if((type(o) & SQOBJECT_CANBEFALSE) && ( (type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0)) )\r
- || (_integer(o) == 0) ) { //OT_NULL|OT_INTEGER|OT_BOOL\r
- return true;\r
- }\r
- return false;\r
- }\r
- inline void Pop() {\r
- _stack[--_top] = _null_;\r
- }\r
-\r
- inline void Pop(SQInteger n) {\r
- for(SQInteger i = 0; i < n; i++){\r
- _stack[--_top] = _null_;\r
- }\r
- }\r
-\r
- inline void Push(const SQObjectPtr &o) { _stack[_top++] = o; }\r
- inline SQObjectPtr &Top() { return _stack[_top-1]; }\r
- inline SQObjectPtr &PopGet() { return _stack[--_top]; }\r
- inline SQObjectPtr &GetUp(SQInteger n) { return _stack[_top+n]; }\r
- inline SQObjectPtr &GetAt(SQInteger n) { return _stack[n]; }\r
+ bool IsFalse(SQObjectPtr &o);\r
+ \r
+ void Pop();\r
+ void Pop(SQInteger n);\r
+ void Push(const SQObjectPtr &o);\r
+ SQObjectPtr &Top();\r
+ SQObjectPtr &PopGet();\r
+ SQObjectPtr &GetUp(SQInteger n);\r
+ SQObjectPtr &GetAt(SQInteger n);\r
\r
SQObjectPtrVec _stack;\r
SQObjectPtrVec _vargsstack;\r
SQInteger _top;\r
SQInteger _stackbase;\r
SQObjectPtr _roottable;\r
- //SQObjectPtr _thrownerror;\r
SQObjectPtr _lasterror;\r
SQObjectPtr _errorhandler;\r
SQObjectPtr _debughook;\r
#include "timer.hpp"
float game_time = 0;
+float real_time = 0;
Timer::Timer()
: period(0), cycle_start(0), cyclic(false)
#define __SUPERTUX_TIMER_H__
extern float game_time;
+extern float real_time;
/**
* Simple timer designed to be used in the update functions of objects
{
Sector* sector = titlesession->get_current_sector();
sector->deactivate();
+ Menu::set_current(NULL);
}
void
// 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__
#include <stdexcept>
#include <GL/gl.h>
-static inline void assert_gl(const char* message)
+static inline void check_gl_error(const char* message)
{
#ifdef DEBUG
GLenum error = glGetError();
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 << ")";
}
#endif
}
+static inline void assert_gl(const char* message)
+{
+#ifdef DEBUG
+ check_gl_error(message);
+#else
+ (void) message;
#endif
+}
+#endif
#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"
{
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;
}
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);
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;
void
World::save_state()
{
+ using namespace Scripting;
+
lisp::Writer writer(savegame_filename);
writer.start_list("supertux-savegame");
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");
void
World::load_state()
{
+ using namespace Scripting;
+
try {
lisp::Parser parser;
std::auto_ptr<lisp::Lisp> root (parser.parse(savegame_filename));
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;
}
std::string savegame_filename;
/// squirrel table that saves persistent state (about the world)
HSQOBJECT state_table;
+ HSQOBJECT world_thread;
static World* current_;
public:
#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
} 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;
#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"
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;
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;
}
void
WorldMap::save_state()
{
- HSQUIRRELVM vm = ScriptManager::instance->get_vm();
+ using namespace Scripting;
+
+ HSQUIRRELVM vm = global_vm;
int oldtop = sq_gettop(vm);
try {
void
WorldMap::load_state()
{
- HSQUIRRELVM vm = ScriptManager::instance->get_vm();
+ using namespace Scripting;
+
+ HSQUIRRELVM vm = global_vm;
int oldtop = sq_gettop(vm);
try {
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
Statistics total_stats;
+ typedef std::vector<HSQOBJECT> ScriptList;
+ ScriptList scripts;
+
public:
WorldMap(const std::string& filename);
~WorldMap();
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);
+#include <config.h>
+
#include "tree.hpp"
#include <iostream>
#include <sstream>
+#include <config.h>
+
#include "tree.hpp"
#include <iostream>
#include <sstream>
%{
+#include <config.h>
+
#include <math.h>
#include <stdlib.h>
#include <string.h>
+#include <config.h>
+
#include <iostream>
#include <fstream>
#include <vector>
%{
+#include <config.h>
#include <iostream>
#include <sstream>
+#include <config.h>
#include "tree.hpp"
BasicType BasicType::VOID("void");