From: Matthias Braun Date: Wed, 4 May 2005 17:15:32 +0000 (+0000) Subject: - More work on scripting interface X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=60908c905544776c376421b8d3e12eeb936c068f;p=supertux.git - More work on scripting interface - Moved remaining stuff from lib directory into src directory SVN-Revision: 2394 --- diff --git a/data/levels/test/foresttheme.stl b/data/levels/test/foresttheme.stl index e3e90bf36..632013457 100644 --- a/data/levels/test/foresttheme.stl +++ b/data/levels/test/foresttheme.stl @@ -4,7 +4,6 @@ (name "Forest Theme Test") (author "Marek Moeckel") (time 300) - (end-sequence-animation "none") (sector (name "main") (gravity 10) diff --git a/data/levels/test/noloktest.stl b/data/levels/test/noloktest.stl index b06c294dc..00e1cce64 100644 --- a/data/levels/test/noloktest.stl +++ b/data/levels/test/noloktest.stl @@ -4,7 +4,6 @@ (name "Nolok Test") (author "Marek") (time 500) - (end-sequence-animation "none") (sector (name "main") (gravity 10) diff --git a/lib/app/.cvsignore b/lib/app/.cvsignore deleted file mode 100644 index f8d9fd474..000000000 --- a/lib/app/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -.sconsign diff --git a/lib/app/gettext.h b/lib/app/gettext.h deleted file mode 100644 index 1d4d6bc7e..000000000 --- a/lib/app/gettext.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library 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 _LIBGETTEXT_H -#define _LIBGETTEXT_H 1 - -#include "globals.h" - -#define _(String) \ - SuperTux::dictionary_manager.get_dictionary().translate(String).c_str() -#define N_(id, id2, num) \ - SuperTux::dictionary_manager.get_dictionary().translate(id, di2, num).c_str() - -#endif /* _LIBGETTEXT_H */ diff --git a/lib/app/globals.cpp b/lib/app/globals.cpp deleted file mode 100644 index 53277787a..000000000 --- a/lib/app/globals.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2004 SuperTux Development Team, see AUTHORS for details -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. - -#include - -#include "app/globals.h" -#include "special/timer.h" - -namespace SuperTux { - -TinyGetText::DictionaryManager dictionary_manager; -TinyGetText::Dictionary* dictionary = 0; - -/** The datadir prefix prepended when loading game data file */ -std::string datadir; -std::string package_symbol_name; -std::string package_name; -std::string package_version; - -int screen_width = SCREEN_WIDTH; -int screen_height = SCREEN_HEIGHT; - -JoystickKeymap::JoystickKeymap() -{ - a_button = 0; - b_button = 1; - start_button = 2; - - x_axis = 0; - y_axis = 1; - - dead_zone = 4096; -} - -JoystickKeymap joystick_keymap; - -SDL_Surface * screen; -MouseCursor * mouse_cursor; - -#if 0 -int joystick_num = 0; -char* level_startup_file = 0; -bool launch_leveleditor_mode = false; -bool launch_worldmap_mode = false; -bool flip_levels_mode = false; -#endif - -/* SuperTux directory ($HOME/.supertux) and save directory($HOME/.supertux/save) */ -std::string user_dir; - -SDL_Joystick * js; - -/* Returns 1 for every button event, 2 for a quit event and 0 for no event. */ -int wait_for_event(SDL_Event& event, unsigned int min_delay, - unsigned int max_delay, bool empty_events) -{ - int i; - Timer maxdelay; - Timer mindelay; - - maxdelay.init(false); - mindelay.init(false); - - if(max_delay < min_delay) - max_delay = min_delay; - - maxdelay.start(max_delay); - mindelay.start(min_delay); - - if(empty_events) - while (SDL_PollEvent(&event)) - {} - - /* Handle events: */ - - for(i = 0; maxdelay.check() || !i; ++i) - { - while (SDL_PollEvent(&event)) - { - if(!mindelay.check()) - { - if (event.type == SDL_QUIT) - { - /* Quit event - quit: */ - return 2; - } - else if (event.type == SDL_KEYDOWN) - { - /* Keypress - skip intro: */ - - return 1; - } - else if (event.type == SDL_JOYBUTTONDOWN) - { - /* Fire button - skip intro: */ - - return 1; - } - else if (event.type == SDL_MOUSEBUTTONDOWN) - { - /* Mouse button - skip intro: */ - return 1; - } - } - } - SDL_Delay(10); - } - - return 0; -} - -} //namespace SuperTux diff --git a/lib/app/globals.h b/lib/app/globals.h deleted file mode 100644 index 850707d73..000000000 --- a/lib/app/globals.h +++ /dev/null @@ -1,75 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2004 Bill Kendrick -// Tobias Glaesser -// Ingo Ruhnke -// -// 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 SUPERTUX_GLOBALS_H -#define SUPERTUX_GLOBALS_H - -#include - -#include "SDL.h" - -#include "video/font.h" -#include "tinygettext.h" - -namespace SuperTux - { - - extern TinyGetText::DictionaryManager dictionary_manager; - extern TinyGetText::Dictionary* dictionary; - - class MouseCursor; - - extern std::string datadir; - - struct JoystickKeymap - { - int a_button; - int b_button; - int start_button; - - int x_axis; - int y_axis; - - int dead_zone; - - JoystickKeymap(); - }; - - extern JoystickKeymap joystick_keymap; - - extern MouseCursor * mouse_cursor; - -#define SCREEN_WIDTH 800 -#define SCREEN_HEIGHT 600 - - /** The number of the joystick that will be use in the game */ - extern int joystick_num; - - /* SuperTux directory ($HOME/.supertux) */ - extern std::string user_dir; - - extern SDL_Joystick * js; - - int wait_for_event(SDL_Event& event,unsigned int min_delay = 0, unsigned int max_delay = 0, bool empty_events = false); - -} //namespace SuperTux - -#endif /* SUPERTUX_GLOBALS_H */ diff --git a/lib/app/setup.cpp b/lib/app/setup.cpp deleted file mode 100644 index 4362c17a3..000000000 --- a/lib/app/setup.cpp +++ /dev/null @@ -1,261 +0,0 @@ -// $Id$ -// -// SuperTux - A Jump'n Run -// Copyright (C) 2000 Bill Kendrick -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#ifndef WIN32 -#include -#endif - -#include - -#include "globals.h" -#include "setup.h" - -using namespace SuperTux; - -#ifdef WIN32 -#define mkdir(dir, mode) mkdir(dir) -#endif - -/* Does the given file exist and is it accessible? */ -bool FileSystem::faccessible(const std::string& filename) -{ - struct stat filestat; - if (stat(filename.c_str(), &filestat) == -1) - { - return false; - } - else - { - if(S_ISREG(filestat.st_mode)) - return true; - else - return false; - } -} - -/* Can we write to this location? */ -bool FileSystem::fwriteable(const std::string& filename) -{ - FILE* fi; - fi = fopen(filename.c_str(), "wa"); - if (fi == NULL) - { - return false; - } - fclose(fi); - return true; -} - -/* Makes sure a directory is created in either the SuperTux home directory or the SuperTux base directory.*/ -bool FileSystem::fcreatedir(const std::string& relative_dir) -{ - std::string path = user_dir + "/" + relative_dir + "/"; - if(mkdir(path.c_str(),0755) != 0) - { - path = datadir + "/" + relative_dir + "/"; - if(mkdir(path.c_str(),0755) != 0) - { - return false; - } - else - { - return true; - } - } - else - { - return true; - } -} - -/* Get all names of sub-directories in a certain directory. */ -/* Returns the number of sub-directories found. */ -/* Note: The user has to free the allocated space. */ -std::set FileSystem::dsubdirs(const std::string &rel_path,const std::string& expected_file) -{ - DIR *dirStructP; - struct dirent *direntp; - std::set sdirs; - std::string filename; - std::string path = user_dir + "/" + rel_path; - - if((dirStructP = opendir(path.c_str())) != NULL) - { - while((direntp = readdir(dirStructP)) != NULL) - { - std::string absolute_filename; - struct stat buf; - - absolute_filename = path + "/" + direntp->d_name; - - if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode)) - { - if(!expected_file.empty()) - { - filename = path + "/" + direntp->d_name + "/" + expected_file; - if(!faccessible(filename)) - continue; - } - - sdirs.insert(direntp->d_name); - } - } - closedir(dirStructP); - } - - path = datadir + "/" + rel_path; - if((dirStructP = opendir(path.c_str())) != NULL) - { - while((direntp = readdir(dirStructP)) != NULL) - { - std::string absolute_filename; - struct stat buf; - - absolute_filename = path + "/" + direntp->d_name; - - if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode)) - { - if(!expected_file.empty()) - { - filename = path + "/" + direntp->d_name + "/" + expected_file; - if(!faccessible(filename.c_str())) - { - continue; - } - else - { - filename = user_dir + "/" + rel_path + "/" + direntp->d_name + "/" + expected_file; - if(faccessible(filename.c_str())) - continue; - } - } - - sdirs.insert(direntp->d_name); - } - } - closedir(dirStructP); - } - - return sdirs; -} - -std::set FileSystem::dfiles(const std::string& rel_path, const std::string& glob, const std::string& exception_str) -{ - DIR *dirStructP; - struct dirent *direntp; - std::set sdirs; - std::string path = user_dir + "/" + rel_path; - - if((dirStructP = opendir(path.c_str())) != NULL) - { - while((direntp = readdir(dirStructP)) != NULL) - { - std::string absolute_filename; - struct stat buf; - - absolute_filename = path + "/" + direntp->d_name; - - if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode)) - { - if(!exception_str.empty()) - { - if(strstr(direntp->d_name,exception_str.c_str()) != NULL) - continue; - } - if(!glob.empty()) - if(strstr(direntp->d_name,glob.c_str()) == NULL) - continue; - - sdirs.insert(direntp->d_name); - } - } - closedir(dirStructP); - } - - path = datadir + "/" + rel_path; - if((dirStructP = opendir(path.c_str())) != NULL) - { - while((direntp = readdir(dirStructP)) != NULL) - { - std::string absolute_filename; - struct stat buf; - - absolute_filename = path + "/" + direntp->d_name; - - if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode)) - { - if(!exception_str.empty()) - { - if(strstr(direntp->d_name,exception_str.c_str()) != NULL) - continue; - } - if(!glob.empty()) - if(strstr(direntp->d_name,glob.c_str()) == NULL) - continue; - - sdirs.insert(direntp->d_name); - } - } - closedir(dirStructP); - } - - return sdirs; -} - -std::string FileSystem::dirname(const std::string& filename) -{ - std::string::size_type p = filename.find_last_of('/'); - if(p == std::string::npos) - return ""; - - return filename.substr(0, p+1); -} - -std::set FileSystem::read_directory(const std::string& pathname) -{ - std::set dirnames; - - DIR* dir = opendir(pathname.c_str()); - if (dir) - { - struct dirent *direntp; - - while((direntp = readdir(dir))) - { - dirnames.insert(direntp->d_name); - } - - closedir(dir); - } - - return dirnames; -} diff --git a/lib/app/setup.h b/lib/app/setup.h deleted file mode 100644 index 98e947f8a..000000000 --- a/lib/app/setup.h +++ /dev/null @@ -1,45 +0,0 @@ -// $Id$ -// -// SuperTux - A Jump'n Run -// Copyright (C) 2000 Bill Kendrick -// -// 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 SUPERTUX_SETUP_H -#define SUPERTUX_SETUP_H - -#include -#include -#include - -namespace SuperTux { - -/// File system utility functions -struct FileSystem - { - static bool faccessible(const std::string& filename); - static bool fcreatedir(const std::string& relative_dir); - static bool fwriteable(const std::string& filename); - static std::set read_directory(const std::string& pathname); - static std::set dsubdirs(const std::string& rel_path, const std::string& expected_file); - static std::set dfiles(const std::string& rel_path, const std::string& glob, const std::string& exception_str); - - static std::string dirname(const std::string& filename); - }; - -} //namespace SuperTux - -#endif /*SUPERTUX_SETUP_H*/ - diff --git a/lib/app/tinygettext.cpp b/lib/app/tinygettext.cpp deleted file mode 100644 index dd73e8028..000000000 --- a/lib/app/tinygettext.cpp +++ /dev/null @@ -1,701 +0,0 @@ -// $Id$ -// -// TinyGetText - A small flexible gettext() replacement -// Copyright (C) 2004 Ingo Ruhnke -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include - -#include -#include -#include -#include -#include -#include -#include -#include "tinygettext.h" - -//#define TRANSLATION_DEBUG - -namespace TinyGetText { - -/** Convert \a which is in \a from_charset to \a to_charset and return it */ -std::string convert(const std::string& text, - const std::string& from_charset, - const std::string& to_charset) -{ - if (from_charset == to_charset) - return text; - - iconv_t cd = iconv_open(to_charset.c_str(), from_charset.c_str()); - - size_t in_len = text.length(); - size_t out_len = text.length()*3; // FIXME: cross fingers that this is enough - - char* out_orig = new char[out_len]; - char* in_orig = new char[in_len+1]; - strcpy(in_orig, text.c_str()); - - char* out = out_orig; - char* in = in_orig; - size_t out_len_temp = out_len; // iconv is counting down the bytes it has - // written from this... - - size_t retval = iconv(cd, &in, &in_len, &out, &out_len_temp); - out_len -= out_len_temp; // see above - if (retval == (size_t) -1) - { - std::cerr << strerror(errno) << std::endl; - std::cerr << "Error: conversion from " << from_charset - << " to " << to_charset << " went wrong: " << retval << std::endl; - return ""; - } - iconv_close(cd); - - std::string ret(out_orig, out_len); - delete[] out_orig; - delete[] in_orig; - return ret; -} - -bool has_suffix(const std::string& lhs, const std::string rhs) -{ - if (lhs.length() < rhs.length()) - return false; - else - return lhs.compare(lhs.length() - rhs.length(), rhs.length(), rhs) == 0; -} - -bool has_prefix(const std::string& lhs, const std::string rhs) -{ - if (lhs.length() < rhs.length()) - return false; - else - return lhs.compare(0, rhs.length(), rhs) == 0; -} - -int plural1(int ) { return 0; } -int plural2_1(int n) { return (n != 1); } -int plural2_2(int n) { return (n > 1); } -int plural3_lv(int n) { return (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); } -int plural3_ga(int n) { return n==1 ? 0 : n==2 ? 1 : 2; } -int plural3_lt(int n) { return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); } -int plural3_1(int n) { return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } -int plural3_sk(int n) { return (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; } -int plural3_pl(int n) { return (n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } -int plural3_sl(int n) { return (n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3); } - -/** Language Definitions */ -//*{ -LanguageDef lang_hu("hu", "Hungarian", 1, plural1); // "nplurals=1; plural=0;" -LanguageDef lang_ja("ja", "Japanese", 1, plural1); // "nplurals=1; plural=0;" -LanguageDef lang_ko("ko", "Korean", 1, plural1); // "nplurals=1; plural=0;" -LanguageDef lang_tr("tr", "Turkish", 1, plural1); // "nplurals=1; plural=0;" -LanguageDef lang_da("da", "Danish", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_nl("nl", "Dutch", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_en("en", "English", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_fo("fo", "Faroese", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_de("de", "German", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_nb("nb", "Norwegian Bokmal", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_no("no", "Norwegian", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_nn("nn", "Norwegian Nynorsk", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_sv("sv", "Swedish", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_et("et", "Estonian", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_fi("fi", "Finnish", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_el("el", "Greek", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_he("he", "Hebrew", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_it("it", "Italian", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_pt("pt", "Portuguese", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_es("es", "Spanish", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_eo("eo", "Esperanto", 2, plural2_1); // "nplurals=2; plural=(n != 1);" -LanguageDef lang_fr("fr", "French", 2, plural2_2); // "nplurals=2; plural=(n > 1);" -LanguageDef lang_pt_BR("pt_BR", "Brazilian", 2, plural2_2); // "nplurals=2; plural=(n > 1);" -LanguageDef lang_lv("lv", "Latvian", 3, plural3_lv); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);" -LanguageDef lang_ga("ga", "Irish", 3, plural3_ga); // "nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;" -LanguageDef lang_lt("lt", "Lithuanian", 3, plural3_lt); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);" -LanguageDef lang_hr("hr", "Croatian", 3, plural3_1); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" -LanguageDef lang_cs("cs", "Czech", 3, plural3_1); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" -LanguageDef lang_ru("ru", "Russian", 3, plural3_1); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" -LanguageDef lang_uk("uk", "Ukrainian", 3, plural3_1); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" -LanguageDef lang_sk("sk", "Slovak", 3, plural3_sk); // "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" -LanguageDef lang_pl("pl", "Polish", 3, plural3_pl); // "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); -LanguageDef lang_sl("sl", "Slovenian", 3, plural3_sl); // "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);" -//*} - -LanguageDef& -get_language_def(const std::string& name) -{ - if (name == "hu") return lang_hu; - else if (name == "ja") return lang_ja; - else if (name == "ko") return lang_ko; - else if (name == "tr") return lang_tr; - else if (name == "da") return lang_da; - else if (name == "nl") return lang_nl; - else if (name == "en") return lang_en; - else if (name == "fo") return lang_fo; - else if (name == "de") return lang_de; - else if (name == "nb") return lang_nb; - else if (name == "no") return lang_no; - else if (name == "nn") return lang_nn; - else if (name == "sv") return lang_sv; - else if (name == "et") return lang_et; - else if (name == "fi") return lang_fi; - else if (name == "el") return lang_el; - else if (name == "he") return lang_he; - else if (name == "it") return lang_it; - else if (name == "pt") return lang_pt; - else if (name == "es") return lang_es; - else if (name == "eo") return lang_eo; - else if (name == "fr") return lang_fr; - else if (name == "pt_BR") return lang_pt_BR; - else if (name == "lv") return lang_lv; - else if (name == "ga") return lang_ga; - else if (name == "lt") return lang_lt; - else if (name == "hr") return lang_hr; - else if (name == "cs") return lang_cs; - else if (name == "ru") return lang_ru; - else if (name == "uk") return lang_uk; - else if (name == "sk") return lang_sk; - else if (name == "pl") return lang_pl; - else if (name == "sl") return lang_sl; - else return lang_en; -} - -DictionaryManager::DictionaryManager() - : current_dict(&empty_dict) -{ - parseLocaleAliases(); - // setup language from environment vars - const char* lang = getenv("LC_ALL"); - if(!lang) - lang = getenv("LC_MESSAGES"); - if(!lang) - lang = getenv("LANG"); - - if(lang) - set_language(lang); -} - -void -DictionaryManager::parseLocaleAliases() -{ - // try to parse language alias list - std::ifstream in("/usr/share/locale/locale.alias"); - - char c = ' '; - while(in.good() && !in.eof()) { - while(isspace(c) && !in.eof()) - in.get(c); - - if(c == '#') { // skip comments - while(c != '\n' && !in.eof()) - in.get(c); - continue; - } - - std::string alias; - while(!isspace(c) && !in.eof()) { - alias += c; - in.get(c); - } - while(isspace(c) && !in.eof()) - in.get(c); - std::string language; - while(!isspace(c) && !in.eof()) { - language += c; - in.get(c); - } - - if(in.eof()) - break; - set_language_alias(alias, language); - } -} - -Dictionary& -DictionaryManager::get_dictionary(const std::string& spec) -{ - std::string lang = get_language_from_spec(spec); - Dictionaries::iterator i = dictionaries.find(get_language_from_spec(lang)); - if (i != dictionaries.end()) - { - return i->second; - } - else // Dictionary for languages lang isn't loaded, so we load it - { - //std::cout << "get_dictionary: " << lang << std::endl; - Dictionary& dict = dictionaries[lang]; - - dict.set_language(get_language_def(lang)); - if(charset != "") - dict.set_charset(charset); - - for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p) - { - DIR* dir = opendir(p->c_str()); - if (!dir) - { - std::cerr << "Error: opendir() failed on " << *p << std::endl; - } - else - { - struct dirent* ent; - while((ent = readdir(dir))) - { - if (std::string(ent->d_name) == lang + ".po") - { - std::string pofile = *p + "/" + ent->d_name; - std::ifstream in(pofile.c_str()); - if (!in) - { - std::cerr << "Error: Failure file opening: " << pofile << std::endl; - } - else - { - read_po_file(dict, in); - } - } - } - closedir(dir); - } - } - - return dict; - } -} - -std::set -DictionaryManager::get_languages() -{ - std::set languages; - - for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p) - { - DIR* dir = opendir(p->c_str()); - if (!dir) - { - std::cerr << "Error: opendir() failed on " << *p << std::endl; - } - else - { - struct dirent* ent; - while((ent = readdir(dir))) - { - if (has_suffix(ent->d_name, ".po")) - { - std::string filename = ent->d_name; - languages.insert(filename.substr(0, filename.length()-3)); - } - } - closedir(dir); - } - } - return languages; -} - -void -DictionaryManager::set_language(const std::string& lang) -{ - language = get_language_from_spec(lang); - current_dict = & (get_dictionary(language)); -} - -void -DictionaryManager::set_charset(const std::string& charset) -{ - dictionaries.clear(); // changing charset invalidates cache - this->charset = charset; - set_language(language); -} - -void -DictionaryManager::set_language_alias(const std::string& alias, - const std::string& language) -{ - language_aliases.insert(std::make_pair(alias, language)); -} - -std::string -DictionaryManager::get_language_from_spec(const std::string& spec) -{ - std::string lang = spec; - Aliases::iterator i = language_aliases.find(lang); - if(i != language_aliases.end()) { - lang = i->second; - } - - std::string::size_type s = lang.find_first_of("_."); - if(s == std::string::npos) - return lang; - - return std::string(lang, 0, s); -} - -void -DictionaryManager::add_directory(const std::string& pathname) -{ - dictionaries.clear(); // adding directories invalidates cache - search_path.push_back(pathname); - set_language(language); -} - -//--------------------------------------------------------------------------- - -Dictionary::Dictionary(const LanguageDef& language_, const std::string& charset_) - : language(language_), charset(charset_) -{ -} - -Dictionary::Dictionary() - : language(lang_en) -{ -} - -std::string -Dictionary::get_charset() const -{ - return charset; -} - -void -Dictionary::set_charset(const std::string& charset_) -{ - charset = charset_; -} - -void -Dictionary::set_language(const LanguageDef& lang) -{ - language = lang; -} - -std::string -Dictionary::translate(const std::string& msgid, const std::string& msgid2, int num) -{ - PluralEntries::iterator i = plural_entries.find(msgid); - std::map& msgstrs = i->second; - - if (i != plural_entries.end() && !msgstrs.empty()) - { - int g = language.plural(num); - std::map::iterator j = msgstrs.find(g); - if (j != msgstrs.end()) - { - return j->second; - } - else - { - // Return the first translation, in case we can't translate the specific number - return msgstrs.begin()->second; - } - } - else - { -#ifdef TRANSLATION_DEBUG - std::cerr << "Warning: Couldn't translate: " << msgid << std::endl; - std::cerr << "Candidates: " << std::endl; - for (PluralEntries::iterator i = plural_entries.begin(); i != plural_entries.end(); ++i) - std::cout << "'" << i->first << "'" << std::endl; -#endif - - if (plural2_1(num)) // default to english rules - return msgid2; - else - return msgid; - } -} - -std::string -Dictionary::translate(const std::string& msgid) -{ - Entries::iterator i = entries.find(msgid); - if (i != entries.end() && !i->second.empty()) - { - return i->second; - } - else - { -#ifdef TRANSLATION_DBEUG - std::cout << "Error: Couldn't translate: " << msgid << std::endl; -#endif - return msgid; - } -} - -void -Dictionary::add_translation(const std::string& msgid, const std::string& , - const std::map& msgstrs) -{ - // Do we need msgid2 for anything? its after all supplied to the - // translate call, so we just throw it away - plural_entries[msgid] = msgstrs; -} - -void -Dictionary::add_translation(const std::string& msgid, const std::string& msgstr) -{ - entries[msgid] = msgstr; -} - -class POFileReader -{ -private: - struct Token - { - std::string keyword; - std::string content; - }; - - Dictionary& dict; - - std::string from_charset; - std::string to_charset; - - std::string current_msgid; - std::string current_msgid_plural; - std::map msgstr_plural; - - int line_num; - - enum { WANT_MSGID, WANT_MSGSTR, WANT_MSGSTR_PLURAL, WANT_MSGID_PLURAL } state; - -public: - POFileReader(std::istream& in, Dictionary& dict_) - : dict(dict_) - { - state = WANT_MSGID; - line_num = 0; - tokenize_po(in); - } - - void parse_header(const std::string& header) - { - // Seperate the header in lines - typedef std::vector Lines; - Lines lines; - - std::string::size_type start = 0; - for(std::string::size_type i = 0; i < header.length(); ++i) - { - if (header[i] == '\n') - { - lines.push_back(header.substr(start, i - start)); - start = i+1; - } - } - - for(Lines::iterator i = lines.begin(); i != lines.end(); ++i) - { - if (has_prefix(*i, "Content-Type: text/plain; charset=")) { - from_charset = i->substr(strlen("Content-Type: text/plain; charset=")); - } - } - - if (from_charset.empty() || from_charset == "CHARSET") - { - std::cerr << "Error: Charset not specified for .po, fallback to ISO-8859-1" << std::endl; - from_charset = "ISO-8859-1"; - } - - to_charset = dict.get_charset(); - if (to_charset.empty()) - { // No charset requested from the dict, so we use the one from the .po - to_charset = from_charset; - dict.set_charset(from_charset); - } - } - - void add_token(const Token& token) - { - switch(state) - { - case WANT_MSGID: - if (token.keyword == "msgid") - { - current_msgid = token.content; - state = WANT_MSGID_PLURAL; - } - else if (token.keyword.empty()) - { - //std::cerr << "Got EOF, everything looks ok." << std::endl; - } - else - { - std::cerr << "tinygettext: expected 'msgid' keyword, got " << token.keyword - << " at line " << line_num << std::endl; - } - break; - - case WANT_MSGID_PLURAL: - if (token.keyword == "msgid_plural") - { - current_msgid_plural = token.content; - state = WANT_MSGSTR_PLURAL; - } - else - { - state = WANT_MSGSTR; - add_token(token); - } - break; - - case WANT_MSGSTR: - if (token.keyword == "msgstr") - { - if (current_msgid == "") - { // .po Header is hidden in the msgid with the empty string - parse_header(token.content); - } - else - { - dict.add_translation(current_msgid, convert(token.content, from_charset, to_charset)); - } - state = WANT_MSGID; - } - else - { - std::cerr << "tinygettext: expected 'msgstr' keyword, got " << token.keyword - << " at line " << line_num << std::endl; - } - break; - - case WANT_MSGSTR_PLURAL: - if (has_prefix(token.keyword, "msgstr[")) - { - int num; - if (sscanf(token.keyword.c_str(), "msgstr[%d]", &num) != 1) - { - std::cerr << "Error: Couldn't parse: " << token.keyword << std::endl; - } - else - { - msgstr_plural[num] = convert(token.content, from_charset, to_charset); - } - } - else - { - dict.add_translation(current_msgid, current_msgid_plural, msgstr_plural); - - state = WANT_MSGID; - add_token(token); - } - break; - } - } - - inline int getchar(std::istream& in) - { - int c = in.get(); - if (c == '\n') - line_num += 1; - return c; - } - - void tokenize_po(std::istream& in) - { - enum State { READ_KEYWORD, - READ_CONTENT, - READ_CONTENT_IN_STRING, - SKIP_COMMENT }; - - State state = READ_KEYWORD; - int c; - Token token; - - while((c = getchar(in)) != EOF) - { - //std::cout << "Lexing char: " << char(c) << " " << state << std::endl; - switch(state) - { - case READ_KEYWORD: - if (c == '#') - { - state = SKIP_COMMENT; - } - else - { - // Read a new token - token = Token(); - - do { // Read keyword - token.keyword += c; - } while((c = getchar(in)) != EOF && !isspace(c)); - in.unget(); - - state = READ_CONTENT; - } - break; - - case READ_CONTENT: - while((c = getchar(in)) != EOF) - { - if (c == '"') { - // Found start of content - state = READ_CONTENT_IN_STRING; - break; - } else if (isspace(c)) { - // skip - } else { // Read something that may be a keyword - in.unget(); - state = READ_KEYWORD; - add_token(token); - break; - } - } - break; - - case READ_CONTENT_IN_STRING: - if (c == '\\') { - c = getchar(in); - if (c != EOF) - { - if (c == 'n') token.content += '\n'; - else if (c == 't') token.content += '\t'; - else if (c == 'r') token.content += '\r'; - else if (c == '"') token.content += '"'; - else - { - std::cout << "Unhandled escape character: " << char(c) << std::endl; - } - } - else - { - std::cout << "Unterminated string" << std::endl; - } - } else if (c == '"') { // Content string is terminated - state = READ_CONTENT; - } else { - token.content += c; - } - break; - - case SKIP_COMMENT: - if (c == '\n') - state = READ_KEYWORD; - break; - } - } - add_token(token); - } -}; - -void read_po_file(Dictionary& dict_, std::istream& in) -{ - POFileReader reader(in, dict_); -} - -} // namespace TinyGetText - -/* EOF */ diff --git a/lib/app/tinygettext.h b/lib/app/tinygettext.h deleted file mode 100644 index 207ce28a6..000000000 --- a/lib/app/tinygettext.h +++ /dev/null @@ -1,153 +0,0 @@ -// $Id$ -// -// TinyGetText - A small flexible gettext() replacement -// Copyright (C) 2004 Ingo Ruhnke -// -// 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 HEADER_TINYGETTEXT_H -#define HEADER_TINYGETTEXT_H - -#include -#include -#include -#include - -namespace TinyGetText { - -typedef int (*PluralFunc)(int n); - -struct LanguageDef { - const char* code; - const char* name; - int nplural; - PluralFunc plural; - - LanguageDef(const char* code_, const char* name_, int nplural_, PluralFunc plural_) - : code(code_), name(name_), nplural(nplural_), plural(plural_) - {} -}; - -/** A simple dictionary class that mimics gettext() behaviour. Each - Dictionary only works for a single language, for managing multiple - languages and .po files at once use the DictionaryManager. */ -class Dictionary -{ -private: - typedef std::map Entries; - Entries entries; - - typedef std::map > PluralEntries; - PluralEntries plural_entries; - - LanguageDef language; - std::string charset; -public: - /** */ - Dictionary(const LanguageDef& language_, const std::string& charset = ""); - - Dictionary(); - - /** Return the charset used for this dictionary */ - std::string get_charset() const; - - /** Set a charset for this dictionary, this will NOT convert stuff, - it is for information only, you have to convert stuff yourself - when you add it with \a add_translation() */ - void set_charset(const std::string& charset); - - /** Set the language that is used for this dictionary, this is - mainly needed to evaluate plural forms */ - void set_language(const LanguageDef& lang); - - /** Translate the string \a msgid to its correct plural form, based - on the number of items given by \a num. \a msgid2 is \a msgid in - plural form. */ - std::string translate(const std::string& msgid, const std::string& msgid2, int num); - - /** Translate the string \a msgid. */ - std::string translate(const std::string& msgid); - - /** Add a translation from \a msgid to \a msgstr to the dictionary, - where \a msgid is the singular form of the message, msgid2 the - plural form and msgstrs a table of translations. The right - translation will be calculated based on the \a num argument to - translate(). */ - void add_translation(const std::string& msgid, const std::string& msgid2, - const std::map& msgstrs); - - /** Add a translation from \a msgid to \a msgstr to the - dictionary */ - void add_translation(const std::string& msgid, const std::string& msgstr); -}; - -/** Manager class for dictionaries, you give it a bunch of directories - with .po files and it will then automatically load the right file - on demand depending on which language was set. */ -class DictionaryManager -{ -private: - typedef std::map Dictionaries; - Dictionaries dictionaries; - typedef std::vector SearchPath; - SearchPath search_path; - typedef std::map Aliases; - Aliases language_aliases; - std::string charset; - std::string language; - Dictionary* current_dict; - Dictionary empty_dict; - -public: - DictionaryManager(); - - /** Return the currently active dictionary, if none is set, an empty - dictionary is returned. */ - Dictionary& get_dictionary() - { return *current_dict; } - - /** Get dictionary for lang */ - Dictionary& get_dictionary(const std::string& langspec); - - /** Set a language based on a four? letter country code */ - void set_language(const std::string& langspec); - - /** Set a charset that will be set on the returned dictionaries */ - void set_charset(const std::string& charset); - - /** Define an alias for a language */ - void set_language_alias(const std::string& alias, const std::string& lang); - - /** Add a directory to the search path for dictionaries */ - void add_directory(const std::string& pathname); - - /** Return a set of the available languages in their country code */ - std::set get_languages(); - -private: - void parseLocaleAliases(); - /// returns the language part in a language spec (like de_DE.UTF-8 -> de) - std::string get_language_from_spec(const std::string& spec); -}; - -/** Read the content of the .po file given as \a in into the - dictionary given as \a dict */ -void read_po_file(Dictionary& dict, std::istream& in); -LanguageDef& get_language_def(const std::string& name); - -} // namespace TinyGetText - -#endif - -/* EOF */ diff --git a/lib/lisp/.cvsignore b/lib/lisp/.cvsignore deleted file mode 100644 index f8d9fd474..000000000 --- a/lib/lisp/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -.sconsign diff --git a/lib/math/.cvsignore b/lib/math/.cvsignore deleted file mode 100644 index f8d9fd474..000000000 --- a/lib/math/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -.sconsign diff --git a/lib/math/aatriangle.h b/lib/math/aatriangle.h deleted file mode 100644 index 97cbae800..000000000 --- a/lib/math/aatriangle.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef __AATRIANGLE_H__ -#define __AATRIANGLE_H__ - -#include "rectangle.h" - -namespace SuperTux -{ - -/** - * An axis aligned triangle (ie. a triangle where 2 sides are parallel to the x- - * and y-axis. - */ -class AATriangle : public Rectangle -{ -public: - /** Directions: - * - * SOUTHEWEST NORTHEAST SOUTHEAST NORTHWEST - * * or *---* or * or *---* - * | \ \ | / | | / - * | \ \ | / | | / - * *---* * *---* * - * - * Deform flags: (see docs/aatriangletypes.png for details) - */ - enum Direction { - SOUTHWEST = 0, - NORTHEAST, - SOUTHEAST, - NORTHWEST, - DIRECTION_MASK = 0x0003, - DEFORM1 = 0x0010, - DEFORM2 = 0x0020, - DEFORM3 = 0x0030, - DEFORM4 = 0x0040, - DEFORM_MASK = 0x0070 - }; - - AATriangle() - : dir(SOUTHWEST) - { - } - AATriangle(const Vector& v1, const Vector& v2, int newdir) - : Rectangle(v1, v2), dir(newdir) - { - } - - int dir; -}; - -} - -#endif - diff --git a/lib/math/physic.cpp b/lib/math/physic.cpp deleted file mode 100644 index 6276a0918..000000000 --- a/lib/math/physic.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2004 Tobias Glaesser -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. - -#include - -#include - -#include "math/physic.h" - -using namespace SuperTux; - -Physic::Physic() - : ax(0), ay(0), vx(0), vy(0), gravity_enabled(true) -{ -} - -Physic::~Physic() -{ -} - -void -Physic::reset() -{ - ax = ay = vx = vy = 0; - gravity_enabled = true; -} - -void -Physic::set_velocity_x(float nvx) -{ - vx = nvx; -} - -void -Physic::set_velocity_y(float nvy) -{ - vy = -nvy; -} - -void -Physic::set_velocity(float nvx, float nvy) -{ - vx = nvx; - vy = -nvy; -} - -void Physic::inverse_velocity_x() -{ -vx = -vx; -} - -void Physic::inverse_velocity_y() -{ -vy = -vy; -} - -float -Physic::get_velocity_x() -{ - return vx; -} - -float -Physic::get_velocity_y() -{ - return -vy; -} - -void -Physic::set_acceleration_x(float nax) -{ - ax = nax; -} - -void -Physic::set_acceleration_y(float nay) -{ - ay = -nay; -} - -void -Physic::set_acceleration(float nax, float nay) -{ - ax = nax; - ay = -nay; -} - -float -Physic::get_acceleration_x() -{ - return ax; -} - -float -Physic::get_acceleration_y() -{ - return -ay; -} - -void -Physic::enable_gravity(bool enable_gravity) -{ - gravity_enabled = enable_gravity; -} - -Vector -Physic::get_movement(float elapsed_time) -{ - float grav = gravity_enabled ? 1000 : 0; - - Vector result( - vx * elapsed_time + ax * elapsed_time * elapsed_time, - vy * elapsed_time + (ay + grav) * elapsed_time * elapsed_time - ); - vx += ax * elapsed_time; - vy += (ay + grav) * elapsed_time; - - return result; -} - diff --git a/lib/math/physic.h b/lib/math/physic.h deleted file mode 100644 index 71d7ccd44..000000000 --- a/lib/math/physic.h +++ /dev/null @@ -1,83 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2004 Tobias Glaesser -// -// 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 SUPERTUX_PHYSIC_H -#define SUPERTUX_PHYSIC_H - -#include "math/vector.h" - -namespace SuperTux - { - - /// Physics engine. - /** This is a very simplistic physics engine handling accelerated and constant - * movement along with gravity. - */ - class Physic - { - public: - Physic(); - ~Physic(); - - /// Resets all velocities and accelerations to 0. - void reset(); - - /// Sets velocity to a fixed value. - void set_velocity(float vx, float vy); - - void set_velocity_x(float vx); - void set_velocity_y(float vy); - - /// Velocities invertion. - void inverse_velocity_x(); - void inverse_velocity_y(); - - float get_velocity_x(); - float get_velocity_y(); - - /// Set acceleration. - /** Sets acceleration applied to the object. (Note that gravity is - * eventually added to the vertical acceleration) - */ - void set_acceleration(float ax, float ay); - - void set_acceleration_x(float ax); - void set_acceleration_y(float ay); - - float get_acceleration_x(); - float get_acceleration_y(); - - /// Enables or disables handling of gravity. - void enable_gravity(bool gravity_enabled); - - Vector get_movement(float elapsed_time); - - private: - /// horizontal and vertical acceleration - float ax, ay; - /// horizontal and vertical velocity - float vx, vy; - /// should we respect gravity in out calculations? - bool gravity_enabled; - }; - -} //namespace SuperTux - -#endif /*SUPERTUX_PHYSIC_H*/ diff --git a/lib/math/rectangle.h b/lib/math/rectangle.h deleted file mode 100644 index e0254bc84..000000000 --- a/lib/math/rectangle.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef __RECTANGLE_H__ -#define __RECTANGLE_H__ - -#include -#include "vector.h" - -namespace SuperTux -{ - -/** This class represents a rectangle. - * (Implementation Note) We're using upper left and lower right point instead of - * upper left and width/height here, because that makes the collision dectection - * a little bit efficienter. - */ -class Rectangle -{ -public: - Rectangle() - { } - - Rectangle(const Vector& np1, const Vector& np2) - : p1(np1), p2(np2) - { - } - - Rectangle(float x1, float y1, float x2, float y2) - : p1(x1, y1), p2(x2, y2) - { - assert(p1.x <= p2.x && p1.y <= p2.y); - } - - float get_width() const - { return p2.x - p1.x; } - - float get_height() const - { return p2.y - p1.y; } - - Vector get_middle() const - { return Vector((p1.x+p2.x)/2, (p1.y+p2.y)/2); } - - void set_pos(const Vector& v) - { - move(v-p1); - } - - void set_height(float height) - { - p2.y = p1.y + height; - } - void set_width(float width) - { - p2.x = p1.x + width; - } - void set_size(float width, float height) - { - set_width(width); - set_height(height); - } - - void move(const Vector& v) - { - p1 += v; - p2 += v; - } - - bool inside(const Vector& v) const - { - return v.x >= p1.x && v.y >= p1.y && v.x < p2.x && v.y < p2.y; - } - bool inside(const Rectangle& other) const - { - if(p1.x >= other.p2.x || other.p1.x >= p2.x) - return false; - if(p1.y >= other.p2.y || other.p1.y >= p2.y) - return false; - - return true; - } - - // leave these 2 public to safe the headaches of set/get functions for such - // simple things :) - - /// upper left edge - Vector p1; - /// lower right edge - Vector p2; -}; - -} - -#endif - diff --git a/lib/math/vector.cpp b/lib/math/vector.cpp deleted file mode 100644 index 66a8352ab..000000000 --- a/lib/math/vector.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// $Id$ -// -// SuperTux - A Jump'n Run -// Copyright (C) 2004 Matthias Braun - -#include - -#include "math/vector.h" - -using namespace SuperTux; - -Vector Vector::unit() const -{ - return *this / norm(); -} - -float Vector::norm() const -{ - return sqrt(x*x + y*y); -} diff --git a/lib/math/vector.h b/lib/math/vector.h deleted file mode 100644 index 31b171d69..000000000 --- a/lib/math/vector.h +++ /dev/null @@ -1,122 +0,0 @@ -// $Id$ -// -// SuperTux - A Jump'n Run -// Copyright (C) 2004 Matthias Braun -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef SUPERTUX_VECTOR_H -#define SUPERTUX_VECTOR_H - -namespace SuperTux - { - - /// 2D Vector. - /** Simple two dimensional vector. */ - class Vector - { - public: - Vector(float nx, float ny) - : x(nx), y(ny) - { } - Vector(const Vector& other) - : x(other.x), y(other.y) - { } - Vector() - : x(0), y(0) - { } - - bool operator ==(const Vector& other) const - { - return x == other.x && y == other.y; - } - - bool operator !=(const Vector& other) const - { - return !(x == other.x && y == other.y); - } - - const Vector& operator=(const Vector& other) - { - x = other.x; - y = other.y; - return *this; - } - - Vector operator+(const Vector& other) const - { - return Vector(x + other.x, y + other.y); - } - - Vector operator-(const Vector& other) const - { - return Vector(x - other.x, y - other.y); - } - - Vector operator*(float s) const - { - return Vector(x * s, y * s); - } - - Vector operator/(float s) const - { - return Vector(x / s, y / s); - } - - Vector operator-() const - { - return Vector(-x, -y); - } - - const Vector& operator +=(const Vector& other) - { - x += other.x; - y += other.y; - return *this; - } - - const Vector& operator *=(float val) - { - x *= val; - y *= val; - return *this; - } - - const Vector& operator /=(float val) - { - x /= val; - y /= val; - return *this; - } - - /// Scalar product of 2 vectors - float operator*(const Vector& other) const - { - return x*other.x + y*other.y; - } - - float norm() const; - Vector unit() const; - - // ... add the other operators as needed, I'm too lazy now ... - - float x, y; // leave this public, get/set methods just give me headaches - // for such simple stuff :) - }; - -} //namespace SuperTux - -#endif /*SUPERTUX_VECTOR_H*/ - diff --git a/lib/special/.cvsignore b/lib/special/.cvsignore deleted file mode 100644 index f8d9fd474..000000000 --- a/lib/special/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -.sconsign diff --git a/lib/special/frame_rate.cpp b/lib/special/frame_rate.cpp deleted file mode 100644 index cff40710d..000000000 --- a/lib/special/frame_rate.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// SuperTux -// Copyright (C) 2004 Tobias Glaesser -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include - -#include "SDL.h" - -#include "frame_rate.h" -#include "timer.h" - -using namespace SuperTux; - -FrameRate::FrameRate(double fps) -{ - set_fps(fps); - set_frame_limit(true); -} - -void FrameRate::start() -{ - update_time = last_update_time = Ticks::get(); -} - -void FrameRate::set_fps(double fps) -{ - frame_ms = static_cast(1000.f/fps); -} - -void FrameRate::set_frame_limit(bool set_limit) -{ - frame_limit = set_limit; -} - -double FrameRate::get() -{ - return ((double)(update_time-last_update_time))/(double)frame_ms; -} - -void FrameRate::update() -{ - /* Set the time of the last update and the time of the current update */ - last_update_time = update_time; - update_time = Ticks::get(); - - /* Pause till next frame, if the machine running the game is too fast: */ - /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But - the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */ - if(frame_limit && last_update_time >= update_time - (frame_ms+2)) - { - SDL_Delay(frame_ms); - update_time = Ticks::get(); - } -} - -void FrameRate::smooth_hanger() -{ - if( (update_time - last_update_time) > frame_ms*100) - update_time = last_update_time = Ticks::get(); -} diff --git a/lib/special/frame_rate.h b/lib/special/frame_rate.h deleted file mode 100644 index 646498d40..000000000 --- a/lib/special/frame_rate.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// SuperTux -// Copyright (C) 2004 Tobias Glaesser -// -// 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 SUPERTUX_FRAMERATE_H -#define SUPERTUX_FRAMERATE_H - -namespace SuperTux - { - - class FrameRate - { - public: - FrameRate() {}; - FrameRate(double fps); - void start(); - void set_fps(double fps); - void set_frame_limit(bool); - double get(); - void update(); - void smooth_hanger(); - private: - unsigned int last_update_time; - unsigned int update_time; - unsigned int frame_ms; - bool frame_limit; - }; - -} //namespace SuperTux - -#endif /*SUPERTUX_FRAMERATE_H*/ - diff --git a/lib/special/timer.cpp b/lib/special/timer.cpp deleted file mode 100644 index 1ff134981..000000000 --- a/lib/special/timer.cpp +++ /dev/null @@ -1,170 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2004 Tobias Glaesser -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. - -#include - -#include "SDL.h" -#include "timer.h" - -using namespace SuperTux; - -unsigned int Ticks::pause_ticks, Ticks::pause_count; - -unsigned int Ticks::get(void) -{ - if(pause_count != 0) - return /*SDL_GetTicks()*/ - pause_ticks /*- SDL_GetTicks()*/ + pause_count; - else - return SDL_GetTicks() - pause_ticks; -} - -void Ticks::pause_init(void) -{ - pause_ticks = 0; - pause_count = 0; -} - -void Ticks::pause_start(void) -{ - if(pause_count == 0) - pause_count = SDL_GetTicks(); -} - -void Ticks::pause_stop(void) -{ -if(pause_count == 0) -return; - - pause_ticks += SDL_GetTicks() - pause_count; - pause_count = 0; -} - -bool Ticks::pause_started(void) -{ -if(pause_count == 0) -return false; -else -return true; -} - -Timer::Timer() -{ - init(true); -} - -void -Timer::init(bool game_ticks) -{ - period = 0; - time = 0; - get_ticks = game_ticks ? Ticks::get : SDL_GetTicks; -} - -void -Timer::start(unsigned int period_) -{ - time = get_ticks(); - period = period_; -} - -void -Timer::stop() -{ - if(get_ticks == get_ticks) - init(true); - else - init(false); -} - -int -Timer::check() -{ - if((time != 0) && (time + period > get_ticks())) - return true; - else - { - time = 0; - return false; - } -} - -int -Timer::started() -{ - if(time != 0) - return true; - else - return false; -} - -int -Timer::get_left() -{ - return (period - (get_ticks() - time)); -} - -int -Timer::get_gone() -{ - return (get_ticks() - time); -} - -void -Timer::fwrite(FILE* fi) -{ - unsigned int diff_ticks; - int tick_mode; - if(time != 0) - diff_ticks = get_ticks() - time; - else - diff_ticks = 0; - - ::fwrite(&period,sizeof(unsigned int),1,fi); - ::fwrite(&diff_ticks,sizeof(unsigned int),1,fi); - if(get_ticks == get_ticks) - tick_mode = true; - else - tick_mode = false; - ::fwrite(&tick_mode,sizeof(unsigned int),1,fi); -} - -void -Timer::fread(FILE* fi) -{ - unsigned int diff_ticks; - int tick_mode; - - ::fread(&period,sizeof(unsigned int),1,fi); - ::fread(&diff_ticks,sizeof(unsigned int),1,fi); - ::fread(&tick_mode,sizeof(unsigned int),1,fi); - - if (tick_mode) - get_ticks = get_ticks; - else - get_ticks = SDL_GetTicks; - - if (diff_ticks != 0) - time = get_ticks() - diff_ticks; - else - time = 0; - -} - -/* EOF */ diff --git a/lib/special/timer.h b/lib/special/timer.h deleted file mode 100644 index 1866a2cc9..000000000 --- a/lib/special/timer.h +++ /dev/null @@ -1,100 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2004 Tobias Glaesser -// -// 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 SUPERTUX_TIMER_H -#define SUPERTUX_TIMER_H - -#include - -namespace SuperTux - { - - class Ticks - { - public: - /// Time a game is running. (Non-pause mode, etc.) - static unsigned int get(); - - static void pause_init(); - static void pause_start(); - static void pause_stop(); - static bool pause_started(); - - private: - static unsigned int pause_ticks; - static unsigned int pause_count; - - }; - - /// Timer - /** This class can be used as stop watch - for example. It's also possible to calculate - frames per seconds and things like that with it. - It's a general timing class, but it - can esspecially be used together with Ticks::get(). */ - class Timer - { - public: - unsigned int period; - unsigned int time; - unsigned int (*get_ticks) (void); - - public: - Timer(); - - /// Initialize the timer. - /** @param st_ticks: If true internally Ticks::get() is used, else SDL_GetTicks() is used. */ - void init(bool game_ticks); - - /// Start the timer with the given period (in ms). - void start(unsigned int period); - - /// Stop the timer. - void stop(); - - /// Check if the timer is started and within its period. - /** If one of these requirements isn't the case the timer - is automatically reseted. */ - int check(); - - /// Is the timer started? - int started(); - - /// Get time left until the last timing period is finished. - /** The returned value can be negative. */ - int get_left(); - - /// Get the gone time, since last timer start. - /** The returned value can be negative. */ - int get_gone(); - - /// Write the timer value to a file (For save games in example). - void fwrite(FILE* fi); - /// Read a timer value from a file (From save games in example). - void fread(FILE* fi); - }; - -} //namespace SuperTux - -#endif /*SUPERTUX_TIMER_H*/ - -/* Local Variables: */ -/* mode:c++ */ -/* End: */ diff --git a/lib/utils/.cvsignore b/lib/utils/.cvsignore deleted file mode 100644 index f8d9fd474..000000000 --- a/lib/utils/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -.sconsign diff --git a/lib/video/.cvsignore b/lib/video/.cvsignore deleted file mode 100644 index f8d9fd474..000000000 --- a/lib/video/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -.sconsign diff --git a/src/Jamfile b/src/Jamfile index 82628ad53..02e7ae93b 100644 --- a/src/Jamfile +++ b/src/Jamfile @@ -1,7 +1,11 @@ SubDir TOP src ; +SubInclude TOP src squirrel ; +SubInclude TOP src scripting ; + sources = [ Wildcard *.cpp *.h ] + [ Wildcard math : *.cpp *.h ] [ Wildcard video : *.cpp *.h ] [ Wildcard audio : *.cpp *.h ] [ Wildcard gui : *.cpp *.h ] @@ -14,8 +18,9 @@ sources = ; TRANSLATABLE_SOURCES += [ SearchSource $(sources) ] ; -Application supertux : $(sources) ; -LinkWith supertux : supertuxlib ; +Application supertux : $(sources) $(wrapper_objects) ; +LinkWith supertux : supertuxlib squirrel ; ExternalLibs supertux : SDL SDLMIXER SDLIMAGE GL ; Help supertux : "Build the supertux executable" ; +IncludeDir supertux : squirrel/include ; diff --git a/src/audio/musicref.cpp b/src/audio/musicref.cpp index f3d47ea1a..2bf8dd4af 100644 --- a/src/audio/musicref.cpp +++ b/src/audio/musicref.cpp @@ -17,13 +17,10 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #include #include "audio/musicref.h" -using namespace SuperTux; - MusicRef::MusicRef() : music(0) { diff --git a/src/audio/sound_manager.cpp b/src/audio/sound_manager.cpp index c7e624aee..9d2883e3d 100644 --- a/src/audio/sound_manager.cpp +++ b/src/audio/sound_manager.cpp @@ -20,18 +20,15 @@ #include #include +#include #include #include #include "audio/sound_manager.h" #include "audio/musicref.h" -#include "app/globals.h" -#include "app/setup.h" #include "moving_object.h" #include "resources.h" -using namespace SuperTux; - SoundManager::SoundManager() : current_music(0), m_music_enabled(true) , m_sound_enabled(true), audio_device(false) @@ -85,7 +82,7 @@ SoundManager::play_sound(const std::string& sound, const Vector& pos, // TODO make sure this formula is good float distance = pos2.x- pos.x; - int loud = int(255.0/float(SCREEN_WIDTH*2) * fabsf(distance)); + int loud = int(255.0/float(1600) * fabsf(distance)); if(loud > 255) return; diff --git a/src/audio/sound_manager.h b/src/audio/sound_manager.h index d0ddad5cd..09c0d00aa 100644 --- a/src/audio/sound_manager.h +++ b/src/audio/sound_manager.h @@ -26,8 +26,6 @@ #include "SDL_mixer.h" #include "math/vector.h" -using namespace SuperTux; - class MusicRef; class MovingObject; diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 42d56dd51..6817efaa9 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -205,7 +205,6 @@ BadGuy::kill_fall() physic.enable_gravity(true); set_state(STATE_FALLING); } - std::cout << "KILL_FALL - HITPOINTS: " << hitpoints << ", BULLET HP: " << bullet_hitpoints << std::endl; } void diff --git a/src/badguy/badguy.h b/src/badguy/badguy.h index ecd753dd4..d5c948cd7 100644 --- a/src/badguy/badguy.h +++ b/src/badguy/badguy.h @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __BADGUY_H__ #define __BADGUY_H__ @@ -26,7 +25,7 @@ #include "timer.h" #include "moving_object.h" #include "sprite/sprite.h" -#include "math/physic.h" +#include "physic.h" #include "object/player.h" #include "serializable.h" #include "resources.h" @@ -39,8 +38,6 @@ #include "video/drawing_context.h" #include "sprite/sprite_manager.h" -using namespace SuperTux; - class BadGuy : public MovingObject, public Serializable { public: diff --git a/src/badguy/mriceblock.cpp b/src/badguy/mriceblock.cpp index 82cec6f8c..b2555763b 100644 --- a/src/badguy/mriceblock.cpp +++ b/src/badguy/mriceblock.cpp @@ -71,7 +71,6 @@ void MrIceBlock::active_action(float elapsed_time) { if(ice_state == ICESTATE_FLAT && flat_timer.check()) { - printf("unflat.\n"); ice_state = ICESTATE_NORMAL; physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED); sprite->set_action(dir == LEFT ? "left" : "right"); @@ -161,7 +160,6 @@ MrIceBlock::collision_squished(Player& player) sprite->set_action(dir == LEFT ? "flat-left" : "flat-right"); flat_timer.start(4); ice_state = ICESTATE_FLAT; - printf("flat.\n"); break; case ICESTATE_FLAT: // kick @@ -175,7 +173,6 @@ MrIceBlock::collision_squished(Player& player) physic.set_velocity_x(dir == LEFT ? -KICKSPEED : KICKSPEED); sprite->set_action(dir == LEFT ? "flat-left" : "flat-right"); ice_state = ICESTATE_KICKED; - printf("kicked.\n"); break; } diff --git a/src/badguy/nolok_01.cpp b/src/badguy/nolok_01.cpp index b1715515f..61c8b12d7 100644 --- a/src/badguy/nolok_01.cpp +++ b/src/badguy/nolok_01.cpp @@ -149,7 +149,6 @@ Nolok_01::kill_fall() set_state(STATE_FALLING); Sector::current()->add_object(new Door((int)get_pos().x+32, 512, "sector1", "main2")); } - std::cout << "KILL_FALL - HITPOINTS: " << hitpoints << ", BULLET HP: " << bullet_hitpoints << std::endl; } IMPLEMENT_FACTORY(Nolok_01, "nolok_01") diff --git a/src/badguy/yeti.cpp b/src/badguy/yeti.cpp index 327927544..c1da901e2 100644 --- a/src/badguy/yeti.cpp +++ b/src/badguy/yeti.cpp @@ -235,7 +235,6 @@ Yeti::kill_fall() physic.enable_gravity(true); set_state(STATE_FALLING); } - std::cout << "KILL_FALL - HITPOINTS: " << hitpoints << ", BULLET HP: " << bullet_hitpoints << std::endl; } IMPLEMENT_FACTORY(Yeti, "yeti") diff --git a/src/collision.h b/src/collision.h index 6b8662c1f..2c65c488f 100644 --- a/src/collision.h +++ b/src/collision.h @@ -21,14 +21,9 @@ #ifndef __COLLISION_H__ #define __COLLISION_H__ -namespace SuperTux { class Vector; class Rectangle; class AATriangle; -} - -using namespace SuperTux; - class CollisionHit; class Collision diff --git a/src/collision_grid.h b/src/collision_grid.h index 10275628f..d206c8c1d 100644 --- a/src/collision_grid.h +++ b/src/collision_grid.h @@ -17,15 +17,12 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __COLLISION_GRID_H__ #define __COLLISION_GRID_H__ #include #include "moving_object.h" -using namespace SuperTux; - class CollisionGridIterator; /** diff --git a/src/collision_grid_iterator.h b/src/collision_grid_iterator.h index d0f0fb844..fd3350beb 100644 --- a/src/collision_grid_iterator.h +++ b/src/collision_grid_iterator.h @@ -17,14 +17,11 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __COLLISION_GRID_ITERATOR_H__ #define __COLLISION_GRID_ITERATOR_H__ #include "math/rectangle.h" -using namespace SuperTux; - class CollisionGrid; class CollisionGridIterator diff --git a/src/collision_hit.h b/src/collision_hit.h index cde4a3105..4c4ccec5b 100644 --- a/src/collision_hit.h +++ b/src/collision_hit.h @@ -21,8 +21,6 @@ #include "math/vector.h" -using namespace SuperTux; - /** * Used as return value for the collision functions, to indicate how the * collision should be handled diff --git a/src/control/joystickkeyboardcontroller.cpp b/src/control/joystickkeyboardcontroller.cpp index d314dae77..4f930917f 100644 --- a/src/control/joystickkeyboardcontroller.cpp +++ b/src/control/joystickkeyboardcontroller.cpp @@ -23,7 +23,7 @@ #include #include "joystickkeyboardcontroller.h" #include "gui/menu.h" -#include "app/gettext.h" +#include "gettext.h" #include "lisp/lisp.h" #include "lisp/list_iterator.h" #include "game_session.h" @@ -71,12 +71,9 @@ JoystickKeyboardController::JoystickKeyboardController() keymap.insert(std::make_pair(SDLK_RETURN, MENU_SELECT)); keymap.insert(std::make_pair(SDLK_KP_ENTER, MENU_SELECT)); - joystick_count = SDL_NumJoysticks(); + int joystick_count = SDL_NumJoysticks(); min_joybuttons = -1; max_joybuttons = -1; -#ifdef DEBUG - std::cout << "Found " << joystick_count << " joysticks.\n"; -#endif for(int i = 0; i < joystick_count; ++i) { SDL_Joystick* joystick = SDL_JoystickOpen(i); bool good = true; @@ -91,8 +88,6 @@ JoystickKeyboardController::JoystickKeyboardController() } if(!good) { SDL_JoystickClose(joystick); - joysticks.push_back(0); - joystick_names.push_back(""); continue; } @@ -102,7 +97,6 @@ JoystickKeyboardController::JoystickKeyboardController() max_joybuttons = SDL_JoystickNumButtons(joystick); } - joystick_names.push_back(SDL_JoystickName(i)); joysticks.push_back(joystick); } @@ -618,9 +612,13 @@ JoystickKeyboardController::JoystickMenu::JoystickMenu( { add_label(_("Joystick Setup")); add_hl(); - add_controlfield(Controller::JUMP, _("Jump")); - add_controlfield(Controller::ACTION, _("Shoot/Run")); - add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu")); + if(controller->joysticks.size() > 0) { + add_controlfield(Controller::JUMP, _("Jump")); + add_controlfield(Controller::ACTION, _("Shoot/Run")); + add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu")); + } else { + add_deactive(-1, _("No Joysticks found")); + } add_hl(); add_back(_("Back")); update(); @@ -651,6 +649,9 @@ JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item) void JoystickKeyboardController::JoystickMenu::update() { + if(controller->joysticks.size() == 0) + return; + // update menu get_item_by_id((int) Controller::JUMP).change_input(get_button_name( controller->reversemap_joybutton(Controller::JUMP))); diff --git a/src/control/joystickkeyboardcontroller.h b/src/control/joystickkeyboardcontroller.h index 93fe1ac9d..150ddb3d1 100644 --- a/src/control/joystickkeyboardcontroller.h +++ b/src/control/joystickkeyboardcontroller.h @@ -53,9 +53,7 @@ private: typedef std::map KeyMap; KeyMap keymap; - int joystick_count; std::vector joysticks; - std::vector joystick_names; typedef std::map ButtonMap; ButtonMap joy_button_map; diff --git a/src/file_system.cpp b/src/file_system.cpp new file mode 100644 index 000000000..af243f837 --- /dev/null +++ b/src/file_system.cpp @@ -0,0 +1,222 @@ +#include + +#include "file_system.h" +#include +#include +#include +#ifndef WIN32 +#include +#endif + +#include "resources.h" + +#ifdef WIN32 +#define mkdir(dir, mode) mkdir(dir) +#endif + +namespace FileSystem +{ + +/* Does the given file exist and is it accessible? */ +bool faccessible(const std::string& filename) +{ + FILE* f = fopen(filename.c_str(), "r"); + if(f == 0) + return false; + + fclose(f); + return true; +} + +/* Can we write to this location? */ +bool fwriteable(const std::string& filename) +{ + FILE* f = fopen(filename.c_str(), "wa"); + if (f == 0) + return false; + + fclose(f); + return true; +} + +/* Makes sure a directory is created in either the SuperTux home directory or the SuperTux base directory.*/ +bool fcreatedir(const std::string& relative_dir) +{ + std::string path = user_dir + "/" + relative_dir + "/"; + if(mkdir(path.c_str(),0755) == 0) + return true; + + path = datadir + "/" + relative_dir + "/"; + if(mkdir(path.c_str(),0755) == 0) + return true; + + return false; +} + +/* Get all names of sub-directories in a certain directory. */ +/* Returns the number of sub-directories found. */ +/* Note: The user has to free the allocated space. */ +std::set dsubdirs(const std::string &rel_path, + const std::string& expected_file) +{ + DIR *dirStructP; + struct dirent *direntp; + std::set sdirs; + std::string filename; + std::string path = user_dir + "/" + rel_path; + + if((dirStructP = opendir(path.c_str())) != NULL) + { + while((direntp = readdir(dirStructP)) != NULL) + { + std::string absolute_filename; + struct stat buf; + + absolute_filename = path + "/" + direntp->d_name; + + if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode)) + { + if(!expected_file.empty()) + { + filename = path + "/" + direntp->d_name + "/" + expected_file; + if(!faccessible(filename)) + continue; + } + + sdirs.insert(direntp->d_name); + } + } + closedir(dirStructP); + } + + path = datadir + "/" + rel_path; + if((dirStructP = opendir(path.c_str())) != NULL) + { + while((direntp = readdir(dirStructP)) != NULL) + { + std::string absolute_filename; + struct stat buf; + + absolute_filename = path + "/" + direntp->d_name; + + if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode)) + { + if(!expected_file.empty()) + { + filename = path + "/" + direntp->d_name + "/" + expected_file; + if(!faccessible(filename.c_str())) + { + continue; + } + else + { + filename = user_dir + "/" + rel_path + "/" + direntp->d_name + "/" + expected_file; + if(faccessible(filename.c_str())) + continue; + } + } + + sdirs.insert(direntp->d_name); + } + } + closedir(dirStructP); + } + + return sdirs; +} + +std::set dfiles(const std::string& rel_path, + const std::string& glob, const std::string& exception_str) +{ + DIR *dirStructP; + struct dirent *direntp; + std::set sdirs; + std::string path = user_dir + "/" + rel_path; + + if((dirStructP = opendir(path.c_str())) != NULL) + { + while((direntp = readdir(dirStructP)) != NULL) + { + std::string absolute_filename; + struct stat buf; + + absolute_filename = path + "/" + direntp->d_name; + + if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode)) + { + if(!exception_str.empty()) + { + if(strstr(direntp->d_name,exception_str.c_str()) != NULL) + continue; + } + if(!glob.empty()) + if(strstr(direntp->d_name,glob.c_str()) == NULL) + continue; + + sdirs.insert(direntp->d_name); + } + } + closedir(dirStructP); + } + + path = datadir + "/" + rel_path; + if((dirStructP = opendir(path.c_str())) != NULL) + { + while((direntp = readdir(dirStructP)) != NULL) + { + std::string absolute_filename; + struct stat buf; + + absolute_filename = path + "/" + direntp->d_name; + + if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode)) + { + if(!exception_str.empty()) + { + if(strstr(direntp->d_name,exception_str.c_str()) != NULL) + continue; + } + if(!glob.empty()) + if(strstr(direntp->d_name,glob.c_str()) == NULL) + continue; + + sdirs.insert(direntp->d_name); + } + } + closedir(dirStructP); + } + + return sdirs; +} + +std::string dirname(const std::string& filename) +{ + std::string::size_type p = filename.find_last_of('/'); + if(p == std::string::npos) + return ""; + + return filename.substr(0, p+1); +} + +std::set read_directory(const std::string& pathname) +{ + std::set dirnames; + + DIR* dir = opendir(pathname.c_str()); + if (dir) + { + struct dirent *direntp; + + while((direntp = readdir(dir))) + { + dirnames.insert(direntp->d_name); + } + + closedir(dir); + } + + return dirnames; +} + +} + diff --git a/src/file_system.h b/src/file_system.h new file mode 100644 index 000000000..341e1fcfc --- /dev/null +++ b/src/file_system.h @@ -0,0 +1,21 @@ +#ifndef __FILESYSTEM_H__ +#define __FILESYSTEM_H__ + +#include +#include + +namespace FileSystem +{ + bool faccessible(const std::string& filename); + bool fcreatedir(const std::string& relative_dir); + bool fwriteable(const std::string& filename); + std::set read_directory(const std::string& pathname); + std::set dsubdirs(const std::string& rel_path, + const std::string& expected_file); + std::set dfiles(const std::string& rel_path, + const std::string& glob, const std::string& exception_str); + std::string dirname(const std::string& filename); +} + +#endif + diff --git a/src/game_session.cpp b/src/game_session.cpp index 037099c32..b4d44ade8 100644 --- a/src/game_session.cpp +++ b/src/game_session.cpp @@ -40,10 +40,8 @@ #include #endif -#include "app/globals.h" #include "game_session.h" #include "video/screen.h" -#include "app/setup.h" #include "gui/menu.h" #include "sector.h" #include "level.h" @@ -57,7 +55,6 @@ #include "lisp/lisp.h" #include "lisp/parser.h" #include "resources.h" -#include "app/gettext.h" #include "worldmap.h" #include "misc.h" #include "statistics.h" @@ -67,6 +64,8 @@ #include "control/codecontroller.h" #include "control/joystickkeyboardcontroller.h" #include "main.h" +#include "gameconfig.h" +#include "gettext.h" // the engine will be run with a lofical framerate of 64fps. // We choose 64fps here because it is a power of 2, so 1/64 gives an "even" @@ -217,8 +216,7 @@ GameSession::levelintro() context.do_drawing(); - SDL_Event event; - wait_for_event(event,1000,3000,true); + wait_for_event(1.0, 3.0); } /* Reset Timers */ @@ -226,7 +224,6 @@ void GameSession::start_timers() { time_left.start(level->timelimit); - Ticks::pause_init(); } void @@ -240,10 +237,8 @@ GameSession::on_escape_press() } else if (!Menu::current()) { Menu::set_current(game_menu); game_menu->set_active_item(MNID_CONTINUE); - Ticks::pause_start(); game_pause = true; } else { - Ticks::pause_stop(); game_pause = false; } } @@ -257,7 +252,6 @@ GameSession::process_events() // end of pause mode? if(!Menu::current() && game_pause) { game_pause = false; - Ticks::pause_stop(); } if (end_sequence != NO_ENDSEQUENCE) { @@ -796,8 +790,7 @@ GameSession::drawresultscreen() context.do_drawing(); - SDL_Event event; - wait_for_event(event,2000,5000,true); + wait_for_event(2.0, 5.0); } std::string slotinfo(int slot) @@ -830,33 +823,32 @@ bool process_load_game_menu() { int slot = load_game_menu->check(); - if(slot != -1 && load_game_menu->get_item_by_id(slot).kind == MN_ACTION) - { - std::stringstream stream; - stream << slot; - std::string slotfile = user_dir + "/save/slot" + stream.str() + ".stsg"; + if(slot == -1) + return false; + + if(load_game_menu->get_item_by_id(slot).kind != MN_ACTION) + return false; + + std::stringstream stream; + stream << slot; + std::string slotfile = user_dir + "/save/slot" + stream.str() + ".stsg"; - fadeout(256); - DrawingContext context; - context.draw_text(white_text, "Loading...", - Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT/2), CENTER_ALLIGN, LAYER_FOREGROUND1); - context.do_drawing(); + fadeout(256); + DrawingContext context; + context.draw_text(white_text, "Loading...", + Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT/2), + CENTER_ALLIGN, LAYER_FOREGROUND1); + context.do_drawing(); - WorldMapNS::WorldMap worldmap; + WorldMapNS::WorldMap worldmap; - worldmap.set_map_filename("/levels/world1/worldmap.stwm"); - // Load the game or at least set the savegame_file variable - worldmap.loadgame(slotfile); + worldmap.set_map_filename("/levels/world1/worldmap.stwm"); + // Load the game or at least set the savegame_file variable + worldmap.loadgame(slotfile); - worldmap.display(); + worldmap.display(); - Menu::set_current(main_menu); + Menu::set_current(main_menu); - Ticks::pause_stop(); - return true; - } - else - { - return false; - } + return true; } diff --git a/src/game_session.h b/src/game_session.h index 4ff1b820f..72784a35a 100644 --- a/src/game_session.h +++ b/src/game_session.h @@ -21,14 +21,13 @@ #ifndef SUPERTUX_GAMELOOP_H #define SUPERTUX_GAMELOOP_H +#include #include #include "timer.h" #include "statistics.h" - -using namespace SuperTux; +#include "math/vector.h" /* GameLoop modes */ - enum GameSessionMode { ST_GL_PLAY, ST_GL_TEST, diff --git a/src/gameconfig.cpp b/src/gameconfig.cpp index 18c2dd230..2387c8cf8 100644 --- a/src/gameconfig.cpp +++ b/src/gameconfig.cpp @@ -26,17 +26,14 @@ #include #include -#include "app/setup.h" -#include "app/globals.h" #include "audio/sound_manager.h" #include "lisp/parser.h" #include "lisp/lisp.h" #include "lisp/writer.h" #include "control/joystickkeyboardcontroller.h" +#include "resources.h" #include "main.h" -using namespace SuperTux; - Config* config = 0; Config::Config() diff --git a/src/gettext.h b/src/gettext.h new file mode 100644 index 000000000..8ecae1a84 --- /dev/null +++ b/src/gettext.h @@ -0,0 +1,33 @@ +/* + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library 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 _LIBGETTEXT_H +#define _LIBGETTEXT_H + +#include "tinygettext/tinygettext.h" + +extern TinyGetText::DictionaryManager dictionary_manager; + +static inline const char* _(const char* message) +{ + return dictionary_manager.get_dictionary().translate(message).c_str(); +} + +static inline const char* N_(const char* id, const char* id2, int num) +{ + return dictionary_manager.get_dictionary().translate(id, id2, num).c_str(); +} + +#endif /* _LIBGETTEXT_H */ diff --git a/src/gui/button.cpp b/src/gui/button.cpp index d9f13c301..2f4580a48 100644 --- a/src/gui/button.cpp +++ b/src/gui/button.cpp @@ -17,20 +17,17 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #include #include "SDL.h" #include +#include "main.h" #include "button.h" #include "mousecursor.h" -#include "app/globals.h" #include "video/font.h" #include "video/surface.h" -using namespace SuperTux; - Font* Button::info_font = 0; extern SDL_Surface* screen; diff --git a/src/gui/button.h b/src/gui/button.h index 6fc2249f4..700dbf079 100644 --- a/src/gui/button.h +++ b/src/gui/button.h @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef SUPERTUX_BUTTON_H #define SUPERTUX_BUTTON_H @@ -29,8 +28,6 @@ class Surface; -namespace SuperTux - { class ButtonGroup; enum { @@ -91,6 +88,4 @@ private: int buttons_pair_nb; }; -} //namespace SuperTux - #endif diff --git a/src/gui/menu.cpp b/src/gui/menu.cpp index 361173c06..d70b16a9c 100644 --- a/src/gui/menu.cpp +++ b/src/gui/menu.cpp @@ -29,24 +29,21 @@ #include #include -#include "app/globals.h" #include "menu.h" #include "video/screen.h" #include "video/drawing_context.h" -#include "app/setup.h" -#include "app/gettext.h" +#include "gettext.h" #include "math/vector.h" #include "main.h" +#include "resources.h" #include "control/joystickkeyboardcontroller.h" static const int MENU_REPEAT_INITIAL = 400; static const int MENU_REPEAT_RATE = 200; -static const int FLICK_CURSOR_TIME=500; +static const int FLICK_CURSOR_TIME = 500; extern SDL_Surface* screen; -using namespace SuperTux; - Surface* checkbox; Surface* checkbox_checked; Surface* back; @@ -128,7 +125,7 @@ Menu::push_current(Menu* pmenu) last_menus.push_back(current_); current_ = pmenu; - current_->effect.start(500); + current_->effect_ticks = SDL_GetTicks(); } void @@ -136,8 +133,7 @@ Menu::pop_current() { if (last_menus.size() >= 1) { current_ = last_menus.back(); - current_->effect.start(500); - + current_->effect_ticks = SDL_GetTicks(); last_menus.pop_back(); } else { current_ = 0; @@ -150,7 +146,7 @@ Menu::set_current(Menu* menu) last_menus.clear(); if (menu) - menu->effect.start(500); + menu->effect_ticks = SDL_GetTicks(); current_ = menu; // just to be sure... @@ -163,9 +159,6 @@ MenuItem::MenuItem(MenuItemKind _kind, int _id) toggled = false; selected = false; target_menu = 0; - input_flickering = false; - input_flickering_timer.init(true); - input_flickering_timer.start(FLICK_CURSOR_TIME); } void @@ -182,19 +175,11 @@ MenuItem::change_input(const std::string& text_) std::string MenuItem::get_input_with_symbol(bool active_item) { - if(!active_item) + if(!active_item) { input_flickering = true; - else - { - if(input_flickering_timer.get_left() < 0) - { - if(input_flickering) - input_flickering = false; - else - input_flickering = true; - input_flickering_timer.start(FLICK_CURSOR_TIME); - } - } + } else { + input_flickering = (SDL_GetTicks() / FLICK_CURSOR_TIME) % 2; + } char str[1024]; if(input_flickering) @@ -225,9 +210,6 @@ Menu::Menu() pos_y = SCREEN_HEIGHT/2; arrange_left = 0; active_item = -1; - effect.init(false); - - repeat_timer.init(true); } void Menu::set_pos(int x, int y, float rw, float rh) @@ -336,21 +318,24 @@ void Menu::action() { /** check main input controller... */ + Uint32 ticks = SDL_GetTicks(); if(main_controller->pressed(Controller::UP)) { menuaction = MENU_ACTION_UP; - repeat_timer.start(MENU_REPEAT_INITIAL); + menu_repeat_ticks = ticks + MENU_REPEAT_INITIAL; } - if(main_controller->hold(Controller::UP) && !repeat_timer.check()) { + if(main_controller->hold(Controller::UP) && + menu_repeat_ticks != 0 && ticks > menu_repeat_ticks) { menuaction = MENU_ACTION_UP; - repeat_timer.start(MENU_REPEAT_RATE); + menu_repeat_ticks = ticks + MENU_REPEAT_RATE; } if(main_controller->pressed(Controller::DOWN)) { menuaction = MENU_ACTION_DOWN; - repeat_timer.start(MENU_REPEAT_INITIAL); + menu_repeat_ticks = ticks + MENU_REPEAT_INITIAL; } - if(main_controller->hold(Controller::DOWN) && !repeat_timer.check()) { + if(main_controller->hold(Controller::DOWN) && + menu_repeat_ticks != 0 && ticks > menu_repeat_ticks) { menuaction = MENU_ACTION_DOWN; - repeat_timer.start(MENU_REPEAT_RATE); + menu_repeat_ticks = ticks + MENU_REPEAT_RATE; } if(main_controller->pressed(Controller::JUMP) || main_controller->pressed(Controller::ACTION) @@ -507,13 +492,13 @@ Menu::draw_item(DrawingContext& context, int index) MenuItem& pitem = *(items[index]); int effect_offset = 0; - { - int effect_time = 0; - - if(effect.check()) - effect_time = effect.get_left() / 4; - - effect_offset = (index % 2) ? effect_time : -effect_time; + if(effect_ticks != 0) { + if(SDL_GetTicks() - effect_ticks > 500) { + effect_ticks = 0; + } else { + Uint32 effect_time = (500 - (SDL_GetTicks() - effect_ticks)) / 4; + effect_offset = (index % 2) ? effect_time : -effect_time; + } } Font* text_font = default_font; @@ -764,7 +749,7 @@ Menu::is_toggled(int id) const void Menu::event(const SDL_Event& event) { - if(effect.started()) + if(effect_ticks != 0) return; switch(event.type) { diff --git a/src/gui/menu.h b/src/gui/menu.h index 46373b45b..dba01bc47 100644 --- a/src/gui/menu.h +++ b/src/gui/menu.h @@ -29,7 +29,6 @@ #include "video/surface.h" #include "video/font.h" -#include "special/timer.h" #include "mousecursor.h" bool confirm_dialog(Surface* background, std::string text); @@ -82,7 +81,6 @@ private: /// keyboard key or joystick button bool input_flickering; - Timer input_flickering_timer; }; class Menu @@ -132,7 +130,7 @@ private: /* input implementation variables */ int delete_character; char mn_input_char; - Timer repeat_timer; + Uint32 menu_repeat_ticks; public: static Font* default_font; @@ -192,7 +190,7 @@ protected: private: void check_controlfield_change_event(const SDL_Event& event); void draw_item(DrawingContext& context, int index); - Timer effect; + Uint32 effect_ticks; int arrange_left; int active_item; }; diff --git a/src/gui/mousecursor.cpp b/src/gui/mousecursor.cpp index bd3ff525b..5a935635c 100644 --- a/src/gui/mousecursor.cpp +++ b/src/gui/mousecursor.cpp @@ -16,29 +16,21 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #include -#include "app/globals.h" #include "video/drawing_context.h" #include "gui/mousecursor.h" - -using namespace SuperTux; +#include "main.h" MouseCursor* MouseCursor::current_ = 0; extern SDL_Surface* screen; -MouseCursor::MouseCursor(std::string cursor_file, int frames) : mid_x(0), mid_y(0) +MouseCursor::MouseCursor(std::string cursor_file) : mid_x(0), mid_y(0) { cursor = new Surface(cursor_file, true); cur_state = MC_NORMAL; - cur_frame = 0; - tot_frames = frames; - timer.init(false); - timer.start(MC_FRAME_PERIOD); - SDL_ShowCursor(SDL_DISABLE); } @@ -76,31 +68,18 @@ void MouseCursor::draw(DrawingContext& context) x = int(x * float(SCREEN_WIDTH)/screen->w); y = int(y * float(SCREEN_HEIGHT)/screen->h); - w = cursor->w / tot_frames; + w = cursor->w; h = cursor->h / MC_STATES_NB; - if(ispressed &SDL_BUTTON(1) || ispressed &SDL_BUTTON(2)) - { - if(cur_state != MC_CLICK) - { - state_before_click = cur_state; - cur_state = MC_CLICK; - } - } - else - { - if(cur_state == MC_CLICK) - cur_state = state_before_click; - } - - if(timer.get_left() < 0 && tot_frames > 1) - { - cur_frame++; - if(cur_frame++ >= tot_frames) - cur_frame = 0; - - timer.start(MC_FRAME_PERIOD); + if(ispressed &SDL_BUTTON(1) || ispressed &SDL_BUTTON(2)) { + if(cur_state != MC_CLICK) { + state_before_click = cur_state; + cur_state = MC_CLICK; } + } else { + if(cur_state == MC_CLICK) + cur_state = state_before_click; + } - context.draw_surface_part(cursor, Vector(w*cur_frame, h*cur_state), Vector(w, - h), Vector(x-mid_x, y-mid_y), LAYER_GUI+100); + context.draw_surface_part(cursor, Vector(w, h*cur_state), + Vector(w, h), Vector(x-mid_x, y-mid_y), LAYER_GUI+100); } diff --git a/src/gui/mousecursor.h b/src/gui/mousecursor.h index 0842b62c8..4bebe5327 100644 --- a/src/gui/mousecursor.h +++ b/src/gui/mousecursor.h @@ -16,71 +16,60 @@ // 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 SUPERTUX_MOUSECURSOR_H #define SUPERTUX_MOUSECURSOR_H #include -#include "special/timer.h" #include "video/surface.h" -namespace SuperTux - { - - #define MC_FRAME_PERIOD 800 // in ms - - #define MC_STATES_NB 3 +#define MC_STATES_NB 3 - enum { - MC_NORMAL, - MC_CLICK, - MC_LINK, - MC_HIDE - }; - - /// Mouse cursor. - /** Used to create mouse cursors. - The mouse cursors can be animated - and can be used in four different states. - (MC_NORMAL, MC_CLICK, MC_LINK or MC_HIDE) */ - class MouseCursor - { - public: - /// Constructor of MouseCursor. - /** Expects an imagefile for the cursor and the number of animation frames it contains. */ - MouseCursor(std::string cursor_file, int frames); - ~MouseCursor(); - /// Get MouseCursor state. - /** (MC_NORMAL, MC_CLICK, MC_LINK or MC_HIDE) */ - int state(); - /// Set MouseCursor state. - /** (MC_NORMAL, MC_CLICK, MC_LINK or MC_HIDE) */ - void set_state(int nstate); - /// Define the middle of a MouseCursor. - /** Useful for cross mouse cursor images in example. */ - void set_mid(int x, int y); +enum { + MC_NORMAL, + MC_CLICK, + MC_LINK, + MC_HIDE +}; - /// Draw MouseCursor on screen. - void draw(DrawingContext& context); +/// Mouse cursor. +/** Used to create mouse cursors. + The mouse cursors can be animated + and can be used in four different states. + (MC_NORMAL, MC_CLICK, MC_LINK or MC_HIDE) */ +class MouseCursor +{ +public: + /// Constructor of MouseCursor. + /** Expects an imagefile for the cursor and the number of animation frames it contains. */ + MouseCursor(std::string cursor_file); + ~MouseCursor(); + /// Get MouseCursor state. + /** (MC_NORMAL, MC_CLICK, MC_LINK or MC_HIDE) */ + int state(); + /// Set MouseCursor state. + /** (MC_NORMAL, MC_CLICK, MC_LINK or MC_HIDE) */ + void set_state(int nstate); + /// Define the middle of a MouseCursor. + /** Useful for cross mouse cursor images in example. */ + void set_mid(int x, int y); - /// Return the current cursor. - static MouseCursor* current() - { return current_; }; - /// Set current cursor. - static void set_current(MouseCursor* pcursor) - { current_ = pcursor; }; + /// Draw MouseCursor on screen. + void draw(DrawingContext& context); - private: - int mid_x, mid_y; - static MouseCursor* current_; - int state_before_click; - int cur_state; - int cur_frame, tot_frames; - Surface* cursor; - Timer timer; - }; + /// Return the current cursor. + static MouseCursor* current() + { return current_; }; + /// Set current cursor. + static void set_current(MouseCursor* pcursor) + { current_ = pcursor; }; -} // namespace SuperTux +private: + int mid_x, mid_y; + static MouseCursor* current_; + int state_before_click; + int cur_state; + Surface* cursor; +}; #endif /*SUPERTUX_MOUSECURSOR_H*/ diff --git a/src/level.cpp b/src/level.cpp index ae81a34c3..b097cc422 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -29,18 +29,17 @@ #include #include -#include "app/globals.h" -#include "app/setup.h" #include "video/screen.h" #include "lisp/parser.h" #include "lisp/lisp.h" #include "lisp/list_iterator.h" #include "lisp/writer.h" #include "level.h" -#include "math/physic.h" +#include "physic.h" #include "sector.h" #include "tile.h" #include "resources.h" +#include "file_system.h" #include "object/gameobjs.h" #include "object/camera.h" #include "object/tilemap.h" diff --git a/src/level_subset.cpp b/src/level_subset.cpp index aa096cb0b..2366f8cf1 100644 --- a/src/level_subset.cpp +++ b/src/level_subset.cpp @@ -17,24 +17,20 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #include #include #include #include #include -#include "app/setup.h" #include "level.h" #include "resources.h" -#include "app/globals.h" +#include "file_system.h" #include "video/surface.h" #include "level_subset.h" #include "lisp/parser.h" #include "lisp/lisp.h" -using namespace SuperTux; - static bool has_suffix(const std::string& data, const std::string& suffix) { if (data.length() >= suffix.length()) diff --git a/src/level_subset.h b/src/level_subset.h index c6ed9a995..40f4b754d 100644 --- a/src/level_subset.h +++ b/src/level_subset.h @@ -17,15 +17,12 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef SUPERTUX_LEVEL_SUBSET_H #define SUPERTUX_LEVEL_SUBSET_H #include #include -using namespace SuperTux; - /** This type holds meta-information about a level-subset. It could be extended to handle manipulation of subsets. */ class LevelSubset diff --git a/src/leveleditor.cpp b/src/leveleditor.cpp index b84b4c474..7cc0756da 100644 --- a/src/leveleditor.cpp +++ b/src/leveleditor.cpp @@ -45,8 +45,6 @@ #include "gui/button.h" #include "audio/sound_manager.h" #include "app/gettext.h" -#include "app/setup.h" -#include "app/globals.h" #include "sprite/sprite.h" #include "leveleditor.h" #include "resources.h" diff --git a/src/leveleditor.h b/src/leveleditor.h index 16ac9dafa..de4065b6d 100644 --- a/src/leveleditor.h +++ b/src/leveleditor.h @@ -17,10 +17,11 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef SUPERTUX_LEVELEDITOR_H #define SUPERTUX_LEVELEDITOR_H +#if 0 + #include #include @@ -150,3 +151,5 @@ private: }; #endif + +#endif diff --git a/src/lisp/parser.cpp b/src/lisp/parser.cpp index 08c5aa78f..65f163ad4 100644 --- a/src/lisp/parser.cpp +++ b/src/lisp/parser.cpp @@ -25,10 +25,10 @@ #include #include -#include "app/setup.h" -#include "app/tinygettext.h" +#include "tinygettext/tinygettext.h" #include "parser.h" #include "lisp.h" +#include "file_system.h" namespace lisp { @@ -58,7 +58,7 @@ Parser::parse(const std::string& filename) } if(dictionary_manager) { - dictionary_manager->add_directory(SuperTux::FileSystem::dirname(filename)); + dictionary_manager->add_directory(FileSystem::dirname(filename)); dictionary = & (dictionary_manager->get_dictionary()); } diff --git a/src/main.cpp b/src/main.cpp index bf94f28f7..8c3d7f8fb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,19 +36,22 @@ #include #include #include +#include #include "gameconfig.h" #include "resources.h" -#include "app/globals.h" -#include "app/setup.h" -#include "app/gettext.h" +#include "gettext.h" #include "audio/sound_manager.h" +#include "video/surface.h" #include "control/joystickkeyboardcontroller.h" #include "misc.h" +#include "title.h" #include "game_session.h" +#include "file_system.h" SDL_Surface* screen = 0; JoystickKeyboardController* main_controller = 0; +TinyGetText::DictionaryManager dictionary_manager; static void init_config() { @@ -75,12 +78,6 @@ static void find_directories() user_dir = home; user_dir += "/.supertux"; - // Remove .supertux config file from old versions - if(FileSystem::faccessible(user_dir)) { - std::cerr << "Removing old config file " << user_dir << "\n"; - remove(user_dir.c_str()); - } - // create directories std::string savedir = user_dir + "/save"; mkdir(user_dir.c_str(), 0755); @@ -205,6 +202,13 @@ static void init_sdl() } SDL_EnableUNICODE(1); + + // wait 100ms and clear SDL event queue because sometimes we have random + // joystick events in the queue on startup... + SDL_Delay(100); + SDL_Event dummy; + while(SDL_PollEvent(&dummy)) + ; } static void check_gl_error() @@ -335,6 +339,40 @@ static void quit_audio() } } +void wait_for_event(float min_delay, float max_delay) +{ + assert(min_delay <= max_delay); + + Uint32 min = (Uint32) (min_delay * 1000); + Uint32 max = (Uint32) (max_delay * 1000); + + SDL_Delay(min); + + // clear even queue + SDL_Event event; + while (SDL_PollEvent(&event)) + {} + + /* Handle events: */ + bool running = false; + Uint32 ticks = SDL_GetTicks(); + while(running) { + while(SDL_PollEvent(&event)) { + switch(event.type) { + case SDL_QUIT: + throw std::runtime_error("received window close"); + case SDL_KEYDOWN: + case SDL_JOYBUTTONDOWN: + case SDL_MOUSEBUTTONDOWN: + running = false; + } + } + if(SDL_GetTicks() - ticks >= (max - min)) + running = false; + SDL_Delay(10); + } +} + int main(int argc, char** argv) { #ifndef DEBUG // we want backtraces in debug mode so don't catch exceptions diff --git a/src/main.h b/src/main.h index d76f8abf6..3738c0039 100644 --- a/src/main.h +++ b/src/main.h @@ -17,24 +17,17 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __MAIN_H__ #define __MAIN_H__ -enum GlobalGameState { - /** the title screen is showing */ - STATE_TITLE, - /** the worldmap is shown */ - STATE_WORLDMAP, - /** a level is played */ - STATE_GAMESESSION -}; - void init_video(); +void wait_for_event(float min_delay, float max_delay); -class JoystickKeyboardController; +static const int SCREEN_WIDTH = 800; +static const int SCREEN_HEIGHT = 600; // global variables +class JoystickKeyboardController; extern JoystickKeyboardController* main_controller; #endif diff --git a/src/math/aatriangle.h b/src/math/aatriangle.h new file mode 100644 index 000000000..4a2d81ac2 --- /dev/null +++ b/src/math/aatriangle.h @@ -0,0 +1,49 @@ +#ifndef __AATRIANGLE_H__ +#define __AATRIANGLE_H__ + +#include "rectangle.h" + +/** + * An axis aligned triangle (ie. a triangle where 2 sides are parallel to the x- + * and y-axis. + */ +class AATriangle : public Rectangle +{ +public: + /** Directions: + * + * SOUTHEWEST NORTHEAST SOUTHEAST NORTHWEST + * * or *---* or * or *---* + * | \ \ | / | | / + * | \ \ | / | | / + * *---* * *---* * + * + * Deform flags: (see docs/aatriangletypes.png for details) + */ + enum Direction { + SOUTHWEST = 0, + NORTHEAST, + SOUTHEAST, + NORTHWEST, + DIRECTION_MASK = 0x0003, + DEFORM1 = 0x0010, + DEFORM2 = 0x0020, + DEFORM3 = 0x0030, + DEFORM4 = 0x0040, + DEFORM_MASK = 0x0070 + }; + + AATriangle() + : dir(SOUTHWEST) + { + } + AATriangle(const Vector& v1, const Vector& v2, int newdir) + : Rectangle(v1, v2), dir(newdir) + { + } + + int dir; +}; + +#endif + diff --git a/src/math/rectangle.h b/src/math/rectangle.h new file mode 100644 index 000000000..f6be7a5e4 --- /dev/null +++ b/src/math/rectangle.h @@ -0,0 +1,87 @@ +#ifndef __RECTANGLE_H__ +#define __RECTANGLE_H__ + +#include +#include "vector.h" + +/** This class represents a rectangle. + * (Implementation Note) We're using upper left and lower right point instead of + * upper left and width/height here, because that makes the collision dectection + * a little bit efficienter. + */ +class Rectangle +{ +public: + Rectangle() + { } + + Rectangle(const Vector& np1, const Vector& np2) + : p1(np1), p2(np2) + { + } + + Rectangle(float x1, float y1, float x2, float y2) + : p1(x1, y1), p2(x2, y2) + { + assert(p1.x <= p2.x && p1.y <= p2.y); + } + + float get_width() const + { return p2.x - p1.x; } + + float get_height() const + { return p2.y - p1.y; } + + Vector get_middle() const + { return Vector((p1.x+p2.x)/2, (p1.y+p2.y)/2); } + + void set_pos(const Vector& v) + { + move(v-p1); + } + + void set_height(float height) + { + p2.y = p1.y + height; + } + void set_width(float width) + { + p2.x = p1.x + width; + } + void set_size(float width, float height) + { + set_width(width); + set_height(height); + } + + void move(const Vector& v) + { + p1 += v; + p2 += v; + } + + bool inside(const Vector& v) const + { + return v.x >= p1.x && v.y >= p1.y && v.x < p2.x && v.y < p2.y; + } + bool inside(const Rectangle& other) const + { + if(p1.x >= other.p2.x || other.p1.x >= p2.x) + return false; + if(p1.y >= other.p2.y || other.p1.y >= p2.y) + return false; + + return true; + } + + // leave these 2 public to safe the headaches of set/get functions for such + // simple things :) + + /// upper left edge + Vector p1; + /// lower right edge + Vector p2; +}; + +#endif + diff --git a/src/math/vector.cpp b/src/math/vector.cpp new file mode 100644 index 000000000..7c914b38f --- /dev/null +++ b/src/math/vector.cpp @@ -0,0 +1,33 @@ +// $Id$ +// +// SuperTux - A Jump'n Run +// Copyright (C) 2004 Matthias Braun + +#include + +#include "math/vector.h" + +Vector Vector::unit() const +{ + return *this / norm(); +} + +float Vector::norm() const +{ + return sqrt(x*x + y*y); +} diff --git a/src/math/vector.h b/src/math/vector.h new file mode 100644 index 000000000..38c120426 --- /dev/null +++ b/src/math/vector.h @@ -0,0 +1,115 @@ +// $Id$ +// +// SuperTux - A Jump'n Run +// Copyright (C) 2004 Matthias Braun +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#ifndef SUPERTUX_VECTOR_H +#define SUPERTUX_VECTOR_H + +/** Simple two dimensional vector. */ +class Vector +{ +public: + Vector(float nx, float ny) + : x(nx), y(ny) + { } + Vector(const Vector& other) + : x(other.x), y(other.y) + { } + Vector() + : x(0), y(0) + { } + + bool operator ==(const Vector& other) const + { + return x == other.x && y == other.y; + } + + bool operator !=(const Vector& other) const + { + return !(x == other.x && y == other.y); + } + + const Vector& operator=(const Vector& other) + { + x = other.x; + y = other.y; + return *this; + } + + Vector operator+(const Vector& other) const + { + return Vector(x + other.x, y + other.y); + } + + Vector operator-(const Vector& other) const + { + return Vector(x - other.x, y - other.y); + } + + Vector operator*(float s) const + { + return Vector(x * s, y * s); + } + + Vector operator/(float s) const + { + return Vector(x / s, y / s); + } + + Vector operator-() const + { + return Vector(-x, -y); + } + + const Vector& operator +=(const Vector& other) + { + x += other.x; + y += other.y; + return *this; + } + + const Vector& operator *=(float val) + { + x *= val; + y *= val; + return *this; + } + + const Vector& operator /=(float val) + { + x /= val; + y /= val; + return *this; + } + + /// Scalar product of 2 vectors + float operator*(const Vector& other) const + { + return x*other.x + y*other.y; + } + + float norm() const; + Vector unit() const; + + // ... add the other operators as needed, I'm too lazy now ... + + float x, y; // leave this public, get/set methods just give me headaches + // for such simple stuff :) +}; + +#endif + diff --git a/src/misc.cpp b/src/misc.cpp index ee4822971..fcdd6f1ab 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -19,8 +19,13 @@ #include "misc.h" #include "main.h" #include "gameconfig.h" -#include "app/globals.h" #include "game_session.h" +#include "gui/menu.h" +#include "gui/button.h" +#include "title.h" +#include "resources.h" +#include "worldmap.h" +#include "gettext.h" #include "control/joystickkeyboardcontroller.h" Menu* main_menu = 0; diff --git a/src/misc.h b/src/misc.h index 26ac3387c..0978b1417 100644 --- a/src/misc.h +++ b/src/misc.h @@ -17,15 +17,6 @@ #ifndef SUPERTUX_MISC_H #define SUPERTUX_MISC_H -#include "app/setup.h" -#include "app/gettext.h" -#include "gui/menu.h" -#include "gameconfig.h" -#include "title.h" -#include "resources.h" -#include "worldmap.h" -#include "object/player.h" - enum OptionsMenuIDs { MNID_FULLSCREEN, MNID_SOUND, diff --git a/src/object/background.cpp b/src/object/background.cpp index a8c5edc28..4995e97a8 100644 --- a/src/object/background.cpp +++ b/src/object/background.cpp @@ -16,16 +16,16 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #include #include "background.h" -#include "app/globals.h" #include "camera.h" #include "video/drawing_context.h" #include "lisp/lisp.h" #include "lisp/writer.h" #include "object_factory.h" +#include "resources.h" +#include "main.h" Background::Background() : type(INVALID), layer(LAYER_BACKGROUND0), image(0) diff --git a/src/object/background.h b/src/object/background.h index 4b6253c51..233d85879 100644 --- a/src/object/background.h +++ b/src/object/background.h @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #ifndef SUPERTUX_BACKGROUND_H #define SUPERTUX_BACKGROUND_H @@ -25,8 +24,6 @@ #include "game_object.h" #include "serializable.h" -using namespace SuperTux; - class DisplayManager; namespace lisp { diff --git a/src/object/bell.h b/src/object/bell.h index 12f134f68..6241c6cf4 100644 --- a/src/object/bell.h +++ b/src/object/bell.h @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __BELL_H__ #define __BELL_H__ @@ -26,8 +25,6 @@ #include "sprite/sprite.h" #include "serializable.h" -using namespace SuperTux; - /** * A bell: When tux touches it, it begins ringing and you will respawn at this * position. diff --git a/src/object/block.h b/src/object/block.h index 2989ad85c..43321f14c 100644 --- a/src/object/block.h +++ b/src/object/block.h @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __BLOCK_H__ #define __BLOCK_H__ @@ -27,8 +26,6 @@ class Sprite; class Player; -using namespace SuperTux; - class Block : public MovingObject { public: diff --git a/src/object/bullet.cpp b/src/object/bullet.cpp index 0ee50dc2d..1b8279f1c 100644 --- a/src/object/bullet.cpp +++ b/src/object/bullet.cpp @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #include #include @@ -25,9 +24,9 @@ #include "resources.h" #include "camera.h" #include "sector.h" -#include "app/globals.h" #include "sprite/sprite_manager.h" #include "badguy/badguy.h" +#include "main.h" static const float BULLET_XM = 300; static const float BULLET_STARTING_YM = 0; diff --git a/src/object/bullet.h b/src/object/bullet.h index 58df31b14..6c49f843c 100644 --- a/src/object/bullet.h +++ b/src/object/bullet.h @@ -17,16 +17,13 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __BULLET_H__ #define __BULLET_H__ #include "moving_object.h" -#include "math/physic.h" +#include "physic.h" #include "sprite/sprite.h" -using namespace SuperTux; - enum BulletsKind { FIRE_BULLET, ICE_BULLET diff --git a/src/object/camera.cpp b/src/object/camera.cpp index f355917d2..476ca4123 100644 --- a/src/object/camera.cpp +++ b/src/object/camera.cpp @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #include #include @@ -30,12 +29,10 @@ #include "player.h" #include "tilemap.h" #include "game_session.h" -#include "app/globals.h" #include "sector.h" +#include "main.h" #include "object_factory.h" -using namespace SuperTux; - Camera::Camera(Sector* newsector) : sector(newsector), do_backscrolling(true), scrollchange(NONE), auto_idx(0), auto_t(0) diff --git a/src/object/camera.h b/src/object/camera.h index f8fbc4f8c..3c8d6c05d 100644 --- a/src/object/camera.h +++ b/src/object/camera.h @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #ifndef SUPERTUX_CAMERA_H #define SUPERTUX_CAMERA_H @@ -29,7 +28,6 @@ #include "serializable.h" #include "timer.h" -using namespace SuperTux; namespace lisp { class Lisp; } diff --git a/src/object/coin.h b/src/object/coin.h index 949ebfc7d..3befd26b3 100644 --- a/src/object/coin.h +++ b/src/object/coin.h @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __COIN_H__ #define __COIN_H__ @@ -26,8 +25,6 @@ class Sprite; -using namespace SuperTux; - class Coin : public MovingObject { public: diff --git a/src/object/fireworks.cpp b/src/object/fireworks.cpp index 18648e025..69244bfcf 100644 --- a/src/object/fireworks.cpp +++ b/src/object/fireworks.cpp @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #include #include "fireworks.h" @@ -25,12 +24,10 @@ #include "sector.h" #include "camera.h" #include "gameobjs.h" -#include "app/globals.h" +#include "main.h" #include "video/drawing_context.h" #include "audio/sound_manager.h" -using namespace SuperTux; - Fireworks::Fireworks() { timer.start(.2); diff --git a/src/object/flower.cpp b/src/object/flower.cpp index 4f52a2ba2..d07f71f4f 100644 --- a/src/object/flower.cpp +++ b/src/object/flower.cpp @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #include #include @@ -26,7 +25,6 @@ #include "camera.h" #include "sector.h" #include "player.h" -#include "app/globals.h" #include "sprite/sprite_manager.h" Flower::Flower(const Vector& pos, Type _type) diff --git a/src/object/flower.h b/src/object/flower.h index 8aa68cbd4..7e2956fa9 100644 --- a/src/object/flower.h +++ b/src/object/flower.h @@ -17,15 +17,12 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __FLOWER_H__ #define __FLOWER_H__ #include "moving_object.h" #include "sprite/sprite.h" -#include "math/physic.h" - -using namespace SuperTux; +#include "physic.h" class Flower : public MovingObject { diff --git a/src/object/gameobjs.cpp b/src/object/gameobjs.cpp index 6a5d391a4..e863be38c 100644 --- a/src/object/gameobjs.cpp +++ b/src/object/gameobjs.cpp @@ -24,7 +24,6 @@ #include #include -#include "app/globals.h" #include "tile.h" #include "tile_manager.h" #include "game_session.h" @@ -35,6 +34,7 @@ #include "tilemap.h" #include "video/drawing_context.h" #include "camera.h" +#include "main.h" BouncyCoin::BouncyCoin(const Vector& pos) : position(pos) diff --git a/src/object/gameobjs.h b/src/object/gameobjs.h index 6cbac9838..81a336a15 100644 --- a/src/object/gameobjs.h +++ b/src/object/gameobjs.h @@ -23,7 +23,7 @@ #include "video/surface.h" #include "timer.h" -#include "math/physic.h" +#include "physic.h" #include "game_object.h" #include "moving_object.h" #include "serializable.h" diff --git a/src/object/growup.cpp b/src/object/growup.cpp index 948955dce..32420f14d 100644 --- a/src/object/growup.cpp +++ b/src/object/growup.cpp @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #include #include @@ -26,7 +25,6 @@ #include "camera.h" #include "sector.h" #include "player.h" -#include "app/globals.h" #include "sprite/sprite_manager.h" GrowUp::GrowUp(const Vector& pos) diff --git a/src/object/growup.h b/src/object/growup.h index 4ea9ba9b5..b2407d82f 100644 --- a/src/object/growup.h +++ b/src/object/growup.h @@ -17,15 +17,12 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __GROWUP_H__ #define __GROWUP_H__ #include "moving_object.h" #include "sprite/sprite.h" -#include "math/physic.h" - -using namespace SuperTux; +#include "physic.h" class GrowUp : public MovingObject { diff --git a/src/object/oneup.h b/src/object/oneup.h index 505b98c2a..4c5794e39 100644 --- a/src/object/oneup.h +++ b/src/object/oneup.h @@ -17,15 +17,12 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __ONEUP_H__ #define __ONEUP_H__ #include "moving_object.h" #include "sprite/sprite.h" -#include "math/physic.h" - -using namespace SuperTux; +#include "physic.h" class OneUp : public MovingObject { diff --git a/src/object/particlesystem.cpp b/src/object/particlesystem.cpp index be1622a69..2642f7162 100644 --- a/src/object/particlesystem.cpp +++ b/src/object/particlesystem.cpp @@ -16,19 +16,18 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - #include #include #include #include "particlesystem.h" -#include "app/globals.h" #include "video/drawing_context.h" #include "lisp/parser.h" #include "lisp/lisp.h" #include "lisp/writer.h" +#include "resources.h" +#include "main.h" ParticleSystem::ParticleSystem() { diff --git a/src/object/particlesystem.h b/src/object/particlesystem.h index 4d1f79965..526fbdd55 100644 --- a/src/object/particlesystem.h +++ b/src/object/particlesystem.h @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #ifndef SUPERTUX_PARTICLESYSTEM_H #define SUPERTUX_PARTICLESYSTEM_H @@ -26,8 +25,6 @@ #include "game_object.h" #include "serializable.h" -using namespace SuperTux; - namespace lisp { class Lisp; } diff --git a/src/object/platform.h b/src/object/platform.h index a8d3db7a1..71200f940 100644 --- a/src/object/platform.h +++ b/src/object/platform.h @@ -17,15 +17,12 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __PLATFORM_H__ #define __PLATFORM_H__ #include "moving_object.h" #include "sprite/sprite.h" -using namespace SuperTux; - /** * This class is the base class for platforms that tux can stand on */ diff --git a/src/object/player.cpp b/src/object/player.cpp index 8093ab226..935713860 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -23,8 +23,7 @@ #include #include -#include "app/globals.h" -#include "app/gettext.h" +#include "gettext.h" #include "sprite/sprite_manager.h" #include "player.h" #include "tile.h" diff --git a/src/object/player.h b/src/object/player.h index 4d7ce216e..c7693b441 100644 --- a/src/object/player.h +++ b/src/object/player.h @@ -27,12 +27,10 @@ #include "video/surface.h" #include "moving_object.h" #include "sprite/sprite.h" -#include "math/physic.h" +#include "physic.h" #include "control/controller.h" #include "player_status.h" -using namespace SuperTux; - class BadGuy; class Portable; diff --git a/src/object/portable.h b/src/object/portable.h index da77919da..bfcef3f3b 100644 --- a/src/object/portable.h +++ b/src/object/portable.h @@ -17,14 +17,11 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __PORTABLE_H__ #define __PORTABLE_H__ #include "moving_object.h" -using namespace SuperTux; - /** * An object that inherits from this object is considered "portable" and can * be carried around by the player. diff --git a/src/object/rock.h b/src/object/rock.h index ff0181016..f0ab98a2a 100644 --- a/src/object/rock.h +++ b/src/object/rock.h @@ -22,7 +22,7 @@ #define __ROCK_H__ #include "moving_object.h" -#include "math/physic.h" +#include "physic.h" #include "lisp/lisp.h" #include "portable.h" #include "serializable.h" diff --git a/src/object/specialriser.cpp b/src/object/specialriser.cpp index 24ab26f95..0058d6d76 100644 --- a/src/object/specialriser.cpp +++ b/src/object/specialriser.cpp @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #include #include @@ -25,7 +24,6 @@ #include "resources.h" #include "camera.h" #include "sector.h" -#include "app/globals.h" #include "sprite/sprite_manager.h" SpecialRiser::SpecialRiser(MovingObject* _child) diff --git a/src/object/specialriser.h b/src/object/specialriser.h index 01f006e03..51932564d 100644 --- a/src/object/specialriser.h +++ b/src/object/specialriser.h @@ -17,14 +17,11 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __SPECIALRISE_H__ #define __SPECIALRISE_H__ #include "moving_object.h" -using namespace SuperTux; - /** * special object that contains another object and slowly rises it out of a * bonus block. diff --git a/src/object/star.h b/src/object/star.h index 8fd2760b1..2ad8da626 100644 --- a/src/object/star.h +++ b/src/object/star.h @@ -17,15 +17,12 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __STAR_H__ #define __STAR_H__ #include "moving_object.h" #include "sprite/sprite.h" -#include "math/physic.h" - -using namespace SuperTux; +#include "physic.h" class Star : public MovingObject { diff --git a/src/object/tilemap.cpp b/src/object/tilemap.cpp index 3832495c5..e845a2dbf 100644 --- a/src/object/tilemap.cpp +++ b/src/object/tilemap.cpp @@ -30,10 +30,10 @@ #include "tile.h" #include "resources.h" #include "tile_manager.h" -#include "app/globals.h" #include "lisp/lisp.h" #include "lisp/writer.h" #include "object_factory.h" +#include "main.h" TileMap::TileMap() : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES), diff --git a/src/object/tilemap.h b/src/object/tilemap.h index 8f389c0ef..b56ce0bce 100644 --- a/src/object/tilemap.h +++ b/src/object/tilemap.h @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #ifndef SUPERTUX_TILEMAP_H #define SUPERTUX_TILEMAP_H @@ -31,8 +30,6 @@ namespace lisp { class Lisp; } -using namespace SuperTux; - class Level; class TileManager; class Tile; diff --git a/src/object/unstable_tile.h b/src/object/unstable_tile.h index 90cab4e11..77a7cc2c8 100644 --- a/src/object/unstable_tile.h +++ b/src/object/unstable_tile.h @@ -17,20 +17,17 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __UNSTABLE_TILE_H__ #define __UNSTABLE_TILE_H__ #include "moving_object.h" #include "lisp/lisp.h" -#include "math/physic.h" +#include "physic.h" #include "timer.h" class Sprite; class Player; -using namespace SuperTux; - /** A tile that starts falling down if tux stands to long on it */ class UnstableTile : public MovingObject { diff --git a/src/object_factory.h b/src/object_factory.h index bbf353be6..efda690ce 100644 --- a/src/object_factory.h +++ b/src/object_factory.h @@ -26,8 +26,6 @@ #include "game_object.h" #include "math/vector.h" -using namespace SuperTux; - class Factory { public: diff --git a/src/physic.cpp b/src/physic.cpp new file mode 100644 index 000000000..39ad54e73 --- /dev/null +++ b/src/physic.cpp @@ -0,0 +1,132 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2004 Tobias Glaesser +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +#include + +#include "physic.h" + +Physic::Physic() + : ax(0), ay(0), vx(0), vy(0), gravity_enabled(true) +{ +} + +Physic::~Physic() +{ +} + +void +Physic::reset() +{ + ax = ay = vx = vy = 0; + gravity_enabled = true; +} + +void +Physic::set_velocity_x(float nvx) +{ + vx = nvx; +} + +void +Physic::set_velocity_y(float nvy) +{ + vy = -nvy; +} + +void +Physic::set_velocity(float nvx, float nvy) +{ + vx = nvx; + vy = -nvy; +} + +void Physic::inverse_velocity_x() +{ +vx = -vx; +} + +void Physic::inverse_velocity_y() +{ +vy = -vy; +} + +float +Physic::get_velocity_x() +{ + return vx; +} + +float +Physic::get_velocity_y() +{ + return -vy; +} + +void +Physic::set_acceleration_x(float nax) +{ + ax = nax; +} + +void +Physic::set_acceleration_y(float nay) +{ + ay = -nay; +} + +void +Physic::set_acceleration(float nax, float nay) +{ + ax = nax; + ay = -nay; +} + +float +Physic::get_acceleration_x() +{ + return ax; +} + +float +Physic::get_acceleration_y() +{ + return -ay; +} + +void +Physic::enable_gravity(bool enable_gravity) +{ + gravity_enabled = enable_gravity; +} + +Vector +Physic::get_movement(float elapsed_time) +{ + float grav = gravity_enabled ? 1000 : 0; + + Vector result( + vx * elapsed_time + ax * elapsed_time * elapsed_time, + vy * elapsed_time + (ay + grav) * elapsed_time * elapsed_time + ); + vx += ax * elapsed_time; + vy += (ay + grav) * elapsed_time; + + return result; +} + diff --git a/src/physic.h b/src/physic.h new file mode 100644 index 000000000..86114eb8c --- /dev/null +++ b/src/physic.h @@ -0,0 +1,77 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2004 Tobias Glaesser +// +// 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 SUPERTUX_PHYSIC_H +#define SUPERTUX_PHYSIC_H + +#include "math/vector.h" + +/// Physics engine. +/** This is a very simplistic physics engine handling accelerated and constant + * movement along with gravity. + */ +class Physic +{ +public: + Physic(); + ~Physic(); + + /// Resets all velocities and accelerations to 0. + void reset(); + + /// Sets velocity to a fixed value. + void set_velocity(float vx, float vy); + + void set_velocity_x(float vx); + void set_velocity_y(float vy); + + /// Velocities invertion. + void inverse_velocity_x(); + void inverse_velocity_y(); + + float get_velocity_x(); + float get_velocity_y(); + + /// Set acceleration. + /** Sets acceleration applied to the object. (Note that gravity is + * eventually added to the vertical acceleration) + */ + void set_acceleration(float ax, float ay); + + void set_acceleration_x(float ax); + void set_acceleration_y(float ay); + + float get_acceleration_x(); + float get_acceleration_y(); + + /// Enables or disables handling of gravity. + void enable_gravity(bool gravity_enabled); + + Vector get_movement(float elapsed_time); + +private: + /// horizontal and vertical acceleration + float ax, ay; + /// horizontal and vertical velocity + float vx, vy; + /// should we respect gravity in out calculations? + bool gravity_enabled; +}; + +#endif diff --git a/src/resources.cpp b/src/resources.cpp index 95bf48dfb..3544a5260 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -16,19 +16,20 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #include -#include "app/globals.h" #include "sprite/sprite_manager.h" -#include "app/setup.h" #include "gui/menu.h" #include "gui/button.h" #include "resources.h" +#include "file_system.h" #include "tile_manager.h" #include "object/gameobjs.h" #include "object/player.h" +std::string datadir; +std::string user_dir; + MusicRef herring_song; MusicRef level_end_song; MusicRef credits_song; @@ -37,6 +38,8 @@ SpriteManager* sprite_manager = 0; TileManager* tile_manager = 0; SoundManager* sound_manager = 0; +MouseCursor* mouse_cursor = 0; + Font* gold_text; Font* blue_text; Font* gray_text; @@ -56,7 +59,7 @@ void load_shared() arrow_right = new Surface(datadir + "/images/icons/right.png", true); /* Load the mouse-cursor */ - mouse_cursor = new MouseCursor( datadir + "/images/status/mousecursor.png",1); + mouse_cursor = new MouseCursor(datadir + "/images/status/mousecursor.png"); MouseCursor::set_current(mouse_cursor); /* Load global images: */ diff --git a/src/resources.h b/src/resources.h index 35f264f9e..c3bcbaaa5 100644 --- a/src/resources.h +++ b/src/resources.h @@ -19,16 +19,16 @@ #ifndef SUPERTUX_RESOURCES_H #define SUPERTUX_RESOURCES_H +#include #include "audio/musicref.h" -using namespace SuperTux; - class SpriteManager; class Menu; class Font; class Surface; class SoundManager; class TileManager; +class MouseCursor; extern Surface* img_super_bkgd; extern Surface* tux_life; @@ -47,6 +47,8 @@ extern Menu* game_menu; extern Menu* options_menu; extern Menu* load_game_menu; +extern MouseCursor* mouse_cursor; + extern Font* gold_text; extern Font* white_text; extern Font* blue_text; @@ -55,6 +57,9 @@ extern Font* white_small_text; extern Font* white_big_text; extern Font* yellow_nums; +extern std::string datadir; +extern std::string user_dir; + /** maps a virtual resource path to a real path (ie. levels/bla is mapped to * $DATADIR/levels/bla or $HOME/.supertux/levels/bla) * All paths inside the game should be handled in as virtual paths and then diff --git a/src/scripting/Jamfile b/src/scripting/Jamfile new file mode 100644 index 000000000..eb5c4929a --- /dev/null +++ b/src/scripting/Jamfile @@ -0,0 +1,49 @@ +SubDir TOP src scripting ; + +if $(MINISWIG) +{ + ## MiniSwigRule outputcppfile : inputfile : modulename : flags + rule MiniSwigRule + { + local sources = [ SearchSource $(>) ] ; + local cppfile = [ LocateTarget $(<) : $(SUBDIR) ] ; + local headerfile = [ LocateTarget $(<:S=.h) : $(SUBDIR) ] ; + SEARCH on $(headerfile) = $(SOURCH_SOURCE) ; + + MiniSwig $(cppfile) : $(sources) ; + CPPFLAGS on $(cppfile) = $(CPPFLAGS) ; + headerfile on $(cppfile) = $(headerfile) ; + modulename on $(cppfile) = $(3) ; + FLAGS on $(cppfile) = $(4) ; + + local object = [ CompileObject $(cppfile) ] ; + + return $(object) ; + } + + rule MiniSwig + { + Depends $(<) : $(>) $(MINISWIG) ; + Clean clean : $(<) ; + } + + actions MiniSwig bind headerfile + { + $(CPP) -x c $(CPPFLAGS) $(>) -o $(LOCATE_OBJECTS)/miniswig.tmp + $(MINISWIG) --output-cpp $(<) --input $(LOCATE_OBJECTS)/miniswig.tmp --output-hpp $(headerfile) --module $(modulename) $(FLAGS) +# rm -f $(LOCATE_OBJECTS)/miniswig.tmp + } +} + +wrapper_sources = [ Filter [ Wildcard *.cpp *.h ] : wrapper.cpp wrapper.h ] ; +if ! $(MINISWIG) +{ + wrapper_sources += wrapper.cpp ; +} +wrapper_objects = [ CompileObjects $(wrapper_sources) ] ; +if $(MINISWIG) +{ + wrapper_objects += + [ MiniSwigRule wrapper.cpp : wrapper.interface.h : supertux : --select-namespace Scripting ] ; +} + diff --git a/src/scripting/camera.cpp b/src/scripting/camera.cpp new file mode 100644 index 000000000..82c5b8755 --- /dev/null +++ b/src/scripting/camera.cpp @@ -0,0 +1,34 @@ +#include + +#include +#include +#include "camera.h" + +#define NOIMPL printf("%s not implemented.\n", __PRETTY_FUNCTION__); + +namespace Scripting +{ + Camera::Camera() + { } + + Camera::~Camera() + { } + + void + Camera::shake(float , float , float ) + { + NOIMPL; + } + + void + Camera::set_pos(float , float ) + { + NOIMPL; + } + + void + Camera::set_mode(const std::string& ) + { + NOIMPL; + } +} diff --git a/src/scripting/camera.h b/src/scripting/camera.h new file mode 100644 index 000000000..add5e5f06 --- /dev/null +++ b/src/scripting/camera.h @@ -0,0 +1,26 @@ +#ifndef __CAMERA_H__ +#define __CAMERA_H__ + +namespace Scripting +{ + +class Camera +{ +public: +#ifndef SCRIPTING_API + Camera(); + ~Camera(); +#endif + + /** Shake the camera */ + void shake(float speed, float x, float y); + /** Set camera to a specific coordinate */ + void set_pos(float x, float y); + /** Set camera to a specific mode, can be "normal", "manual" */ + void set_mode(const std::string& mode); +}; + +} + +#endif + diff --git a/src/scripting/display.cpp b/src/scripting/display.cpp new file mode 100644 index 000000000..6da4e875d --- /dev/null +++ b/src/scripting/display.cpp @@ -0,0 +1,21 @@ +#include + +#include +#include +#include "display.h" + +#define NOIMPL printf(__FUNCTION__ " not implemented\n"); + +namespace Scripting +{ + Display::Display() + {} + + Display::~Display() + {} + + void + Display::set_effect(const std::string& ) + {} +} + diff --git a/src/scripting/display.h b/src/scripting/display.h new file mode 100644 index 000000000..0cd272018 --- /dev/null +++ b/src/scripting/display.h @@ -0,0 +1,21 @@ +#ifndef __DISPLAY_H__ +#define __DISPLAY_H__ + +namespace Scripting +{ + +class Display +{ +public: +#ifndef SCRIPTING_API + Display(); + ~Display(); +#endif + + void set_effect(const std::string& effect); +}; + +} + +#endif + diff --git a/src/scripting/functions.cpp b/src/scripting/functions.cpp new file mode 100644 index 000000000..b0b9429a0 --- /dev/null +++ b/src/scripting/functions.cpp @@ -0,0 +1,14 @@ +#include +#include "functions.h" + +namespace Scripting +{ + +void wait(float secs) +{ + (void) secs; + printf("Wait not implemented.\n"); +} + +} + diff --git a/src/scripting/functions.h b/src/scripting/functions.h new file mode 100644 index 000000000..e1769c099 --- /dev/null +++ b/src/scripting/functions.h @@ -0,0 +1,12 @@ +#ifndef __FUNCTIONS_H__ +#define __FUNCTIONS_H__ + +namespace Scripting +{ + +void wait(float secs); + +} + +#endif + diff --git a/src/scripting/level.cpp b/src/scripting/level.cpp new file mode 100644 index 000000000..d29e18b65 --- /dev/null +++ b/src/scripting/level.cpp @@ -0,0 +1,28 @@ +#include + +#include +#include +#include "level.h" + +#define NOIMPL printf("%s not implemented.\n", __PRETTY_FUNCTION__); + +namespace Scripting +{ + Level::Level() + {} + + Level::~Level() + {} + + void + Level::finish() + { + NOIMPL; + } + + void + Level::spawn(const std::string& , const std::string& ) + { + NOIMPL; + } +} diff --git a/src/scripting/level.h b/src/scripting/level.h new file mode 100644 index 000000000..e0217424d --- /dev/null +++ b/src/scripting/level.h @@ -0,0 +1,24 @@ +#ifndef __LEVEL_H__ +#define __LEVEL_H__ + +namespace Scripting +{ + +class Level +{ +public: +#ifndef SCRIPTING_API + Level(); + ~Level(); +#endif + + /** Instantly finish the currently played level */ + void finish(); + /** spawn tux at specified sector and spawnpoint */ + void spawn(const std::string& sector, const std::string& spawnpoint); +}; + +} + +#endif + diff --git a/src/scripting/script_interpreter.h b/src/scripting/script_interpreter.h new file mode 100644 index 000000000..0ebe95238 --- /dev/null +++ b/src/scripting/script_interpreter.h @@ -0,0 +1,17 @@ +#ifndef __SCRIPT_INTERPRETER_H__ +#define __SCRIPT_INTERPRETER_H__ + +class ScriptInterpreter +{ +public: + ScriptInterpreter(); + ~ScriptInterpreter(); + + void load_script(const std::istream& in); + void run_script(); + void resume_script(); + bool script_suspended() const; +}; + +#endif + diff --git a/src/scripting/scripted_object.cpp b/src/scripting/scripted_object.cpp new file mode 100644 index 000000000..269475193 --- /dev/null +++ b/src/scripting/scripted_object.cpp @@ -0,0 +1,75 @@ +#include + +#include +#include +#include "scripted_object.h" + +#define NOIMPL printf("%s not implemented.\n", __PRETTY_FUNCTION__) + +namespace Scripting +{ + ScriptedObject::ScriptedObject() + {} + + ScriptedObject::~ScriptedObject() + {} + + void + ScriptedObject::set_animation(const std::string& ) + { + NOIMPL; + } + + std::string + ScriptedObject::get_animation() + { + NOIMPL; + return ""; + } + + void + ScriptedObject::move(float , float ) + { + NOIMPL; + } + + void + ScriptedObject::set_pos(float , float ) + { + NOIMPL; + } + + float + ScriptedObject::get_pos_x() + { + NOIMPL; + return -1; + } + + float + ScriptedObject::get_pos_y() + { + NOIMPL; + return -1; + } + + void + ScriptedObject::set_velocity(float , float ) + { + NOIMPL; + } + + float + ScriptedObject::get_velocity_x() + { + NOIMPL; + return -1; + } + + float + ScriptedObject::get_velocity_y() + { + NOIMPL; + return -1; + } +} diff --git a/src/scripting/scripted_object.h b/src/scripting/scripted_object.h new file mode 100644 index 000000000..b22fd0888 --- /dev/null +++ b/src/scripting/scripted_object.h @@ -0,0 +1,30 @@ +#ifndef __SCRIPTED_OBJECT_H__ +#define __SCRIPTED_OBJECT_H__ + +namespace Scripting +{ + +class ScriptedObject +{ +public: +#ifndef SCRIPTING_API + ScriptedObject(); + virtual ~ScriptedObject(); +#endif + + void set_animation(const std::string& animation); + std::string get_animation(); + + void move(float x, float y); + void set_pos(float x, float y); + float get_pos_x(); + float get_pos_y(); + void set_velocity(float x, float y); + float get_velocity_x(); + float get_velocity_y(); +}; + +} + +#endif + diff --git a/src/scripting/semantic.cache b/src/scripting/semantic.cache new file mode 100644 index 000000000..02ff11e27 --- /dev/null +++ b/src/scripting/semantic.cache @@ -0,0 +1,75 @@ +;; Object semantic.cache +;; SEMANTICDB Tags save file +(semanticdb-project-database "semantic.cache" + :file "semantic.cache" + :tables (list + (semanticdb-table "camera.cpp" + :file "camera.cpp" + :pointmax 435 + :major-mode 'c++-mode + :tokens '(("config.h" include t nil nil [1 20]) ("string" include t nil nil [22 39]) ("stdio.h" include t nil nil [40 58]) ("camera.h" include nil nil nil [59 78]) ("NOIMPL" variable nil nil ((const . t)) nil nil [80 152]) ("Scripting" type "namespace" (("Camera" function ("Camera" type "class") nil ((parent . "Camera") (constructor . t)) nil ((reparse-symbol . namespacesubparts)) [179 201]) ("Camera" function "void" nil ((parent . "Camera") (destructor . t)) nil ((reparse-symbol . namespacesubparts)) [205 228]) ("shake" function ("void") (("" variable "float" nil nil nil nil [255 262]) ("" variable "float" nil nil nil nil [263 270]) ("" variable "float" nil nil nil nil [271 278])) ((parent . "Camera")) nil ((reparse-symbol . namespacesubparts)) [234 298]) ("set_pos" function ("void") (("" variable "float" nil nil nil nil [327 334]) ("" variable "float" nil nil nil nil [335 342])) ((parent . "Camera")) nil ((reparse-symbol . namespacesubparts)) [304 362]) ("set_mode" function ("void") (("" variable ("std::string" type "class") nil ((const . t)) nil nil [390 410])) ((parent . "Camera")) nil ((reparse-symbol . namespacesubparts)) [366 430])) nil nil nil nil [155 434])) + :unmatched-syntax '((punctuation 152 . 153)) + ) + (semanticdb-table "camera.h" + :file "camera.h" + :pointmax 434 + :major-mode 'c++-mode + :tokens '(("__CAMERA_H__" variable nil nil ((const . t)) nil nil [22 53]) ("Scripting" type "namespace" (("Camera" type "class" (("public" label ((reparse-symbol . classsubparts)) [82 89]) ("Camera" function ("Camera" type "class") nil ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [116 125]) ("Camera" function "void" nil ((destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [130 140]) ("shake" function ("void") (("speed" variable "float" nil nil nil nil [192 204]) ("x" variable "float" nil nil nil nil [205 213]) ("y" variable "float" nil nil nil nil [214 222])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [181 223]) ("set_pos" function ("void") (("x" variable "float" nil nil nil nil [288 296]) ("y" variable "float" nil nil nil nil [297 305])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [275 306]) ("set_mode" function ("void") (("mode" variable ("std::string" type "class") nil ((const . t)) nil nil [393 417])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [379 418])) nil nil nil ((reparse-symbol . namespacesubparts)) [67 421])) nil nil nil nil [44 424])) + :unmatched-syntax 'nil + ) + (semanticdb-table "sound.h" + :file "sound.h" + :pointmax 261 + :major-mode 'c++-mode + :tokens '(("__SOUND_H__" variable nil nil ((const . t)) nil nil [21 51]) ("Scripting" type "namespace" (("Sound" type "class" (("public" label ((reparse-symbol . classsubparts)) [79 86]) ("play_music" function ("void") (("musicfile" variable ("std::string" type "class") nil ((const . t)) nil nil [107 136])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [91 137]) ("play_sound" function ("void") (("soundfile" variable ("std::string" type "class") nil ((const . t)) nil nil [158 187])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [142 188]) ("Sound" function ("Sound" type "class") nil ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [216 224]) ("Sound" function "void" nil ((destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [229 238])) nil nil nil ((reparse-symbol . namespacesubparts)) [65 248])) nil nil nil nil [42 251])) + :unmatched-syntax 'nil + ) + (semanticdb-table "sound.cpp" + :file "sound.cpp" + :pointmax 364 + :major-mode 'c++-mode + :tokens '(("config.h" include t nil nil [1 20]) ("string" include t nil nil [22 39]) ("stdio.h" include t nil nil [40 58]) ("sound.h" include nil nil nil [59 77]) ("NOIMPL" variable nil nil ((const . t)) nil nil [79 151]) ("Scripting" type "namespace" (("Sound" function ("Sound" type "class") nil ((parent . "Sound") (constructor . t)) nil ((reparse-symbol . namespacesubparts)) [179 198]) ("Sound" function "void" nil ((parent . "Sound") (destructor . t)) nil ((reparse-symbol . namespacesubparts)) [202 223]) ("play_music" function ("void") (("" variable ("std::string" type "class") nil ((const . t)) nil nil [252 272])) ((parent . "Sound")) nil ((reparse-symbol . namespacesubparts)) [227 292]) ("play_sound" function ("void") (("" variable ("std::string" type "class") nil ((const . t)) nil nil [321 341])) ((parent . "Sound")) nil ((reparse-symbol . namespacesubparts)) [296 361])) nil nil nil nil [154 363])) + :unmatched-syntax '((punctuation 151 . 152)) + ) + (semanticdb-table "level.cpp" + :file "level.cpp" + :pointmax 355 + :major-mode 'c++-mode + :tokens '(("config.h" include t nil nil [1 20]) ("string" include t nil nil [22 39]) ("stdio.h" include t nil nil [40 58]) ("level.h" include nil nil nil [59 77]) ("NOIMPL" variable nil nil ((const . t)) nil nil [79 151]) ("Scripting" type "namespace" (("Level" function ("Level" type "class") nil ((parent . "Level") (constructor . t)) nil ((reparse-symbol . namespacesubparts)) [178 197]) ("Level" function "void" nil ((parent . "Level") (destructor . t)) nil ((reparse-symbol . namespacesubparts)) [201 221]) ("finish" function ("void") nil ((parent . "Level")) nil ((reparse-symbol . namespacesubparts)) [225 267]) ("spawn" function ("void") (("" variable ("std::string" type "class") nil ((const . t)) nil nil [291 311]) ("" variable ("std::string" type "class") nil ((const . t)) nil nil [312 332])) ((parent . "Level")) nil ((reparse-symbol . namespacesubparts)) [271 352])) nil nil nil nil [154 354])) + :unmatched-syntax '((punctuation 151 . 152)) + ) + (semanticdb-table "level.h" + :file "level.h" + :pointmax 363 + :major-mode 'c++-mode + :tokens '(("__LEVEL_H__" variable nil nil ((const . t)) nil nil [21 51]) ("Scripting" type "namespace" (("Level" type "class" (("public" label ((reparse-symbol . classsubparts)) [79 86]) ("Level" function ("Level" type "class") nil ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [113 121]) ("Level" function "void" nil ((destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [126 135]) ("finish" function ("void") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [203 217]) ("spawn" function ("void") (("sector" variable ("std::string" type "class") nil ((const . t)) nil nil [289 315]) ("spawnpoint" variable ("std::string" type "class") nil ((const . t)) nil nil [316 346])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [278 347])) nil nil nil ((reparse-symbol . namespacesubparts)) [65 350])) nil nil nil nil [42 353])) + :unmatched-syntax 'nil + ) + (semanticdb-table "scripted_object.cpp" + :file "scripted_object.cpp" + :pointmax 952 + :major-mode 'c++-mode + :tokens '(("config.h" include t nil nil [1 20]) ("string" include t nil nil [22 39]) ("stdio.h" include t nil nil [40 58]) ("scripted_object.h" include nil nil nil [59 87]) ("NOIMPL" variable nil nil ((const . t)) nil nil [89 161]) ("Scripting" type "namespace" (("ScriptedObject" function ("ScriptedObject" type "class") nil ((parent . "ScriptedObject") (constructor . t)) nil ((reparse-symbol . namespacesubparts)) [187 224]) ("ScriptedObject" function "void" nil ((parent . "ScriptedObject") (destructor . t)) nil ((reparse-symbol . namespacesubparts)) [228 266]) ("set_animation" function ("void") (("" variable ("std::string" type "class") nil ((const . t)) nil nil [307 327])) ((parent . "ScriptedObject")) nil ((reparse-symbol . namespacesubparts)) [270 347]) ("get_animation" function ("std::string" type "class") nil ((parent . "ScriptedObject")) nil ((reparse-symbol . namespacesubparts)) [351 431]) ("move" function ("void") (("" variable "float" nil nil nil nil [463 470]) ("" variable "float" nil nil nil nil [471 478])) ((parent . "ScriptedObject")) nil ((reparse-symbol . namespacesubparts)) [435 498]) ("set_pos" function ("void") (("" variable "float" nil nil nil nil [533 540]) ("" variable "float" nil nil nil nil [541 548])) ((parent . "ScriptedObject")) nil ((reparse-symbol . namespacesubparts)) [502 568]) ("get_pos_x" function ("float") nil ((parent . "ScriptedObject")) nil ((reparse-symbol . namespacesubparts)) [572 642]) ("get_pos_y" function ("float") nil ((parent . "ScriptedObject")) nil ((reparse-symbol . namespacesubparts)) [646 716]) ("set_velocity" function ("void") (("" variable "float" nil nil nil nil [756 763]) ("" variable "float" nil nil nil nil [764 771])) ((parent . "ScriptedObject")) nil ((reparse-symbol . namespacesubparts)) [720 791]) ("get_velocity_x" function ("float") nil ((parent . "ScriptedObject")) nil ((reparse-symbol . namespacesubparts)) [795 870]) ("get_velocity_y" function ("float") nil ((parent . "ScriptedObject")) nil ((reparse-symbol . namespacesubparts)) [874 949])) nil nil nil nil [163 951])) + :unmatched-syntax '((punctuation 635 . 636) (punctuation 634 . 635) (symbol 620 . 634) (FLOAT 612 . 617)) + ) + (semanticdb-table "scripted_object.h" + :file "scripted_object.h" + :pointmax 514 + :major-mode 'c++-mode + :tokens '(("__SCRIPTED_OBJECT_H__" variable nil nil ((const . t)) nil nil [31 71]) ("Scripting" type "namespace" (("ScriptedObject" type "class" (("public" label ((reparse-symbol . classsubparts)) [108 115]) ("ScriptedObject" function ("ScriptedObject" type "class") nil ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [142 159]) ("ScriptedObject" function "void" nil ((typemodifiers "virtual") (destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [164 190]) ("set_animation" function ("void") (("animation" variable ("std::string" type "class") nil ((const . t)) nil nil [222 251])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [203 252]) ("get_animation" function ("std::string" type "class") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [257 285]) ("move" function ("void") (("x" variable "float" nil nil nil nil [301 309]) ("y" variable "float" nil nil nil nil [310 318])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [291 319]) ("set_pos" function ("void") (("x" variable "float" nil nil nil nil [337 345]) ("y" variable "float" nil nil nil nil [346 354])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [324 355]) ("get_pos_x" function ("float") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [360 378]) ("get_pos_y" function ("float") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [383 401]) ("set_velocity" function ("void") (("x" variable "float" nil nil nil nil [424 432]) ("y" variable "float" nil nil nil nil [433 441])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [406 442]) ("get_velocity_x" function ("float") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [447 470]) ("get_velocity_y" function ("float") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [475 498])) nil nil nil ((reparse-symbol . namespacesubparts)) [85 501])) nil nil nil nil [62 504])) + ) + (semanticdb-table "display.cpp" + :file "display.cpp" + :pointmax 280 + :major-mode 'c++-mode + :tokens '(("config.h" include t nil nil [1 20]) ("string" include t nil nil [22 39]) ("stdio.h" include t nil nil [40 58]) ("display.h" include nil nil nil [59 79]) ("NOIMPL" variable nil nil ((const . t)) nil nil [81 142]) ("Scripting" type "namespace" (("Display" function ("Display" type "class") nil ((parent . "Display") (constructor . t)) nil ((reparse-symbol . namespacesubparts)) [169 192]) ("Display" function "void" nil ((parent . "Display") (destructor . t)) nil ((reparse-symbol . namespacesubparts)) [196 220]) ("set_effect" function ("void") (("effect" variable ("std::string" type "class") nil ((const . t)) nil ((dirty . t)) [251 271])) ((parent . "Display")) nil ((reparse-symbol . namespacesubparts)) [224 276])) nil nil nil nil [145 278])) + :unmatched-syntax '((punctuation 142 . 143)) + ) + (semanticdb-table "display.h" + :file "display.h" + :pointmax 217 + :major-mode 'c++-mode + :tokens '(("__DISPLAY_H__" variable nil nil ((const . t)) nil nil [23 55]) ("Scripting" type "namespace" (("Display" type "class" (("public" label ((reparse-symbol . classsubparts)) [85 92]) ("Display" function ("Display" type "class") nil ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [119 129]) ("Display" function "void" nil ((destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [134 145]) ("set_effect" function ("void") (("effect" variable ("std::string" type "class") nil ((const . t)) nil nil [174 200])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [158 201])) nil nil nil ((reparse-symbol . namespacesubparts)) [69 204])) nil nil nil nil [46 207])) + ) + ) + ) diff --git a/src/scripting/sound.cpp b/src/scripting/sound.cpp new file mode 100644 index 000000000..a0589c7f4 --- /dev/null +++ b/src/scripting/sound.cpp @@ -0,0 +1,29 @@ +#include + +#include +#include +#include "sound.h" + +#define NOIMPL printf("%s not implemented.\n", __PRETTY_FUNCTION__); + +namespace Scripting +{ + + Sound::Sound() + {} + + Sound::~Sound() + {} + + void + Sound::play_music(const std::string& ) + { + NOIMPL; + } + + void + Sound::play_sound(const std::string& ) + { + NOIMPL; + } +} diff --git a/src/scripting/sound.h b/src/scripting/sound.h new file mode 100644 index 000000000..66ac95a4b --- /dev/null +++ b/src/scripting/sound.h @@ -0,0 +1,22 @@ +#ifndef __SOUND_H__ +#define __SOUND_H__ + +namespace Scripting +{ + +class Sound +{ +public: + void play_music(const std::string& musicfile); + void play_sound(const std::string& soundfile); + +#ifndef SCRIPTING_API + Sound(); + ~Sound(); +#endif +}; + +} + +#endif + diff --git a/src/scripting/wrapper.cpp b/src/scripting/wrapper.cpp new file mode 100644 index 000000000..a7dd2f3df --- /dev/null +++ b/src/scripting/wrapper.cpp @@ -0,0 +1,381 @@ +/** + * WARNING: This file is automatically generated from './build/i686-pc-linux-gnu/debug/miniswig.tmp' - do not change + */ + +#include +#include +#include +#include "wrapper_util.h" +#include "wrapper.interface.h" + +using namespace Scripting; + +static int Display_release_wrapper(SQUserPointer ptr, int ) +{ + Display* _this = reinterpret_cast (ptr); + delete _this; + return 0; +} + +static int Display_construct_wrapper(HSQUIRRELVM v) +{ + Display* _this = new Display(); + sq_setinstanceup(v, 1, _this); + sq_setreleasehook(v, 1, Display_release_wrapper); + + return 0; +} + +static int Display_set_effect_wrapper(HSQUIRRELVM v) +{ + Display* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + const char* arg0; + sq_getstring(v, 2, &arg0); + + _this->set_effect(arg0); + + return 0; +} + +static int Camera_release_wrapper(SQUserPointer ptr, int ) +{ + Camera* _this = reinterpret_cast (ptr); + delete _this; + return 0; +} + +static int Camera_construct_wrapper(HSQUIRRELVM v) +{ + Camera* _this = new Camera(); + sq_setinstanceup(v, 1, _this); + sq_setreleasehook(v, 1, Camera_release_wrapper); + + return 0; +} + +static int Camera_shake_wrapper(HSQUIRRELVM v) +{ + Camera* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + float arg0; + sq_getfloat(v, 2, &arg0); + float arg1; + sq_getfloat(v, 3, &arg1); + float arg2; + sq_getfloat(v, 4, &arg2); + + _this->shake(arg0, arg1, arg2); + + return 0; +} + +static int Camera_set_pos_wrapper(HSQUIRRELVM v) +{ + Camera* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + float arg0; + sq_getfloat(v, 2, &arg0); + float arg1; + sq_getfloat(v, 3, &arg1); + + _this->set_pos(arg0, arg1); + + return 0; +} + +static int Camera_set_mode_wrapper(HSQUIRRELVM v) +{ + Camera* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + const char* arg0; + sq_getstring(v, 2, &arg0); + + _this->set_mode(arg0); + + return 0; +} + +static int Level_release_wrapper(SQUserPointer ptr, int ) +{ + Level* _this = reinterpret_cast (ptr); + delete _this; + return 0; +} + +static int Level_construct_wrapper(HSQUIRRELVM v) +{ + Level* _this = new Level(); + sq_setinstanceup(v, 1, _this); + sq_setreleasehook(v, 1, Level_release_wrapper); + + return 0; +} + +static int Level_finish_wrapper(HSQUIRRELVM v) +{ + Level* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + + _this->finish(); + + return 0; +} + +static int Level_spawn_wrapper(HSQUIRRELVM v) +{ + Level* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + const char* arg0; + sq_getstring(v, 2, &arg0); + const char* arg1; + sq_getstring(v, 3, &arg1); + + _this->spawn(arg0, arg1); + + return 0; +} + +static int ScriptedObject_release_wrapper(SQUserPointer ptr, int ) +{ + ScriptedObject* _this = reinterpret_cast (ptr); + delete _this; + return 0; +} + +static int ScriptedObject_construct_wrapper(HSQUIRRELVM v) +{ + ScriptedObject* _this = new ScriptedObject(); + sq_setinstanceup(v, 1, _this); + sq_setreleasehook(v, 1, ScriptedObject_release_wrapper); + + return 0; +} + +static int ScriptedObject_set_animation_wrapper(HSQUIRRELVM v) +{ + ScriptedObject* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + const char* arg0; + sq_getstring(v, 2, &arg0); + + _this->set_animation(arg0); + + return 0; +} + +static int ScriptedObject_get_animation_wrapper(HSQUIRRELVM v) +{ + ScriptedObject* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + + std::string return_value = _this->get_animation(); + + sq_pushstring(v, return_value.c_str(), return_value.size()); + return 1; +} + +static int ScriptedObject_move_wrapper(HSQUIRRELVM v) +{ + ScriptedObject* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + float arg0; + sq_getfloat(v, 2, &arg0); + float arg1; + sq_getfloat(v, 3, &arg1); + + _this->move(arg0, arg1); + + return 0; +} + +static int ScriptedObject_set_pos_wrapper(HSQUIRRELVM v) +{ + ScriptedObject* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + float arg0; + sq_getfloat(v, 2, &arg0); + float arg1; + sq_getfloat(v, 3, &arg1); + + _this->set_pos(arg0, arg1); + + return 0; +} + +static int ScriptedObject_get_pos_x_wrapper(HSQUIRRELVM v) +{ + ScriptedObject* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + + float return_value = _this->get_pos_x(); + + sq_pushfloat(v, return_value); + return 1; +} + +static int ScriptedObject_get_pos_y_wrapper(HSQUIRRELVM v) +{ + ScriptedObject* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + + float return_value = _this->get_pos_y(); + + sq_pushfloat(v, return_value); + return 1; +} + +static int ScriptedObject_set_velocity_wrapper(HSQUIRRELVM v) +{ + ScriptedObject* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + float arg0; + sq_getfloat(v, 2, &arg0); + float arg1; + sq_getfloat(v, 3, &arg1); + + _this->set_velocity(arg0, arg1); + + return 0; +} + +static int ScriptedObject_get_velocity_x_wrapper(HSQUIRRELVM v) +{ + ScriptedObject* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + + float return_value = _this->get_velocity_x(); + + sq_pushfloat(v, return_value); + return 1; +} + +static int ScriptedObject_get_velocity_y_wrapper(HSQUIRRELVM v) +{ + ScriptedObject* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + + float return_value = _this->get_velocity_y(); + + sq_pushfloat(v, return_value); + return 1; +} + +static int Sound_release_wrapper(SQUserPointer ptr, int ) +{ + Sound* _this = reinterpret_cast (ptr); + delete _this; + return 0; +} + +static int Sound_construct_wrapper(HSQUIRRELVM v) +{ + Sound* _this = new Sound(); + sq_setinstanceup(v, 1, _this); + sq_setreleasehook(v, 1, Sound_release_wrapper); + + return 0; +} + +static int Sound_play_music_wrapper(HSQUIRRELVM v) +{ + Sound* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + const char* arg0; + sq_getstring(v, 2, &arg0); + + _this->play_music(arg0); + + return 0; +} + +static int Sound_play_sound_wrapper(HSQUIRRELVM v) +{ + Sound* _this; + sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + assert(_this != 0); + const char* arg0; + sq_getstring(v, 2, &arg0); + + _this->play_sound(arg0); + + return 0; +} + +static int wait_wrapper(HSQUIRRELVM v) +{ + float arg0; + sq_getfloat(v, 2, &arg0); + + Scripting::wait(arg0); + + return 0; +} + +WrappedFunction supertux_global_functions[] = { + { "wait", &wait_wrapper }, + { 0, 0 } +}; + +static WrappedFunction supertux_Display_methods[] = { + { "constructor", &Display_construct_wrapper }, + { "set_effect", &Display_set_effect_wrapper }, +}; + +static WrappedFunction supertux_Camera_methods[] = { + { "constructor", &Camera_construct_wrapper }, + { "shake", &Camera_shake_wrapper }, + { "set_pos", &Camera_set_pos_wrapper }, + { "set_mode", &Camera_set_mode_wrapper }, +}; + +static WrappedFunction supertux_Level_methods[] = { + { "constructor", &Level_construct_wrapper }, + { "finish", &Level_finish_wrapper }, + { "spawn", &Level_spawn_wrapper }, +}; + +static WrappedFunction supertux_ScriptedObject_methods[] = { + { "constructor", &ScriptedObject_construct_wrapper }, + { "set_animation", &ScriptedObject_set_animation_wrapper }, + { "get_animation", &ScriptedObject_get_animation_wrapper }, + { "move", &ScriptedObject_move_wrapper }, + { "set_pos", &ScriptedObject_set_pos_wrapper }, + { "get_pos_x", &ScriptedObject_get_pos_x_wrapper }, + { "get_pos_y", &ScriptedObject_get_pos_y_wrapper }, + { "set_velocity", &ScriptedObject_set_velocity_wrapper }, + { "get_velocity_x", &ScriptedObject_get_velocity_x_wrapper }, + { "get_velocity_y", &ScriptedObject_get_velocity_y_wrapper }, +}; + +static WrappedFunction supertux_Sound_methods[] = { + { "constructor", &Sound_construct_wrapper }, + { "play_music", &Sound_play_music_wrapper }, + { "play_sound", &Sound_play_sound_wrapper }, +}; + +WrappedClass supertux_classes[] = { + { "Display", supertux_Display_methods }, + { "Camera", supertux_Camera_methods }, + { "Level", supertux_Level_methods }, + { "ScriptedObject", supertux_ScriptedObject_methods }, + { "Sound", supertux_Sound_methods }, + { 0, 0 } +}; + diff --git a/src/scripting/wrapper.h b/src/scripting/wrapper.h new file mode 100644 index 000000000..f25aea134 --- /dev/null +++ b/src/scripting/wrapper.h @@ -0,0 +1,13 @@ +/** + * WARNING: This file is automatically generated from './build/i686-pc-linux-gnu/debug/miniswig.tmp' - do not change + */ +#ifndef __supertux_WRAPPER_H__ +#define __supertux_WRAPPER_H__ + +#include "wrapper_util.h" + +extern WrappedFunction supertux_global_functions[]; +extern WrappedClass supertux_classes[]; + +#endif + diff --git a/src/scripting/wrapper.interface.h b/src/scripting/wrapper.interface.h new file mode 100644 index 000000000..0b4513dd9 --- /dev/null +++ b/src/scripting/wrapper.interface.h @@ -0,0 +1,9 @@ +/** This file is processes by miniswig to produce the scripting API */ +#define SCRIPTING_API + +#include "display.h" +#include "camera.h" +#include "level.h" +#include "scripted_object.h" +#include "sound.h" +#include "functions.h" diff --git a/src/scripting/wrapper_util.cpp b/src/scripting/wrapper_util.cpp new file mode 100644 index 000000000..a16953ad7 --- /dev/null +++ b/src/scripting/wrapper_util.cpp @@ -0,0 +1,152 @@ +#include + +#include +#include +#include "wrapper_util.h" + +static void register_function(HSQUIRRELVM v, SQFUNCTION func, const char* name) +{ + sq_pushstring(v, name, -1); + sq_newclosure(v, func, 0); //create a new function + sq_createslot(v, -3); +} + +static void register_class(HSQUIRRELVM v, WrappedClass* wclass) +{ + sq_pushstring(v, wclass->name, -1); + sq_newclass(v, false); + for(WrappedFunction* func = wclass->functions; func->name != 0; ++func) { + register_function(v, func->f, func->name); + } + sq_createslot(v, -3); +} + +void register_functions(HSQUIRRELVM v, WrappedFunction* functions) +{ + sq_pushroottable(v); + for(WrappedFunction* func = functions; func->name != 0; ++func) { + register_function(v, func->f, func->name); + } + sq_pop(v, 1); +} + +void register_classes(HSQUIRRELVM v, WrappedClass* classes) +{ + sq_pushroottable(v); + for(WrappedClass* wclass = classes; wclass->name != 0; ++wclass) { + register_class(v, wclass); + } + sq_pop(v, 1); +} + +static void print_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_CLASS: + printf("class"); + break; + case OT_INSTANCE: + printf("instance"); + break; + default: + printf("unknown?!?"); + break; + } + printf("\n"); + } + printf("--------------------------------------------------------------\n"); +} + +#define check(x) \ + if((x) < 0) { \ + std::stringstream msg; \ + sq_getlasterror(v); \ + const char* error; \ + sq_getstring(v, -1, &error); \ + msg << "Error: " << error; \ + throw std::runtime_error(msg.str()); \ + } + +void expose_object(HSQUIRRELVM v, void* object, const char* type, + const char* name) +{ + // part1 of registration of the instance in the root table + sq_pushroottable(v); + sq_pushstring(v, name, -1); + + // resolve class name + sq_pushroottable(v); + sq_pushstring(v, type, -1); + print_stack(v); + if(sq_get(v, -2) < 0) { + std::ostringstream msg; + msg << "Couldn't resolve squirrel type '" << type << "'."; + throw std::runtime_error(msg.str()); + } + sq_remove(v, -2); // remove roottable + print_stack(v); + + // create an instance and set pointer to c++ object + print_stack(v); + check(sq_createinstance(v, -1)); + printf("after creatinstance\n"); + print_stack(v); + check(sq_setinstanceup(v, -1, object)); + printf("after setinstanceup\n"); + print_stack(v); + + sq_remove(v, -2); // remove class + + // part2 of registration of the instance in the root table + print_stack(v); + check(sq_createslot(v, -3)); + sq_pop(v, 1); +} + diff --git a/src/scripting/wrapper_util.h b/src/scripting/wrapper_util.h new file mode 100644 index 000000000..0eb0737e9 --- /dev/null +++ b/src/scripting/wrapper_util.h @@ -0,0 +1,21 @@ +#ifndef __WRAPPERUTIL_HPP__ +#define __WRAPPERUTIL_HPP__ + +#include + +struct WrappedFunction { + const char* name; + SQFUNCTION f; +}; +struct WrappedClass { + const char* name; + WrappedFunction* functions; +}; + +void register_functions(HSQUIRRELVM v, WrappedFunction* functions); +void register_classes(HSQUIRRELVM v, WrappedClass* classes); + +void expose_object(HSQUIRRELVM v, void* object, const char* type, + const char* name); + +#endif diff --git a/src/sector.cpp b/src/sector.cpp index 46298c67d..1470654e2 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -26,7 +26,6 @@ #include #include -#include "app/globals.h" #include "sector.h" #include "player_status.h" #include "object/gameobjs.h" diff --git a/src/sector.h b/src/sector.h index 64e2b3d02..2067e0916 100644 --- a/src/sector.h +++ b/src/sector.h @@ -27,16 +27,12 @@ #include "audio/musicref.h" #include "video/drawing_context.h" -using namespace SuperTux; - -namespace SuperTux { -class Rectangle; -} namespace lisp { class Lisp; class Writer; } +class Rectangle; class Sprite; class GameObject; class Player; diff --git a/src/sprite/sprite.cpp b/src/sprite/sprite.cpp index 38a448de0..28dc1fa55 100644 --- a/src/sprite/sprite.cpp +++ b/src/sprite/sprite.cpp @@ -23,8 +23,6 @@ #include #include -#include "app/globals.h" -#include "app/setup.h" #include "sprite.h" #include "video/drawing_context.h" diff --git a/src/sprite/sprite_data.cpp b/src/sprite/sprite_data.cpp index 16207ff30..a369d6664 100644 --- a/src/sprite/sprite_data.cpp +++ b/src/sprite/sprite_data.cpp @@ -24,8 +24,7 @@ #include #include "sprite_data.h" -#include "app/globals.h" -#include "app/setup.h" +#include "resources.h" #include "video/drawing_context.h" #include "lisp/list_iterator.h" diff --git a/src/squirrel/Jamfile b/src/squirrel/Jamfile new file mode 100644 index 000000000..556dd0118 --- /dev/null +++ b/src/squirrel/Jamfile @@ -0,0 +1,10 @@ +SubDir TOP src squirrel ; + +Library squirrel + : [ Wildcard squirrel : *.cpp *.h ] + [ Wildcard sqstdlib : *.cpp *.h ] + : noinstall +; +IncludeDir squirrel : include ; +C++Flags squirrel : -Wno-error -Wno-switch -Wno-missing-field-initializers +-Wno-unused -Wno-parentheses -Wno-non-virtual-dtor -Wno-sign-compare ; diff --git a/src/squirrel/README b/src/squirrel/README new file mode 100644 index 000000000..a0776e9f6 --- /dev/null +++ b/src/squirrel/README @@ -0,0 +1,3 @@ +This directory contains the SQUIRREL programming language version 2.0.1 from +http://squirrel.sourceforge.net +Originally on zlib/png license. diff --git a/src/squirrel/include/sqstdaux.h b/src/squirrel/include/sqstdaux.h new file mode 100644 index 000000000..b90034823 --- /dev/null +++ b/src/squirrel/include/sqstdaux.h @@ -0,0 +1,16 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_AUXLIB_H_ +#define _SQSTD_AUXLIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +SQUIRREL_API void sqstd_seterrorhandlers(HSQUIRRELVM v); +SQUIRREL_API void sqstd_printcallstack(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /* _SQSTD_AUXLIB_H_ */ diff --git a/src/squirrel/include/sqstdblob.h b/src/squirrel/include/sqstdblob.h new file mode 100644 index 000000000..023729432 --- /dev/null +++ b/src/squirrel/include/sqstdblob.h @@ -0,0 +1,20 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTDBLOB_H_ +#define _SQSTDBLOB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +SQUIRREL_API SQUserPointer sqstd_createblob(HSQUIRRELVM v, int size); +SQUIRREL_API SQRESULT sqstd_getblob(HSQUIRRELVM v,int idx,SQUserPointer *ptr); +SQUIRREL_API int sqstd_getblobsize(HSQUIRRELVM v,int idx); + +SQUIRREL_API SQRESULT sqstd_register_bloblib(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*_SQSTDBLOB_H_*/ + diff --git a/src/squirrel/include/sqstdio.h b/src/squirrel/include/sqstdio.h new file mode 100644 index 000000000..9ea0230ef --- /dev/null +++ b/src/squirrel/include/sqstdio.h @@ -0,0 +1,53 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTDIO_H_ +#define _SQSTDIO_H_ + +#ifdef __cplusplus + +#define SQSTD_STREAM_TYPE_TAG 0x80000000 + +struct SQStream { + virtual SQInteger Read(void *buffer, SQInteger size) = 0; + virtual SQInteger Write(void *buffer, SQInteger size) = 0; + virtual int Flush() = 0; + virtual long Tell() = 0; + virtual SQInteger Len() = 0; + virtual SQInteger Seek(long offset, int origin) = 0; + virtual bool IsValid() = 0; + virtual bool EOS() = 0; +}; + +extern "C" { +#endif + +#define SQ_SEEK_CUR 0 +#define SQ_SEEK_END 1 +#define SQ_SEEK_SET 2 + +typedef void* SQFILE; + +SQUIRREL_API SQFILE sqstd_fopen(const SQChar *,const SQChar *); +SQUIRREL_API SQInteger sqstd_fread(SQUserPointer, SQInteger, SQInteger, SQFILE); +SQUIRREL_API SQInteger sqstd_fwrite(const SQUserPointer, SQInteger, SQInteger, SQFILE); +SQUIRREL_API SQInteger sqstd_fseek(SQFILE , long , int); +SQUIRREL_API long sqstd_ftell(SQFILE); +SQUIRREL_API SQInteger sqstd_fflush(SQFILE); +SQUIRREL_API SQInteger sqstd_fclose(SQFILE); +SQUIRREL_API SQInteger sqstd_feof(SQFILE); + +SQUIRREL_API SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own); +SQUIRREL_API SQRESULT sqstd_getfile(HSQUIRRELVM v, int idx, SQFILE *file); + +//compiler helpers +SQUIRREL_API SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror); +SQUIRREL_API SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror); +SQUIRREL_API SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename); + +SQUIRREL_API SQRESULT sqstd_register_iolib(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*_SQSTDIO_H_*/ + diff --git a/src/squirrel/include/sqstdmath.h b/src/squirrel/include/sqstdmath.h new file mode 100644 index 000000000..420f2ce67 --- /dev/null +++ b/src/squirrel/include/sqstdmath.h @@ -0,0 +1,15 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_MATH_H_ +#define _SQSTD_MATH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +SQUIRREL_API SQRESULT sqstd_register_mathlib(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*_SQSTD_MATH_H_*/ diff --git a/src/squirrel/include/sqstdstring.h b/src/squirrel/include/sqstdstring.h new file mode 100644 index 000000000..83f55aa55 --- /dev/null +++ b/src/squirrel/include/sqstdstring.h @@ -0,0 +1,34 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_STRING_H_ +#define _SQSTD_STRING_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +//#define SQRex_True 1 +//#define SQRex_False 0 + +typedef unsigned int SQRexBool; +typedef struct SQRex SQRex; + +typedef struct { + const SQChar *begin; + int len; +} SQRexMatch; + +SQUIRREL_API SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error); +SQUIRREL_API void sqstd_rex_free(SQRex *exp); +SQUIRREL_API SQBool sqstd_rex_match(SQRex* exp,const SQChar* text); +SQUIRREL_API SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end); +SQUIRREL_API SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end); +SQUIRREL_API int sqstd_rex_getsubexpcount(SQRex* exp); +SQUIRREL_API SQBool sqstd_rex_getsubexp(SQRex* exp, int n, SQRexMatch *subexp); + +SQUIRREL_API SQRESULT sqstd_register_stringlib(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*_SQSTD_STRING_H_*/ diff --git a/src/squirrel/include/sqstdsystem.h b/src/squirrel/include/sqstdsystem.h new file mode 100644 index 000000000..73099aeaa --- /dev/null +++ b/src/squirrel/include/sqstdsystem.h @@ -0,0 +1,15 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_SYSTEMLIB_H_ +#define _SQSTD_SYSTEMLIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +SQUIRREL_API int sqstd_register_systemlib(HSQUIRRELVM v); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /* _SQSTD_SYSTEMLIB_H_ */ diff --git a/src/squirrel/include/squirrel.h b/src/squirrel/include/squirrel.h new file mode 100644 index 000000000..a59dbf91e --- /dev/null +++ b/src/squirrel/include/squirrel.h @@ -0,0 +1,368 @@ +/* +Copyright (c) 2003-2005 Alberto Demichelis + +This software is provided 'as-is', without any +express or implied warranty. In no event will the +authors be held liable for any damages arising from +the use of this software. + +Permission is granted to anyone to use this software +for any purpose, including commercial applications, +and to alter it and redistribute it freely, subject +to the following restrictions: + + 1. The origin of this software must not be + misrepresented; you must not claim that + you wrote the original software. If you + use this software in a product, an + acknowledgment in the product + documentation would be appreciated but is + not required. + + 2. Altered source versions must be plainly + marked as such, and must not be + misrepresented as being the original + software. + + 3. This notice may not be removed or + altered from any source distribution. + +*/ +#ifndef _SQUIRREL_H_ +#define _SQUIRREL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SQUIRREL_API +#define SQUIRREL_API extern +#endif + +typedef float SQFloat; +typedef int SQInteger; +typedef void* SQUserPointer; +typedef unsigned int SQBool; +typedef int SQRESULT; + +#define SQTrue 1 +#define SQFalse 0 + + +struct SQVM; +struct SQTable; +struct SQArray; +struct SQString; +struct SQClosure; +struct SQGenerator; +struct SQNativeClosure; +struct SQUserData; +struct SQFunctionProto; +struct SQRefCounted; +struct SQClass; +struct SQInstance; +struct SQDelegable; + +#ifdef _UNICODE +#define SQUNICODE +#endif + +#ifdef SQUNICODE +typedef unsigned short SQChar; +#define _SC(a) L##a +#define scstrcmp wcscmp +#define scsprintf swprintf +#define scstrlen wcslen +#define scstrtod wcstod +#define scatoi _wtoi +#define scstrtoul wcstoul +#define scvsprintf vswprintf +#define scstrstr wcsstr +#define scisspace iswspace +#define scisdigit iswdigit +#define scisalpha iswalpha +#define sciscntrl iswcntrl +#define scisalnum iswalnum +#define scprintf wprintf +#define MAX_CHAR 0xFFFF +#else +typedef char SQChar; +#define _SC(a) a +#define scstrcmp strcmp +#define scsprintf sprintf +#define scstrlen strlen +#define scstrtod strtod +#define scatoi atoi +#define scstrtoul strtoul +#define scvsprintf vsprintf +#define scstrstr strstr +#define scisspace isspace +#define scisdigit isdigit +#define sciscntrl iscntrl +#define scisalpha isalpha +#define scisalnum isalnum +#define scprintf printf +#define MAX_CHAR 0xFF +#endif + +#define SQUIRREL_VERSION _SC("Squirrel 2.0.1 stable") +#define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2005 Alberto Demichelis") +#define SQUIRREL_AUTHOR _SC("Alberto Demichelis") + +#define SQ_VMSTATE_IDLE 0 +#define SQ_VMSTATE_RUNNING 1 +#define SQ_VMSTATE_SUSPENDED 2 + +#define SQUIRREL_EOB 0 +#define SQ_BYTECODE_STREAM_TAG 0xFAFA + +#define SQOBJECT_REF_COUNTED 0x00800000 +#define SQOBJECT_NUMERIC 0x00080000 +#define SQOBJECT_DELEGABLE 0x08000000 +#define SQOBJECT_CANBEFALSE 0x80000000 +//typedef unsigned int SQObjectType; + +#define _RT_MASK 0x0000FFFF +#define _RAW_TYPE(type) (type&_RT_MASK) + +#define _RT_NULL 0x00000000 +#define _RT_INTEGER 0x00000001 +#define _RT_FLOAT 0x00000002 +#define _RT_BOOL 0x00000004 +#define _RT_STRING 0x00000008 +#define _RT_TABLE 0x00000010 +#define _RT_ARRAY 0x00000020 +#define _RT_USERDATA 0x00000040 +#define _RT_CLOSURE 0x00000080 +#define _RT_NATIVECLOSURE 0x00000100 +#define _RT_GENERATOR 0x00000200 +#define _RT_USERPOINTER 0x00000400 +#define _RT_THREAD 0x00000800 +#define _RT_FUNCPROTO 0x00001000 +#define _RT_CLASS 0x00002000 +#define _RT_INSTANCE 0x00004000 + +typedef enum { + OT_NULL = (_RT_NULL|SQOBJECT_CANBEFALSE), + OT_INTEGER = (_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), + OT_FLOAT = (_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), + OT_BOOL = (_RT_BOOL|SQOBJECT_CANBEFALSE), + OT_STRING = (_RT_STRING|SQOBJECT_REF_COUNTED), + OT_TABLE = (_RT_TABLE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), + OT_ARRAY = (_RT_ARRAY|SQOBJECT_REF_COUNTED), + OT_USERDATA = (_RT_USERDATA|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), + OT_CLOSURE = (_RT_CLOSURE|SQOBJECT_REF_COUNTED), + OT_NATIVECLOSURE = (_RT_NATIVECLOSURE|SQOBJECT_REF_COUNTED), + OT_GENERATOR = (_RT_GENERATOR|SQOBJECT_REF_COUNTED), + OT_USERPOINTER = _RT_USERPOINTER, + OT_THREAD = (_RT_THREAD|SQOBJECT_REF_COUNTED) , + OT_FUNCPROTO = (_RT_FUNCPROTO|SQOBJECT_REF_COUNTED), //internal usage only + OT_CLASS = (_RT_CLASS|SQOBJECT_REF_COUNTED), + OT_INSTANCE = (_RT_INSTANCE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE) +}SQObjectType; + +#define ISREFCOUNTED(t) (t&SQOBJECT_REF_COUNTED) + + +typedef union tagSQObjectValue +{ + struct SQTable *pTable; + struct SQArray *pArray; + struct SQClosure *pClosure; + struct SQGenerator *pGenerator; + struct SQNativeClosure *pNativeClosure; + struct SQString *pString; + struct SQUserData *pUserData; + SQInteger nInteger; + SQFloat fFloat; + SQUserPointer pUserPointer; + struct SQFunctionProto *pFunctionProto; + struct SQRefCounted *pRefCounted; + struct SQDelegable *pDelegable; + struct SQVM *pThread; + struct SQClass *pClass; + struct SQInstance *pInstance; +}SQObjectValue; + + +typedef struct tagSQObject +{ + SQObjectValue _unVal; + SQObjectType _type; +}SQObject; + +typedef struct tagSQStackInfos{ + const SQChar* funcname; + const SQChar* source; + int line; +}SQStackInfos; + +typedef struct SQVM* HSQUIRRELVM; +typedef SQObject HSQOBJECT; +typedef int (*SQFUNCTION)(HSQUIRRELVM); +typedef int (*SQRELEASEHOOK)(SQUserPointer,int size); +typedef void (*SQCOMPILERERROR)(HSQUIRRELVM,const SQChar * /*desc*/,const SQChar * /*source*/,int /*line*/,int /*column*/); +typedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,const SQChar * ,...); + +typedef int (*SQWRITEFUNC)(SQUserPointer,SQUserPointer,int); +typedef int (*SQREADFUNC)(SQUserPointer,SQUserPointer,int); + +typedef SQInteger (*SQLEXREADFUNC)(SQUserPointer); + +typedef struct tagSQRegFunction{ + const SQChar *name; + SQFUNCTION f; + int nparamscheck; + const SQChar *typemask; +}SQRegFunction; + +/*vm*/ +SQUIRREL_API HSQUIRRELVM sq_open(int initialstacksize); +SQUIRREL_API HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, int initialstacksize); +SQUIRREL_API void sq_seterrorhandler(HSQUIRRELVM v); +SQUIRREL_API void sq_close(HSQUIRRELVM v); +SQUIRREL_API void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p); +SQUIRREL_API SQUserPointer sq_getforeignptr(HSQUIRRELVM v); +SQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc); +SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval); +SQUIRREL_API int sq_getvmstate(HSQUIRRELVM v); + +/*compiler*/ +SQUIRREL_API SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror); +SQUIRREL_API SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,int size,const SQChar *sourcename,SQBool raiseerror); +SQUIRREL_API void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo); +SQUIRREL_API void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f); + +/*stack operations*/ +SQUIRREL_API void sq_push(HSQUIRRELVM v,int idx); +SQUIRREL_API void sq_pop(HSQUIRRELVM v,int nelemstopop); +SQUIRREL_API void sq_remove(HSQUIRRELVM v,int idx); +SQUIRREL_API int sq_gettop(HSQUIRRELVM v); +SQUIRREL_API void sq_settop(HSQUIRRELVM v,int newtop); +SQUIRREL_API void sq_reservestack(HSQUIRRELVM v,int nsize); +SQUIRREL_API int sq_cmp(HSQUIRRELVM v); +SQUIRREL_API void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,int idx); + +/*object creation handling*/ +SQUIRREL_API SQUserPointer sq_newuserdata(HSQUIRRELVM v,unsigned int size); +SQUIRREL_API void sq_newtable(HSQUIRRELVM v); +SQUIRREL_API void sq_newarray(HSQUIRRELVM v,int size); +SQUIRREL_API void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,unsigned int nfreevars); +SQUIRREL_API SQRESULT sq_setparamscheck(HSQUIRRELVM v,int nparamscheck,const SQChar *typemask); +SQUIRREL_API void sq_pushstring(HSQUIRRELVM v,const SQChar *s,int len); +SQUIRREL_API void sq_pushfloat(HSQUIRRELVM v,SQFloat f); +SQUIRREL_API void sq_pushinteger(HSQUIRRELVM v,SQInteger n); +SQUIRREL_API void sq_pushbool(HSQUIRRELVM v,SQBool b); +SQUIRREL_API void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p); +SQUIRREL_API void sq_pushnull(HSQUIRRELVM v); +SQUIRREL_API SQObjectType sq_gettype(HSQUIRRELVM v,int idx); +SQUIRREL_API SQInteger sq_getsize(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_getstring(HSQUIRRELVM v,int idx,const SQChar **c); +SQUIRREL_API SQRESULT sq_getinteger(HSQUIRRELVM v,int idx,SQInteger *i); +SQUIRREL_API SQRESULT sq_getfloat(HSQUIRRELVM v,int idx,SQFloat *f); +SQUIRREL_API SQRESULT sq_getbool(HSQUIRRELVM v,int idx,SQBool *b); +SQUIRREL_API SQRESULT sq_getthread(HSQUIRRELVM v,int idx,HSQUIRRELVM *thread); +SQUIRREL_API SQRESULT sq_getuserpointer(HSQUIRRELVM v,int idx,SQUserPointer *p); +SQUIRREL_API SQRESULT sq_getuserdata(HSQUIRRELVM v,int idx,SQUserPointer *p,unsigned int *typetag); +SQUIRREL_API SQRESULT sq_settypetag(HSQUIRRELVM v,int idx,unsigned int typetag); +SQUIRREL_API SQRESULT sq_gettypetag(HSQUIRRELVM v,int idx,unsigned int *typetag); +SQUIRREL_API void sq_setreleasehook(HSQUIRRELVM v,int idx,SQRELEASEHOOK hook); +SQUIRREL_API SQChar *sq_getscratchpad(HSQUIRRELVM v,int minsize); +SQUIRREL_API SQRESULT sq_getclosureinfo(HSQUIRRELVM v,int idx,unsigned int *nparams,unsigned int *nfreevars); +SQUIRREL_API SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,int idx,const SQChar *name); +SQUIRREL_API SQRESULT sq_setinstanceup(HSQUIRRELVM v, int idx, SQUserPointer p); +SQUIRREL_API SQRESULT sq_getinstanceup(HSQUIRRELVM v, int idx, SQUserPointer *p,unsigned int typetag); +SQUIRREL_API SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase); +SQUIRREL_API SQRESULT sq_createinstance(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_setattributes(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_getattributes(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_getclass(HSQUIRRELVM v,int idx); + +/*object manipulation*/ +SQUIRREL_API void sq_pushroottable(HSQUIRRELVM v); +SQUIRREL_API void sq_pushregistrytable(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_setroottable(HSQUIRRELVM v); +SQUIRREL_API SQRESULT sq_createslot(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_deleteslot(HSQUIRRELVM v,int idx,SQBool pushval); +SQUIRREL_API SQRESULT sq_set(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_get(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_rawget(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_rawset(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,int idx,SQBool pushval); +SQUIRREL_API SQRESULT sq_arrayappend(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_arraypop(HSQUIRRELVM v,int idx,SQBool pushval); +SQUIRREL_API SQRESULT sq_arrayresize(HSQUIRRELVM v,int idx,int newsize); +SQUIRREL_API SQRESULT sq_arrayreverse(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_setdelegate(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_getdelegate(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_clone(HSQUIRRELVM v,int idx); +SQUIRREL_API SQRESULT sq_setfreevariable(HSQUIRRELVM v,int idx,unsigned int nval); +SQUIRREL_API SQRESULT sq_next(HSQUIRRELVM v,int idx); + +/*calls*/ +SQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,int params,SQBool retval); +SQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval); +SQUIRREL_API const SQChar *sq_getlocal(HSQUIRRELVM v,unsigned int level,unsigned int idx); +SQUIRREL_API SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err); +SQUIRREL_API void sq_reseterror(HSQUIRRELVM v); +SQUIRREL_API void sq_getlasterror(HSQUIRRELVM v); + +/*raw object handling*/ +SQUIRREL_API SQRESULT sq_getstackobj(HSQUIRRELVM v,int idx,HSQOBJECT *po); +SQUIRREL_API void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj); +SQUIRREL_API void sq_addref(HSQUIRRELVM v,HSQOBJECT *po); +SQUIRREL_API SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po); +SQUIRREL_API void sq_resetobject(HSQOBJECT *po); +SQUIRREL_API const SQChar *sq_objtostring(HSQOBJECT *o); +SQUIRREL_API SQInteger sq_objtointeger(HSQOBJECT *o); +SQUIRREL_API SQFloat sq_objtofloat(HSQOBJECT *o); + +/*GC*/ +SQUIRREL_API int sq_collectgarbage(HSQUIRRELVM v); + +/*serialization*/ +SQUIRREL_API SQRESULT sq_writeclosure(HSQUIRRELVM vm,SQWRITEFUNC writef,SQUserPointer up); +SQUIRREL_API SQRESULT sq_readclosure(HSQUIRRELVM vm,SQREADFUNC readf,SQUserPointer up); + +/*mem allocation*/ +SQUIRREL_API void *sq_malloc(unsigned int size); +SQUIRREL_API void *sq_realloc(void* p,unsigned int oldsize,unsigned int newsize); +SQUIRREL_API void sq_free(void *p,unsigned int size); + +/*debug*/ +SQUIRREL_API SQRESULT sq_stackinfos(HSQUIRRELVM v,int level,SQStackInfos *si); +SQUIRREL_API void sq_setdebughook(HSQUIRRELVM v); + +/*UTILITY MACRO*/ +#define sq_isnumeric(o) ((o)._type&SQOBJECT_NUMERIC) +#define sq_istable(o) ((o)._type==OT_TABLE) +#define sq_isarray(o) ((o)._type==OT_ARRAY) +#define sq_isfunction(o) ((o)._type==OT_FUNCPROTO) +#define sq_isclosure(o) ((o)._type==OT_CLOSURE) +#define sq_isgenerator(o) ((o)._type==OT_GENERATOR) +#define sq_isnativeclosure(o) ((o)._type==OT_NATIVECLOSURE) +#define sq_isstring(o) ((o)._type==OT_STRING) +#define sq_isinteger(o) ((o)._type==OT_INTEGER) +#define sq_isfloat(o) ((o)._type==OT_FLOAT) +#define sq_isuserpointer(o) ((o)._type==OT_USERPOINTER) +#define sq_isuserdata(o) ((o)._type==OT_USERDATA) +#define sq_isthread(o) ((o)._type==OT_THREAD) +#define sq_isnull(o) ((o)._type==OT_NULL) +#define sq_isclass(o) ((o)._type==OT_CLASS) +#define sq_isinstance(o) ((o)._type==OT_INSTANCE) +#define sq_isbool(o) ((o)._type==OT_BOOL) +#define sq_type(o) ((o)._type) + +#define SQ_OK (0) +#define SQ_ERROR (-1) + +#define SQ_FAILED(res) (res<0) +#define SQ_SUCCEEDED(res) (res>=0) + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*_SQUIRREL_H_*/ diff --git a/src/squirrel/sqstdlib/Makefile b/src/squirrel/sqstdlib/Makefile new file mode 100644 index 000000000..625f1b44e --- /dev/null +++ b/src/squirrel/sqstdlib/Makefile @@ -0,0 +1,21 @@ +SQUIRREL= .. + + +OUT= $(SQUIRREL)/lib/libsqstdlib.a +INCZ= -I$(SQUIRREL)/include -I. -Iinclude + +SRCS= \ + sqstdblob.cpp \ + sqstdio.cpp \ + sqstdstream.cpp \ + sqstdmath.cpp \ + sqstdsystem.cpp \ + sqstdstring.cpp \ + sqstdaux.cpp \ + sqstdrex.c + + +squirrel: + gcc -O3 -Os -c $(SRCS) $(INCZ) + ar rc $(OUT) *.o + rm *.o \ No newline at end of file diff --git a/src/squirrel/sqstdlib/sqstdaux.cpp b/src/squirrel/sqstdlib/sqstdaux.cpp new file mode 100644 index 000000000..9609b50f4 --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdaux.cpp @@ -0,0 +1,116 @@ +/* see copyright notice in squirrel.h */ +#include +#include + +void sqstd_printcallstack(HSQUIRRELVM v) +{ + SQPRINTFUNCTION pf = sq_getprintfunc(v); + if(pf) { + SQStackInfos si; + SQInteger i; + SQFloat f; + const SQChar *s; + int level=1; //1 is to skip this function that is level 0 + const SQChar *name=0; + int seq=0; + pf(v,_SC("\nCALLSTACK\n")); + while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si))) + { + const SQChar *fn=_SC("unknown"); + const SQChar *src=_SC("unknown"); + if(si.funcname)fn=si.funcname; + if(si.source)src=si.source; + pf(v,_SC("*FUNCTION [%s()] %s line [%d]\n"),fn,src,si.line); + level++; + } + level=0; + pf(v,_SC("\nLOCALS\n")); + + for(level=0;level<10;level++){ + seq=0; + while(name=sq_getlocal(v,level,seq)) + { + seq++; + switch(sq_gettype(v,-1)) + { + case OT_NULL: + pf(v,_SC("[%s] NULL\n"),name); + break; + case OT_INTEGER: + sq_getinteger(v,-1,&i); + pf(v,_SC("[%s] %d\n"),name,i); + break; + case OT_FLOAT: + sq_getfloat(v,-1,&f); + pf(v,_SC("[%s] %.14g\n"),name,f); + break; + case OT_USERPOINTER: + pf(v,_SC("[%s] USERPOINTER\n"),name); + break; + case OT_STRING: + sq_getstring(v,-1,&s); + pf(v,_SC("[%s] \"%s\"\n"),name,s); + break; + case OT_TABLE: + pf(v,_SC("[%s] TABLE\n"),name); + break; + case OT_ARRAY: + pf(v,_SC("[%s] ARRAY\n"),name); + break; + case OT_CLOSURE: + pf(v,_SC("[%s] CLOSURE\n"),name); + break; + case OT_NATIVECLOSURE: + pf(v,_SC("[%s] NATIVECLOSURE\n"),name); + break; + case OT_USERDATA: + pf(v,_SC("[%s] USERDATA\n"),name); + break; + case OT_THREAD: + pf(v,_SC("[%s] THREAD\n"),name); + break; + case OT_CLASS: + pf(v,_SC("[%s] CLASS\n"),name); + break; + case OT_INSTANCE: + pf(v,_SC("[%s] INSTANCE\n"),name); + break; + } + sq_pop(v,1); + } + } + } +} + +static int _sqstd_aux_printerror(HSQUIRRELVM v) +{ + SQPRINTFUNCTION pf = sq_getprintfunc(v); + if(pf) { + const SQChar *sErr = 0; + if(sq_gettop(v)>=1) { + if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr))) { + pf(v,_SC("\nAN ERROR HAS OCCURED [%s]\n"),sErr); + } + else{ + pf(v,_SC("\nAN ERROR HAS OCCURED [unknown]\n")); + } + sqstd_printcallstack(v); + } + } + return 0; +} + +void _sqstd_compiler_error(HSQUIRRELVM v,const SQChar *sErr,const SQChar *sSource,int line,int column) +{ + SQPRINTFUNCTION pf = sq_getprintfunc(v); + if(pf) { + pf(v,_SC("ERROR %s line=(%d) column=(%d) [%s]\n"),sErr,line,column,sSource); + } +} + +void sqstd_seterrorhandlers(HSQUIRRELVM v) +{ + sq_setcompilererrorhandler(v,_sqstd_compiler_error); + sq_newclosure(v,_sqstd_aux_printerror,0); + sq_seterrorhandler(v); +} diff --git a/src/squirrel/sqstdlib/sqstdblob.cpp b/src/squirrel/sqstdlib/sqstdblob.cpp new file mode 100644 index 000000000..6813f5f62 --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdblob.cpp @@ -0,0 +1,255 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include +#include "sqstdstream.h" +#include "sqstdblobimpl.h" + +#define SQSTD_BLOB_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000002) + +//Blob + + +#define SETUP_BLOB(v) \ + SQBlob *self = NULL; \ + { if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,SQSTD_BLOB_TYPE_TAG))) \ + return SQ_ERROR; } + + +static int _blob_resize(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + SQInteger size; + sq_getinteger(v,2,&size); + if(!self->Resize(size)) + return sq_throwerror(v,_SC("resize failed")); + return 0; +} + +static void __swap_dword(unsigned int *n) +{ + *n=(unsigned int)(((*n&0xFF000000)>>24) | + ((*n&0x00FF0000)>>8) | + ((*n&0x0000FF00)<<8) | + ((*n&0x000000FF)<<24)); +} + +static void __swap_word(unsigned short *n) +{ + *n=(unsigned short)((*n>>8)&0x00FF)| ((*n<<8)&0xFF00); +} + +static int _blob_swap4(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + int num=(self->Len()-(self->Len()%4))>>2; + unsigned int *t=(unsigned int *)self->GetBuf(); + for(int i = 0; i < num; i++) { + __swap_dword(&t[i]); + } + return 0; +} + +static int _blob_swap2(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + int num=(self->Len()-(self->Len()%2))>>1; + unsigned short *t = (unsigned short *)self->GetBuf(); + for(int i = 0; i < num; i++) { + __swap_word(&t[i]); + } + return 0; +} + +static int _blob__set(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + SQInteger idx,val; + sq_getinteger(v,2,&idx); + sq_getinteger(v,3,&val); + if(idx < 0 || idx >= self->Len()) + return sq_throwerror(v,_SC("index out of range")); + ((unsigned char *)self->GetBuf())[idx] = (unsigned char) val; + sq_push(v,3); + return 1; +} + +static int _blob__get(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + SQInteger idx; + sq_getinteger(v,2,&idx); + if(idx < 0 || idx >= self->Len()) + return sq_throwerror(v,_SC("index out of range")); + sq_pushinteger(v,((unsigned char *)self->GetBuf())[idx]); + return 1; +} + +static int _blob__nexti(HSQUIRRELVM v) +{ + SETUP_BLOB(v); + if(sq_gettype(v,2) == OT_NULL) { + sq_pushinteger(v, 0); + return 1; + } + SQInteger idx; + if(SQ_SUCCEEDED(sq_getinteger(v, 2, &idx))) { + if(idx+1 < self->Len()) { + sq_pushinteger(v, idx+1); + return 1; + } + sq_pushnull(v); + return 1; + } + return sq_throwerror(v,_SC("internal error (_nexti) wrong argument type")); +} + +static int _blob__typeof(HSQUIRRELVM v) +{ + sq_pushstring(v,_SC("blob"),-1); + return 1; +} + +static int _blob_releasehook(SQUserPointer p, int size) +{ + SQBlob *self = (SQBlob*)p; + delete self; + return 1; +} + +static int _blob_constructor(HSQUIRRELVM v) +{ + SQInteger nparam = sq_gettop(v); + SQInteger size = 0; + if(nparam == 2) { + sq_getinteger(v, 2, &size); + } + if(size < 0) return sq_throwerror(v, _SC("cannot create blob with negative size")); + SQBlob *b = new SQBlob(size); + if(SQ_FAILED(sq_setinstanceup(v,1,b))) { + delete b; + return sq_throwerror(v, _SC("cannot create blob with negative size")); + } + sq_setreleasehook(v,1,_blob_releasehook); + return 0; +} + +#define _DECL_BLOB_FUNC(name,nparams,typecheck) {_SC(#name),_blob_##name,nparams,typecheck} +static SQRegFunction _blob_methods[] = { + _DECL_BLOB_FUNC(constructor,-1,_SC("xn")), + _DECL_BLOB_FUNC(resize,2,_SC("xn")), + _DECL_BLOB_FUNC(swap2,1,_SC("x")), + _DECL_BLOB_FUNC(swap4,1,_SC("x")), + _DECL_BLOB_FUNC(_set,3,_SC("xnn")), + _DECL_BLOB_FUNC(_get,2,_SC("xn")), + _DECL_BLOB_FUNC(_typeof,1,_SC("x")), + _DECL_BLOB_FUNC(_nexti,2,_SC("x")), + {0,0,0,0} +}; + + + +//GLOBAL FUNCTIONS + +static int _g_blob_casti2f(HSQUIRRELVM v) +{ + SQInteger i; + sq_getinteger(v,2,&i); + sq_pushfloat(v,*((SQFloat *)&i)); + return 1; +} + +static int _g_blob_castf2i(HSQUIRRELVM v) +{ + SQFloat f; + sq_getfloat(v,2,&f); + sq_pushinteger(v,*((SQInteger *)&f)); + return 1; +} + +static int _g_blob_swap2(HSQUIRRELVM v) +{ + SQInteger i; + sq_getinteger(v,2,&i); + short s=(short)i; + sq_pushinteger(v,(s<<8)|((s>>8)&0x00FF)); + return 1; +} + +static int _g_blob_swap4(HSQUIRRELVM v) +{ + SQInteger i; + sq_getinteger(v,2,&i); + __swap_dword((unsigned int *)&i); + sq_pushinteger(v,i); + return 1; +} + +static int _g_blob_swapfloat(HSQUIRRELVM v) +{ + SQFloat f; + sq_getfloat(v,2,&f); + __swap_dword((unsigned int *)&f); + sq_pushfloat(v,f); + return 1; +} + +#define _DECL_GLOBALBLOB_FUNC(name,nparams,typecheck) {_SC(#name),_g_blob_##name,nparams,typecheck} +static SQRegFunction bloblib_funcs[]={ + _DECL_GLOBALBLOB_FUNC(casti2f,2,_SC(".n")), + _DECL_GLOBALBLOB_FUNC(castf2i,2,_SC(".n")), + _DECL_GLOBALBLOB_FUNC(swap2,2,_SC(".n")), + _DECL_GLOBALBLOB_FUNC(swap4,2,_SC(".n")), + _DECL_GLOBALBLOB_FUNC(swapfloat,2,_SC(".n")), + {0,0} +}; + +SQRESULT sqstd_getblob(HSQUIRRELVM v,int idx,SQUserPointer *ptr) +{ + SQBlob *blob; + if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,SQSTD_BLOB_TYPE_TAG))) + return -1; + *ptr = blob->GetBuf(); + return SQ_OK; +} + +int sqstd_getblobsize(HSQUIRRELVM v,int idx) +{ + SQBlob *blob; + if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,SQSTD_BLOB_TYPE_TAG))) + return -1; + return blob->Len(); +} + +SQUserPointer sqstd_createblob(HSQUIRRELVM v, int size) +{ + int top = sq_gettop(v); +// SQUserPointer p = sq_newuserdata(v, sizeof(SQBlob)); +// sq_setreleasehook(v,-1,_blob_releasehook); +// sq_settypetag(v,-1,SQSTD_BLOB_TYPE_TAG); +// new (p) SQBlob(size); + sq_pushregistrytable(v); + sq_pushstring(v,_SC("std_blob"),-1); + if(SQ_SUCCEEDED(sq_get(v,-2))) { + sq_remove(v,-2); //removes the registry + sq_push(v,1); // push the this + sq_pushinteger(v,size); //size + SQBlob *blob = NULL; + if(SQ_SUCCEEDED(sq_call(v,2,SQTrue)) + && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,SQSTD_BLOB_TYPE_TAG))) { + sq_remove(v,-2); + sq_remove(v,-2); + return blob->GetBuf(); + } + } + sq_settop(v,top); + return NULL; +} + +SQRESULT sqstd_register_bloblib(HSQUIRRELVM v) +{ + return declare_stream(v,_SC("blob"),SQSTD_BLOB_TYPE_TAG,_SC("std_blob"),_blob_methods,bloblib_funcs); +} + diff --git a/src/squirrel/sqstdlib/sqstdblobimpl.h b/src/squirrel/sqstdlib/sqstdblobimpl.h new file mode 100644 index 000000000..6bcd48e7b --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdblobimpl.h @@ -0,0 +1,108 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_BLOBIMPL_H_ +#define _SQSTD_BLOBIMPL_H_ + +struct SQBlob : public SQStream +{ + SQBlob(int size) { + _size = size; + _allocated = size; + _buf = (unsigned char *)sq_malloc(size); + memset(_buf, 0, _size); + _ptr = 0; + _owns = true; + } + ~SQBlob() { + sq_free(_buf, _size); + } + SQInteger Write(void *buffer, SQInteger size) { + if(!CanAdvance(size)) { + GrowBufOf(_ptr + size - _size); + } + memcpy(&_buf[_ptr], buffer, size); + _ptr += size; + return size; + } + SQInteger Read(void *buffer,SQInteger size) { + int n = size; + if(!CanAdvance(size)) { + if((_size - _ptr) > 0) + n = _size - _ptr; + else return 0; + } + memcpy(buffer, &_buf[_ptr], n); + _ptr += n; + return n; + } + bool Resize(int n) { + if(!_owns) return false; + if(n != _allocated) { + unsigned char *newbuf = (unsigned char *)sq_malloc(n); + memset(newbuf,0,n); + if(_size > n) + memcpy(newbuf,_buf,n); + else + memcpy(newbuf,_buf,_size); + sq_free(_buf,_allocated); + _buf=newbuf; + _allocated = n; + if(_size > _allocated) + _size = _allocated; + if(_ptr > _allocated) + _ptr = _allocated; + } + return true; + } + bool GrowBufOf(int n) + { + bool ret = true; + if(_size + n > _allocated) { + if(_size + n > _size * 2) + ret = Resize(_size + n); + else + ret = Resize(_size * 2); + } + _size = _size + n; + return ret; + } + bool CanAdvance(int n) { + if(_ptr+n>_size)return false; + return true; + } + SQInteger Seek(long offset, int origin) { + switch(origin) { + case SQ_SEEK_SET: + if(offset >= _size || offset < 0) return -1; + _ptr = offset; + break; + case SQ_SEEK_CUR: + if(_ptr + offset >= _size || _ptr + offset < 0) return -1; + _ptr += offset; + break; + case SQ_SEEK_END: + if(_size + offset >= _size || _size + offset < 0) return -1; + _ptr = _size + offset; + break; + default: return -1; + } + return 0; + } + bool IsValid() { + return _buf?true:false; + } + bool EOS() { + return _ptr == _size; + } + int Flush() { return 0; } + long Tell() { return _ptr; } + SQInteger Len() { return _size; } + SQUserPointer GetBuf(){ return _buf; } +private: + int _size; + int _allocated; + int _ptr; + unsigned char *_buf; + bool _owns; +}; + +#endif //_SQSTD_BLOBIMPL_H_ diff --git a/src/squirrel/sqstdlib/sqstdio.cpp b/src/squirrel/sqstdlib/sqstdio.cpp new file mode 100644 index 000000000..5d02f55ac --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdio.cpp @@ -0,0 +1,336 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include "sqstdstream.h" + +#define SQSTD_FILE_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000001) +//basic API +SQFILE sqstd_fopen(const SQChar *filename ,const SQChar *mode) +{ +#ifndef _UNICODE + return (SQFILE)fopen(filename,mode); +#else + return (SQFILE)_wfopen(filename,mode); +#endif +} + +SQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file) +{ + return (SQInteger)fread(buffer,size,count,(FILE *)file); +} + +SQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file) +{ + return (SQInteger)fwrite(buffer,size,count,(FILE *)file); +} + +SQInteger sqstd_fseek(SQFILE file, long offset, int origin) +{ + int realorigin; + switch(origin) { + case SQ_SEEK_CUR: realorigin = SEEK_CUR; break; + case SQ_SEEK_END: realorigin = SEEK_END; break; + case SQ_SEEK_SET: realorigin = SEEK_SET; break; + default: return -1; //failed + } + return fseek((FILE *)file,offset,realorigin); +} + +long sqstd_ftell(SQFILE file) +{ + return ftell((FILE *)file); +} + +SQInteger sqstd_fflush(SQFILE file) +{ + return fflush((FILE *)file); +} + +SQInteger sqstd_fclose(SQFILE file) +{ + return fclose((FILE *)file); +} + +SQInteger sqstd_feof(SQFILE file) +{ + return feof((FILE *)file); +} + +//File +struct SQFile : public SQStream { + SQFile() { _handle = NULL; _owns = false;} + SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;} + ~SQFile() { Close(); } + bool Open(const SQChar *filename ,const SQChar *mode) { + Close(); + if(_handle = sqstd_fopen(filename,mode)) { + _owns = true; + return true; + } + return false; + } + void Close() { + if(_handle && _owns) { + sqstd_fclose(_handle); + _handle = NULL; + _owns = false; + } + } + SQInteger Read(void *buffer,SQInteger size) { + return sqstd_fread(buffer,1,size,_handle); + } + SQInteger Write(void *buffer,SQInteger size) { + return sqstd_fwrite(buffer,1,size,_handle); + } + int Flush() { + return sqstd_fflush(_handle); + } + long Tell() { + return sqstd_ftell(_handle); + } + SQInteger Len() { + int prevpos=Tell(); + Seek(0,SQ_SEEK_END); + int size=Tell(); + Seek(prevpos,SQ_SEEK_SET); + return size; + } + SQInteger Seek(long offset, int origin) { + return sqstd_fseek(_handle,offset,origin); + } + bool IsValid() { return _handle?true:false; } + bool EOS() { return Tell()==Len()?true:false;} + SQFILE GetHandle() {return _handle;} +private: + SQFILE _handle; + bool _owns; +}; + +static int _file__typeof(HSQUIRRELVM v) +{ + sq_pushstring(v,_SC("file"),-1); + return 1; +} + +static int _file_releasehook(SQUserPointer p, int size) +{ + SQFile *self = (SQFile*)p; + delete self; + return 1; +} + +static int _file_constructor(HSQUIRRELVM v) +{ + const SQChar *filename,*mode; + bool owns = true; + SQFile *f; + SQFILE newf; + if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) { + sq_getstring(v, 2, &filename); + sq_getstring(v, 3, &mode); + newf = sqstd_fopen(filename, mode); + if(!newf) return sq_throwerror(v, _SC("cannot open file")); + } else if(sq_gettype(v,2) == OT_USERPOINTER) { + owns = !(sq_gettype(v,3) == OT_NULL); + sq_getuserpointer(v,2,&newf); + } else { + return sq_throwerror(v,_SC("wrong parameter")); + } + f = new SQFile(newf,owns); + if(SQ_FAILED(sq_setinstanceup(v,1,f))) { + delete f; + return sq_throwerror(v, _SC("cannot create blob with negative size")); + } + sq_setreleasehook(v,1,_file_releasehook); + return 0; +} + +//bindings +#define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck} +static SQRegFunction _file_methods[] = { + _DECL_FILE_FUNC(constructor,3,_SC("x")), + _DECL_FILE_FUNC(_typeof,1,_SC("x")), + {0,0,0,0}, +}; + + + +SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own) +{ + int top = sq_gettop(v); + sq_pushregistrytable(v); + sq_pushstring(v,_SC("std_file"),-1); + if(SQ_SUCCEEDED(sq_get(v,-2))) { + sq_remove(v,-2); //removes the registry + sq_pushroottable(v); // push the this + sq_pushuserpointer(v,file); //file + if(own){ + sq_pushinteger(v,1); //true + } + else{ + sq_pushnull(v); //false + } + if(SQ_SUCCEEDED( sq_call(v,3,SQTrue) )) { + sq_remove(v,-2); + return SQ_OK; + } + } + sq_settop(v,top); + return SQ_OK; +} + +SQRESULT sqstd_getfile(HSQUIRRELVM v, int idx, SQFILE *file) +{ + SQFile *fileobj = NULL; + if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,SQSTD_FILE_TYPE_TAG))) { + *file = fileobj->GetHandle(); + return SQ_OK; + } + return sq_throwerror(v,_SC("not a file")); +} + + +static SQInteger _io_file_lexfeedASCII(SQUserPointer file) +{ + int ret; + char c; + if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) + return c; + return 0; +} + +static SQInteger _io_file_lexfeedWCHAR(SQUserPointer file) +{ + int ret; + wchar_t c; + if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) + return (SQChar)c; + return 0; +} + +int file_read(SQUserPointer file,SQUserPointer buf,int size) +{ + int ret; + if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret; + return -1; +} + +int file_write(SQUserPointer file,SQUserPointer p,int size) +{ + return sqstd_fwrite(p,1,size,(SQFILE)file); +} + +SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror) +{ + SQFILE file = sqstd_fopen(filename,_SC("rb")); + int ret; + unsigned short uc; + SQLEXREADFUNC func = _io_file_lexfeedASCII; + if(file && (ret=sqstd_fread(&uc,1,2,file))){ + if(ret!=2) { + sqstd_fclose(file); + return sq_throwerror(v,_SC("io error")); + } + if(uc==SQ_BYTECODE_STREAM_TAG) { //BYTECODE + sqstd_fseek(file,0,SQ_SEEK_SET); + if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) { + sqstd_fclose(file); + return SQ_OK; + } + } + else { //SCRIPT + if(uc==0xFEFF) + func = _io_file_lexfeedWCHAR; + else + sqstd_fseek(file,0,SQ_SEEK_SET); + + if(SQ_SUCCEEDED(sq_compile(v,func,file,filename,printerror))){ + sqstd_fclose(file); + return SQ_OK; + } + } + sqstd_fclose(file); + return SQ_ERROR; + } + return sq_throwerror(v,_SC("cannot open the file")); +} + +SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror) +{ + if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) { + sq_push(v,-2); + int ntop = sq_gettop(v); + if(SQ_SUCCEEDED(sq_call(v,1,retval))) { + sq_remove(v,retval?-2:-1); //removes the closure + return 1; + } + sq_pop(v,1); //removes the closure + } + return SQ_ERROR; +} + +SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename) +{ + SQFILE file = sqstd_fopen(filename,_SC("wb+")); + if(!file) return sq_throwerror(v,_SC("cannot open the file")); + if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) { + sqstd_fclose(file); + return SQ_OK; + } + sqstd_fclose(file); + return SQ_ERROR; //forward the error +} + +int _g_io_loadfile(HSQUIRRELVM v) +{ + const SQChar *filename; + SQBool printerror = SQFalse; + sq_getstring(v,2,&filename); + if(sq_gettop(v) >= 3) { + sq_getbool(v,3,&printerror); + } + if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) + return 1; + return SQ_ERROR; //propagates the error +} + +int _g_io_dofile(HSQUIRRELVM v) +{ + const SQChar *filename; + SQBool printerror = SQFalse; + sq_getstring(v,2,&filename); + if(sq_gettop(v) >= 3) { + sq_getbool(v,3,&printerror); + } + sq_push(v,1); //repush the this + if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror))) + return 1; + return SQ_ERROR; //propagates the error +} + +#define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck} +static SQRegFunction iolib_funcs[]={ + _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")), + _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")), + {0,0} +}; + +SQRESULT sqstd_register_iolib(HSQUIRRELVM v) +{ + int top = sq_gettop(v); + //create delegate + declare_stream(v,_SC("file"),SQSTD_FILE_TYPE_TAG,_SC("std_file"),_file_methods,iolib_funcs); + sq_pushstring(v,_SC("stdout"),-1); + sqstd_createfile(v,stdout,0); + sq_createslot(v,-3); + sq_pushstring(v,_SC("stdin"),-1); + sqstd_createfile(v,stdin,0); + sq_createslot(v,-3); + sq_pushstring(v,_SC("stderr"),-1); + sqstd_createfile(v,stderr,0); + sq_createslot(v,-3); + sq_settop(v,top); + return SQ_OK; +} diff --git a/src/squirrel/sqstdlib/sqstdlib.dsp b/src/squirrel/sqstdlib/sqstdlib.dsp new file mode 100644 index 000000000..9fd09ef27 --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdlib.dsp @@ -0,0 +1,131 @@ +# Microsoft Developer Studio Project File - Name="sqstdlib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=sqstdlib - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "sqstdlib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "sqstdlib.mak" CFG="sqstdlib - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "sqstdlib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "sqstdlib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "sqstdlib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x410 /d "NDEBUG" +# ADD RSC /l 0x410 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\sqstdlib.lib" + +!ELSEIF "$(CFG)" == "sqstdlib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x410 /d "_DEBUG" +# ADD RSC /l 0x410 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\sqstdlib.lib" + +!ENDIF + +# Begin Target + +# Name "sqstdlib - Win32 Release" +# Name "sqstdlib - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\sqstdblob.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdio.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdmath.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdrex.c +# End Source File +# Begin Source File + +SOURCE=.\sqstdstream.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdstring.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdaux.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqstdsystem.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\sqstdblobimpl.h +# End Source File +# Begin Source File + +SOURCE=.\sqstdstream.h +# End Source File +# End Group +# End Target +# End Project diff --git a/src/squirrel/sqstdlib/sqstdmath.cpp b/src/squirrel/sqstdlib/sqstdmath.cpp new file mode 100644 index 000000000..0b613737e --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdmath.cpp @@ -0,0 +1,105 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include + +#define SINGLE_ARG_FUNC(_funcname) static int math_##_funcname(HSQUIRRELVM v){ \ + SQFloat f; \ + sq_getfloat(v,2,&f); \ + sq_pushfloat(v,(SQFloat)_funcname(f)); \ + return 1; \ +} + +#define TWO_ARGS_FUNC(_funcname) static int math_##_funcname(HSQUIRRELVM v){ \ + SQFloat p1,p2; \ + sq_getfloat(v,2,&p1); \ + sq_getfloat(v,3,&p2); \ + sq_pushfloat(v,(SQFloat)_funcname(p1,p2)); \ + return 1; \ +} + +static int math_srand(HSQUIRRELVM v) +{ + SQInteger i; + if(!sq_getinteger(v,2,&i))return sq_throwerror(v,_SC("invalid param")); + srand(i); + return 0; +} + +static int math_rand(HSQUIRRELVM v) +{ + sq_pushinteger(v,rand()); + return 1; +} + +static int math_abs(HSQUIRRELVM v) +{ + SQInteger n; + sq_getinteger(v,2,&n); + sq_pushinteger(v,(SQInteger)abs(n)); + return 1; +} + +SINGLE_ARG_FUNC(sqrt) +SINGLE_ARG_FUNC(fabs) +SINGLE_ARG_FUNC(sin) +SINGLE_ARG_FUNC(cos) +SINGLE_ARG_FUNC(asin) +SINGLE_ARG_FUNC(acos) +SINGLE_ARG_FUNC(log) +SINGLE_ARG_FUNC(log10) +SINGLE_ARG_FUNC(tan) +SINGLE_ARG_FUNC(atan) +TWO_ARGS_FUNC(atan2) +TWO_ARGS_FUNC(pow) +SINGLE_ARG_FUNC(floor) +SINGLE_ARG_FUNC(ceil) +SINGLE_ARG_FUNC(exp) + +#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),math_##name,nparams,tycheck} +static SQRegFunction mathlib_funcs[] = { + _DECL_FUNC(sqrt,2,_SC(".n")), + _DECL_FUNC(sin,2,_SC(".n")), + _DECL_FUNC(cos,2,_SC(".n")), + _DECL_FUNC(asin,2,_SC(".n")), + _DECL_FUNC(acos,2,_SC(".n")), + _DECL_FUNC(log,2,_SC(".n")), + _DECL_FUNC(log10,2,_SC(".n")), + _DECL_FUNC(tan,2,_SC(".n")), + _DECL_FUNC(atan,2,_SC(".n")), + _DECL_FUNC(atan2,3,_SC(".nn")), + _DECL_FUNC(pow,3,_SC(".nn")), + _DECL_FUNC(floor,2,_SC(".n")), + _DECL_FUNC(ceil,2,_SC(".n")), + _DECL_FUNC(exp,2,_SC(".n")), + _DECL_FUNC(srand,2,_SC(".n")), + _DECL_FUNC(rand,1,NULL), + _DECL_FUNC(fabs,2,_SC(".n")), + _DECL_FUNC(abs,2,_SC(".n")), + {0,0}, +}; + +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + +SQRESULT sqstd_register_mathlib(HSQUIRRELVM v) +{ + int i=0; + while(mathlib_funcs[i].name!=0) { + sq_pushstring(v,mathlib_funcs[i].name,-1); + sq_newclosure(v,mathlib_funcs[i].f,0); + sq_setparamscheck(v,mathlib_funcs[i].nparamscheck,mathlib_funcs[i].typemask); + sq_setnativeclosurename(v,-1,mathlib_funcs[i].name); + sq_createslot(v,-3); + i++; + } + sq_pushstring(v,_SC("RAND_MAX"),-1); + sq_pushinteger(v,RAND_MAX); + sq_createslot(v,-3); + sq_pushstring(v,_SC("PI"),-1); + sq_pushfloat(v,(SQFloat)M_PI); + sq_createslot(v,-3); + return SQ_OK; +} diff --git a/src/squirrel/sqstdlib/sqstdrex.c b/src/squirrel/sqstdlib/sqstdrex.c new file mode 100644 index 000000000..534f17da1 --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdrex.c @@ -0,0 +1,586 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include "sqstdstring.h" + +#ifdef _DEBUG +#include + +static const SQChar *g_nnames[] = +{ + _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"), + _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"), + _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"), + _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB") +}; + +#endif + +#define OP_GREEDY MAX_CHAR+1 // * + ? {n} +#define OP_OR MAX_CHAR+2 +#define OP_EXPR MAX_CHAR+3 //parentesis () +#define OP_NOCAPEXPR MAX_CHAR+4 //parentesis (?:) +#define OP_DOT MAX_CHAR+5 +#define OP_CLASS MAX_CHAR+6 +#define OP_CCLASS MAX_CHAR+7 +#define OP_NCLASS MAX_CHAR+8 //negates class the [^ +#define OP_RANGE MAX_CHAR+9 +#define OP_CHAR MAX_CHAR+10 +#define OP_EOL MAX_CHAR+11 +#define OP_BOL MAX_CHAR+12 +#define OP_WB MAX_CHAR+13 + +#define SQREX_SYMBOL_ANY_CHAR '.' +#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE '+' +#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE '*' +#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE '?' +#define SQREX_SYMBOL_BRANCH '|' +#define SQREX_SYMBOL_END_OF_STRING '$' +#define SQREX_SYMBOL_BEGINNING_OF_STRING '^' +#define SQREX_SYMBOL_ESCAPE_CHAR '\\' + + +typedef int SQRexNodeType; + +typedef struct tagSQRexNode{ + SQRexNodeType type; + long left; + long right; + int next; +}SQRexNode; + +struct SQRex{ + const SQChar *_eol; + const SQChar *_bol; + const SQChar *_p; + int _first; + int _op; + SQRexNode *_nodes; + int _nallocated; + int _nsize; + int _nsubexpr; + SQRexMatch *_matches; + int _currsubexp; + void *_jmpbuf; + const SQChar **_error; +}; + +static int sqstd_rex_list(SQRex *exp); + +static int sqstd_rex_newnode(SQRex *exp, SQRexNodeType type) +{ + SQRexNode n; + n.type = type; + n.next = n.right = n.left = -1; + if(type == OP_EXPR) + n.right = exp->_nsubexpr++; + if(exp->_nallocated < (exp->_nsize + 1)) { + int oldsize = exp->_nallocated; + exp->_nallocated *= 2; + exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode)); + } + exp->_nodes[exp->_nsize++] = n; + return (int)exp->_nsize - 1; +} + +static void sqstd_rex_error(SQRex *exp,const SQChar *error) +{ + if(exp->_error) *exp->_error = error; + longjmp(*((jmp_buf*)exp->_jmpbuf),-1); +} + +static void sqstd_rex_expect(SQRex *exp, int n){ + if((*exp->_p) != n) + sqstd_rex_error(exp, _SC("expected paren")); + exp->_p++; +} + +static SQBool sqstd_rex_ischar(SQChar c) +{ + switch(c) { + case SQREX_SYMBOL_BRANCH:case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: + case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE:case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: + case SQREX_SYMBOL_BEGINNING_OF_STRING:case SQREX_SYMBOL_END_OF_STRING: + case SQREX_SYMBOL_ANY_CHAR:case SQREX_SYMBOL_ESCAPE_CHAR:case '(':case ')':case '[':case '{': case '}': + return SQFalse; + } + return SQTrue; +} + +static SQChar sqstd_rex_escapechar(SQRex *exp) +{ + if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){ + exp->_p++; + switch(*exp->_p) { + case 'v': exp->_p++; return '\v'; + case 'n': exp->_p++; return '\n'; + case 't': exp->_p++; return '\t'; + case 'r': exp->_p++; return '\r'; + case 'f': exp->_p++; return '\f'; + default: return (*exp->_p++); + } + } else if(!sqstd_rex_ischar(*exp->_p)) sqstd_rex_error(exp,_SC("letter expected")); + return (*exp->_p++); +} + +static int sqstd_rex_charclass(SQRex *exp,int classid) +{ + int n = sqstd_rex_newnode(exp,OP_CCLASS); + exp->_nodes[n].left = classid; + return n; +} + +static int sqstd_rex_charnode(SQRex *exp,SQBool isclass) +{ + if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) { + exp->_p++; + switch(*exp->_p) { + case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n'); + case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t'); + case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r'); + case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f'); + case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v'); + case 'a': case 'A': case 'w': case 'W': case 's': case 'S': + case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': + case 'p': case 'P': case 'l': case 'u': + { + SQChar t = *exp->_p; + exp->_p++; + return sqstd_rex_charclass(exp,t); + } + case 'b': + case 'B': + if(!isclass) { + int node = sqstd_rex_newnode(exp,OP_WB); + exp->_nodes[node].left = *exp->_p; + exp->_p++; + return node; + } //else default + default: return sqstd_rex_newnode(exp,(*exp->_p++)); + } + } + else if(!sqstd_rex_ischar(*exp->_p)) { + + sqstd_rex_error(exp,_SC("letter expected")); + } + return sqstd_rex_newnode(exp,*exp->_p++); +} +static int sqstd_rex_class(SQRex *exp) +{ + int ret = -1; + int first = -1,chain; + if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){ + ret = sqstd_rex_newnode(exp,OP_NCLASS); + exp->_p++; + }else ret = sqstd_rex_newnode(exp,OP_CLASS); + + if(*exp->_p == ']' || *exp->_p == '-'){ + first = *exp->_p; + exp->_p++; + } + chain = ret; + while(*exp->_p != ']' && exp->_p != exp->_eol) { + if(*exp->_p == '-' && first != -1){ + int r; + if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range")); + r = sqstd_rex_newnode(exp,OP_RANGE); + if(first>*exp->_p) sqstd_rex_error(exp,_SC("invalid range")); + if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC("cannot use character classes in ranges")); + exp->_nodes[r].left = exp->_nodes[first].type; + exp->_nodes[r].right = sqstd_rex_escapechar(exp); + exp->_nodes[chain].next = r; + chain = r; + first = -1; + } + else{ + if(first!=-1){ + int c = first; + exp->_nodes[chain].next = c; + chain = c; + first = sqstd_rex_charnode(exp,SQTrue); + } + else{ + first = sqstd_rex_charnode(exp,SQTrue); + } + } + } + if(first!=-1){ + int c = first; + exp->_nodes[chain].next = c; + chain = c; + first = -1; + } + /* hack? */ + exp->_nodes[ret].left = exp->_nodes[ret].next; + exp->_nodes[ret].next = -1; + return ret; +} + +static int sqstd_rex_parsenumber(SQRex *exp) +{ + int ret = *exp->_p-'0'; + int positions = 10; + exp->_p++; + while(isdigit(*exp->_p)) { + ret = ret*10+(*exp->_p++-'0'); + if(positions==1000000000) sqstd_rex_error(exp,_SC("overflow in numeric constant")); + positions *= 10; + }; + return ret; +} + +static int sqstd_rex_element(SQRex *exp) +{ + int ret; + switch(*exp->_p) + { + case '(': { + int expr; + exp->_p++; + + + if(*exp->_p =='?') { + exp->_p++; + sqstd_rex_expect(exp,':'); + expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR); + } + else + expr = sqstd_rex_newnode(exp,OP_EXPR); + exp->_nodes[expr].left = sqstd_rex_list(exp); + ret = expr; + sqstd_rex_expect(exp,')'); + } + break; + case '[': + exp->_p++; + ret = sqstd_rex_class(exp); + sqstd_rex_expect(exp,']'); + break; + case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break; + case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break; + default: + ret = sqstd_rex_charnode(exp,SQFalse); + break; + } + /* scope block */ + { + int op; + unsigned short p0 = 0, p1 = 0; + switch(*exp->_p){ + case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; goto __end; + case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; goto __end; + case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; goto __end; + case '{':{ + exp->_p++; + if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC("number expected")); + p0 = sqstd_rex_parsenumber(exp); + switch(*exp->_p) { + case '}': + p1 = p0; exp->_p++; + goto __end; + case ',': + exp->_p++; + p1 = 0xFFFF; + if(isdigit(*exp->_p)){ + p1 = sqstd_rex_parsenumber(exp); + } + sqstd_rex_expect(exp,'}'); + goto __end; + default: + sqstd_rex_error(exp,_SC(", or } expected")); + } + } + __end: { + int nnode = sqstd_rex_newnode(exp,OP_GREEDY); + op = OP_GREEDY; + exp->_nodes[nnode].left = ret; + exp->_nodes[nnode].right = ((p0)<<16)|p1; + ret = nnode; + } + } + } + if(*exp->_p != SQREX_SYMBOL_BRANCH && *exp->_p != ')' && *exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE && *exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE && *exp->_p != '\0') + exp->_nodes[ret].next = sqstd_rex_element(exp); + return ret; +} + +static int sqstd_rex_list(SQRex *exp) +{ + int ret=-1,e; + if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) { + exp->_p++; + ret = sqstd_rex_newnode(exp,OP_BOL); + } + e = sqstd_rex_element(exp); + if(ret != -1) { + exp->_nodes[ret].next = e; + } + else ret = e; + + if(*exp->_p == SQREX_SYMBOL_BRANCH) { + int temp; + exp->_p++; + temp = sqstd_rex_newnode(exp,OP_OR); + exp->_nodes[temp].left = ret; + exp->_nodes[temp].right = sqstd_rex_list(exp); + ret = temp; + } + return ret; +} + +static SQBool sqstd_rex_matchcclass(int cclass,SQChar c) +{ + switch(cclass) { + case 'a': return isalpha(c)?SQTrue:SQFalse; + case 'A': return !isalpha(c)?SQTrue:SQFalse; + case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse; + case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse; + case 's': return isspace(c)?SQTrue:SQFalse; + case 'S': return !isspace(c)?SQTrue:SQFalse; + case 'd': return isdigit(c)?SQTrue:SQFalse; + case 'D': return !isdigit(c)?SQTrue:SQFalse; + case 'x': return isxdigit(c)?SQTrue:SQFalse; + case 'X': return !isxdigit(c)?SQTrue:SQFalse; + case 'c': return iscntrl(c)?SQTrue:SQFalse; + case 'C': return !iscntrl(c)?SQTrue:SQFalse; + case 'p': return ispunct(c)?SQTrue:SQFalse; + case 'P': return !ispunct(c)?SQTrue:SQFalse; + case 'l': return islower(c)?SQTrue:SQFalse; + case 'u': return isupper(c)?SQTrue:SQFalse; + } + return SQFalse; /*cannot happen*/ +} + +static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQChar c) +{ + do { + switch(node->type) { + case OP_RANGE: + if(c >= node->left && c <= node->right) return SQTrue; + break; + case OP_CCLASS: + if(sqstd_rex_matchcclass(node->left,c)) return SQTrue; + break; + default: + if(c == node->type)return SQTrue; + } + } while((node->next != -1) && (node = &exp->_nodes[node->next])); + return SQFalse; +} + +static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str) +{ + SQRexNodeType type = node->type; + switch(type) { + case OP_GREEDY: { + int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; + const SQChar *s=str, *good = str; + while((nmaches == 0xFFFF || nmaches < p1) + && (s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s))) { + good=s; + nmaches++; + if(s >= exp->_eol) + break; + } + if(p0 == p1 && p0 == nmaches) return good; + else if(nmaches >= p0 && p1 == 0xFFFF) return good; + else if(nmaches >= p0 && nmaches <= p1) return good; + return NULL; + } + case OP_OR: { + const SQChar *asd = str; + SQRexNode *temp=&exp->_nodes[node->left]; + while(asd = sqstd_rex_matchnode(exp,temp,asd)) { + if(temp->next != -1) + temp = &exp->_nodes[temp->next]; + else + return asd; + } + asd = str; + temp = &exp->_nodes[node->right]; + while(asd = sqstd_rex_matchnode(exp,temp,asd)) { + if(temp->next != -1) + temp = &exp->_nodes[temp->next]; + else + return asd; + } + return NULL; + break; + } + case OP_EXPR: + case OP_NOCAPEXPR:{ + SQRexNode *n = &exp->_nodes[node->left]; + const SQChar *cur = str; + int capture = -1; + if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { + capture = exp->_currsubexp; + exp->_matches[capture].begin = cur; + exp->_currsubexp++; + } + + do { + if(!(cur = sqstd_rex_matchnode(exp,n,cur))) { + if(capture != -1){ + exp->_matches[capture].begin = 0; + exp->_matches[capture].len = 0; + } + return NULL; + } + } while((n->next != -1) && (n = &exp->_nodes[n->next])); + + if(capture != -1) + exp->_matches[capture].len = cur - exp->_matches[capture].begin; + return cur; + } + case OP_WB: + if(str == exp->_bol && !isspace(*str) + || (str == exp->_eol && !isspace(*(str-1))) + || (!isspace(*str) && isspace(*(str+1))) + || (isspace(*str) && !isspace(*(str+1))) ) { + return (node->left == 'b')?str:NULL; + } + return (node->left == 'b')?NULL:str; + case OP_BOL: + if(str == exp->_bol) return str; + return NULL; + case OP_EOL: + if(str == exp->_eol) return str; + return NULL; + case OP_DOT: + *str++; + return str; + case OP_NCLASS: + case OP_CLASS: + if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) { + *str++; + return str; + } + return NULL; + case OP_CCLASS: + if(sqstd_rex_matchcclass(node->left,*str)) { + *str++; + return str; + } + return NULL; + default: /* char */ + if(*str != node->type) return NULL; + *str++; + return str; + } + return NULL; +} + +/* public api */ +SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error) +{ + SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex)); + exp->_p = pattern; + exp->_nallocated = (int)scstrlen(pattern) * sizeof(SQChar); + exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode)); + exp->_nsize = 0; + exp->_matches = 0; + exp->_nsubexpr = 0; + exp->_first = sqstd_rex_newnode(exp,OP_EXPR); + exp->_error = error; + exp->_jmpbuf = sq_malloc(sizeof(jmp_buf)); + if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) { + exp->_nodes[exp->_first].left=sqstd_rex_list(exp); + if(*exp->_p!='\0') + sqstd_rex_error(exp,_SC("unexpected character")); +#ifdef _DEBUG + { + int nsize,i; + SQRexNode *t; + nsize = exp->_nsize; + t = &exp->_nodes[0]; + scprintf(_SC("\n")); + for(i = 0;i < nsize; i++) { + if(exp->_nodes[i].type>MAX_CHAR) + scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]); + else + scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type); + scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next); + } + scprintf(_SC("\n")); + } +#endif + exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch)); + memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch)); + } + else{ + sqstd_rex_free(exp); + return NULL; + } + return exp; +} + +void sqstd_rex_free(SQRex *exp) +{ + if(exp) { + if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode)); + if(exp->_jmpbuf) sq_free(exp->_jmpbuf,sizeof(jmp_buf)); + if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch)); + sq_free(exp,sizeof(SQRex)); + } +} + +SQBool sqstd_rex_match(SQRex* exp,const SQChar* text) +{ + const SQChar* res = NULL; + exp->_bol = text; + exp->_eol = text + scstrlen(text); + exp->_currsubexp = 0; + res = sqstd_rex_matchnode(exp,exp->_nodes,text); + if(res == NULL || res != exp->_eol) + return SQFalse; + return SQTrue; +} + +SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end) +{ + const SQChar *cur = NULL; + int node = exp->_first; + if(text_begin >= text_end) return SQFalse; + exp->_bol = text_begin; + exp->_eol = text_end; + do { + cur = text_begin; + while(node != -1) { + exp->_currsubexp = 0; + cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur); + if(!cur) + break; + node = exp->_nodes[node].next; + } + *text_begin++; + } while(cur == NULL && text_begin != text_end); + + if(cur == NULL) + return SQFalse; + + --text_begin; + + if(out_begin) *out_begin = text_begin; + if(out_end) *out_end = cur; + return SQTrue; +} + +SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end) +{ + return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end); +} + +int sqstd_rex_getsubexpcount(SQRex* exp) +{ + return exp->_nsubexpr; +} + +SQBool sqstd_rex_getsubexp(SQRex* exp, int n, SQRexMatch *subexp) +{ + if( n<0 || n >= exp->_nsubexpr) return SQFalse; + *subexp = exp->_matches[n]; + return SQTrue; +} + diff --git a/src/squirrel/sqstdlib/sqstdstream.cpp b/src/squirrel/sqstdlib/sqstdstream.cpp new file mode 100644 index 000000000..3cbc808bd --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdstream.cpp @@ -0,0 +1,396 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include +#include +#include +#include "sqstdstream.h" +#include "sqstdblobimpl.h" + +#define SETUP_STREAM(v) \ + SQStream *self = NULL; \ + if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,SQSTD_STREAM_TYPE_TAG))) \ + return sq_throwerror(v,_SC("invalid type tag")); \ + if(!self->IsValid()) \ + return sq_throwerror(v,_SC("the stream is invalid")); + +int _stream_readstr(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + SQInteger type = _SC('a'), size = 0; + sq_getinteger(v, 2, &size); + if(size <= 0) return sq_throwerror(v,_SC("invalid size")); + if(sq_gettop(v) > 2) + sq_getinteger(v, 3, &type); + SQChar *dest = NULL; + switch(type) { + case _SC('a'): { + char *temp; + if(self->Read(sq_getscratchpad(v, size+1), size) != size) + return sq_throwerror(v, _SC("io failure")); +#ifdef _UNICODE + temp = (char*) sq_getscratchpad(v, size + (size * sizeof(SQChar))); + dest = (SQChar*) &temp[size]; + size = (SQInteger)mbstowcs(dest, (const char*)temp, size); +#else + temp = (char *) sq_getscratchpad(v, -1); + dest = temp; +#endif + } + break; + case _SC('u'): { + wchar_t *temp; + if(self->Read(sq_getscratchpad(v, (size + 1) * sizeof(wchar_t)),size * sizeof(wchar_t)) != (size * sizeof(wchar_t))) + return sq_throwerror(v, _SC("io failure")); + +#ifdef _UNICODE + temp = (wchar_t*) sq_getscratchpad(v, -1); + dest = (SQChar*) temp; +#else + temp = (wchar_t*) sq_getscratchpad(v,(size * 3) + (size * sizeof(wchar_t))); + dest = (char*) &temp[size]; + size = (SQInteger)wcstombs(dest, (const wchar_t*)temp, size); +#endif + } + break; + default: + return sq_throwerror(v, _SC("invalid coding")); + } + + sq_pushstring(v, dest, size); + return 1; +} + +int _stream_readblob(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + SQUserPointer data,blobp; + SQInteger size,res; + sq_getinteger(v,2,&size); + if(size > self->Len()) { + size = self->Len(); + } + data = sq_getscratchpad(v,size); + res = self->Read(data,size); + if(res <= 0) + return sq_throwerror(v,_SC("no data left to read")); + blobp = sqstd_createblob(v,res); + memcpy(blobp,data,res); + return 1; +} + +#define SAFE_READN(ptr,len) { \ + if(self->Read(ptr,len) != len) return sq_throwerror(v,_SC("io error")); \ + } +int _stream_readn(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + SQInteger format; + sq_getinteger(v, 2, &format); + switch(format) { + case 'i': { + int i; + SAFE_READN(&i, sizeof(i)); + sq_pushinteger(v, i); + } + break; + case 's': { + short s; + SAFE_READN(&s, sizeof(short)); + sq_pushinteger(v, s); + } + break; + case 'w': { + unsigned short w; + SAFE_READN(&w, sizeof(unsigned short)); + sq_pushinteger(v, w); + } + break; + case 'c': { + char c; + SAFE_READN(&c, sizeof(char)); + sq_pushinteger(v, c); + } + break; + case 'b': { + unsigned char c; + SAFE_READN(&c, sizeof(unsigned char)); + sq_pushinteger(v, c); + } + break; + case 'f': { + float f; + SAFE_READN(&f, sizeof(float)); + sq_pushfloat(v, f); + } + break; + case 'd': { + double d; + SAFE_READN(&d, sizeof(double)); + sq_pushfloat(v, (SQFloat)d); + } + break; + default: + return sq_throwerror(v, _SC("invalid format")); + } + return 1; +} + +int _stream_writestr(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + const SQChar *str,*res; + SQInteger trgformat = 'a',len = 0; + sq_getstring(v,2,&str); + len = sq_getsize(v,2); + if(sq_gettop(v)>2) + sq_getinteger(v,3,&trgformat); + switch(trgformat) + { + case 'a': +#ifdef _UNICODE + res = sq_getscratchpad(v,len*3); + len = (SQInteger) wcstombs((char *)res, (const wchar_t*)str, len); +#else + res = str; +#endif + self->Write((void *)res,len); + break; + case 'u': +#ifdef _UNICODE + res = str; +#else + res = sq_getscratchpad(v,len*sizeof(wchar_t)); + len = (SQInteger) mbstowcs((wchar_t*)res, str, len); +#endif + self->Write((void *)res,len*sizeof(wchar_t)); + break; + default: + return sq_throwerror(v,_SC("wrong encoding")); + } + + return 0; +} + +int _stream_writeblob(HSQUIRRELVM v) +{ + SQUserPointer data; + int size; + SETUP_STREAM(v); + if(SQ_FAILED(sqstd_getblob(v,2,&data))) + return sq_throwerror(v,_SC("invalid parameter")); + size = sqstd_getblobsize(v,2); + if(self->Write(data,size) != size) + return sq_throwerror(v,_SC("io error")); + sq_pushinteger(v,size); + return 1; +} + +int _stream_writen(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + SQInteger format, ti; + SQFloat tf; + sq_getinteger(v, 3, &format); + switch(format) { + case 'i': { + int i; + sq_getinteger(v, 2, &ti); + i = ti; + self->Write(&i, sizeof(int)); + } + break; + case 's': { + short s; + sq_getinteger(v, 2, &ti); + s = ti; + self->Write(&s, sizeof(short)); + } + break; + case 'w': { + unsigned short w; + sq_getinteger(v, 2, &ti); + w = ti; + self->Write(&w, sizeof(unsigned short)); + } + break; + case 'c': { + char c; + sq_getinteger(v, 2, &ti); + c = ti; + self->Write(&c, sizeof(char)); + } + break; + case 'b': { + unsigned char b; + sq_getinteger(v, 2, &ti); + b = ti; + self->Write(&b, sizeof(unsigned char)); + } + break; + case 'f': { + float f; + sq_getfloat(v, 2, &tf); + f = tf; + self->Write(&f, sizeof(float)); + } + break; + case 'd': { + double d; + sq_getfloat(v, 2, &tf); + d = tf; + self->Write(&d, sizeof(double)); + } + break; + default: + return sq_throwerror(v, _SC("invalid format")); + } + return 0; +} + +int _stream_seek(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + SQInteger offset, origin = SQ_SEEK_SET; + sq_getinteger(v, 2, &offset); + if(sq_gettop(v) > 2) { + SQInteger t; + sq_getinteger(v, 3, &t); + switch(t) { + case 'b': origin = SQ_SEEK_SET; break; + case 'c': origin = SQ_SEEK_CUR; break; + case 'e': origin = SQ_SEEK_END; break; + default: return sq_throwerror(v,_SC("invalid origin")); + } + } + sq_pushinteger(v, self->Seek(offset, origin)); + return 1; +} + +int _stream_tell(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + sq_pushinteger(v, self->Tell()); + return 1; +} + +int _stream_len(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + sq_pushinteger(v, self->Len()); + return 1; +} + +int _stream_flush(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + if(!self->Flush()) + sq_pushinteger(v, 1); + else + sq_pushnull(v); + return 1; +} + +int _stream_eos(HSQUIRRELVM v) +{ + SETUP_STREAM(v); + if(self->EOS()) + sq_pushinteger(v, 1); + else + sq_pushnull(v); + return 1; +} + +static SQRegFunction _stream_methods[] = { + _DECL_STREAM_FUNC(readstr,-2,_SC("xnn")), + _DECL_STREAM_FUNC(readblob,2,_SC("xn")), + _DECL_STREAM_FUNC(readn,2,_SC("xn")), + _DECL_STREAM_FUNC(writestr,-2,_SC("xsn")), + _DECL_STREAM_FUNC(writeblob,-2,_SC("xx")), + _DECL_STREAM_FUNC(writen,3,_SC("xnn")), + _DECL_STREAM_FUNC(seek,-2,_SC("xnn")), + _DECL_STREAM_FUNC(tell,1,_SC("x")), + _DECL_STREAM_FUNC(len,1,_SC("x")), + _DECL_STREAM_FUNC(eos,1,_SC("x")), + _DECL_STREAM_FUNC(flush,1,_SC("x")), + {0,0} +}; + +void init_streamclass(HSQUIRRELVM v) +{ + sq_pushregistrytable(v); + sq_pushstring(v,_SC("std_stream"),-1); + if(SQ_FAILED(sq_get(v,-2))) { + sq_pushstring(v,_SC("std_stream"),-1); + sq_newclass(v,SQFalse); + sq_settypetag(v,-1,SQSTD_STREAM_TYPE_TAG); + int i = 0; + while(_stream_methods[i].name != 0) { + SQRegFunction &f = _stream_methods[i]; + sq_pushstring(v,f.name,-1); + sq_newclosure(v,f.f,0); + sq_setparamscheck(v,f.nparamscheck,f.typemask); + sq_createslot(v,-3); + i++; + } + sq_createslot(v,-3); + } + else { + sq_pop(v,1); //result + } + sq_pop(v,1); +} + +SQRESULT declare_stream(HSQUIRRELVM v,SQChar* name,int typetag,SQChar* reg_name,SQRegFunction *methods,SQRegFunction *globals) +{ + if(sq_gettype(v,-1) != OT_TABLE) + return sq_throwerror(v,_SC("table expected")); + int top = sq_gettop(v); + //create delegate + init_streamclass(v); + sq_pushregistrytable(v); + sq_pushstring(v,reg_name,-1); + sq_pushstring(v,_SC("std_stream"),-1); + if(SQ_SUCCEEDED(sq_get(v,-3))) { + sq_newclass(v,SQTrue); + sq_settypetag(v,-1,typetag); + int i = 0; + while(methods[i].name != 0) { + SQRegFunction &f = methods[i]; + sq_pushstring(v,f.name,-1); + sq_newclosure(v,f.f,0); + sq_setparamscheck(v,f.nparamscheck,f.typemask); + sq_setnativeclosurename(v,-1,f.name); + sq_createslot(v,-3); + i++; + } + sq_createslot(v,-3); + sq_pop(v,1); + + i = 0; + while(globals[i].name!=0) + { + SQRegFunction &f = globals[i]; + sq_pushstring(v,f.name,-1); + sq_newclosure(v,f.f,0); + sq_setparamscheck(v,f.nparamscheck,f.typemask); + sq_setnativeclosurename(v,-1,f.name); + sq_createslot(v,-3); + i++; + } + //register the class in the target table + sq_pushstring(v,name,-1); + sq_pushregistrytable(v); + sq_pushstring(v,reg_name,-1); + sq_get(v,-2); + sq_remove(v,-2); + sq_createslot(v,-3); + + sq_settop(v,top); + return SQ_OK; + } + sq_settop(v,top); + return SQ_ERROR; +} diff --git a/src/squirrel/sqstdlib/sqstdstream.h b/src/squirrel/sqstdlib/sqstdstream.h new file mode 100644 index 000000000..a13bc4d03 --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdstream.h @@ -0,0 +1,20 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_STREAM_H_ +#define _SQSTD_STREAM_H_ + +int _stream_readstr(HSQUIRRELVM v); +int _stream_readblob(HSQUIRRELVM v); +int _stream_readline(HSQUIRRELVM v); +int _stream_readn(HSQUIRRELVM v); +int _stream_writestr(HSQUIRRELVM v); +int _stream_writeblob(HSQUIRRELVM v); +int _stream_writen(HSQUIRRELVM v); +int _stream_seek(HSQUIRRELVM v); +int _stream_tell(HSQUIRRELVM v); +int _stream_len(HSQUIRRELVM v); +int _stream_eos(HSQUIRRELVM v); +int _stream_flush(HSQUIRRELVM v); + +#define _DECL_STREAM_FUNC(name,nparams,typecheck) {_SC(#name),_stream_##name,nparams,typecheck} +SQRESULT declare_stream(HSQUIRRELVM v,SQChar* name,int typetag,SQChar* reg_name,SQRegFunction *methods,SQRegFunction *globals); +#endif /*_SQSTD_STREAM_H_*/ diff --git a/src/squirrel/sqstdlib/sqstdstring.cpp b/src/squirrel/sqstdlib/sqstdstring.cpp new file mode 100644 index 000000000..728376bf3 --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdstring.cpp @@ -0,0 +1,272 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include +#include + +#ifdef _UNICODE +#define scstrchr wcschr +#define scsnprintf wsnprintf +#define scatoi _wtoi +#else +#define scstrchr strchr +#define scsnprintf snprintf +#define scatoi atoi +#endif +#define MAX_FORMAT_LEN 20 +#define MAX_WFORMAT_LEN 3 +#define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar)) + +static int validate_format(HSQUIRRELVM v, SQChar *fmt, const SQChar *src, int n,int &width) +{ + SQChar swidth[MAX_WFORMAT_LEN]; + int wc = 0; + int start = n; + fmt[0] = '%'; + while (scstrchr(_SC("-+ #0"), src[n])) n++; + while (scisdigit(src[n])) { + swidth[wc] = src[n]; + n++; + wc++; + if(wc>=MAX_WFORMAT_LEN) + return sq_throwerror(v,_SC("width format too long")); + } + swidth[wc] = '\0'; + if(wc > 0) { + width = scatoi(swidth); + } + else + width = 0; + if (src[n] == '.') { + n++; + + wc = 0; + while (scisdigit(src[n])) { + swidth[wc] = src[n]; + n++; + wc++; + if(wc>=MAX_WFORMAT_LEN) + return sq_throwerror(v,_SC("precision format too long")); + } + swidth[wc] = '\0'; + if(wc > 0) { + width += scatoi(swidth); + } + } + if (n-start > MAX_FORMAT_LEN ) + return sq_throwerror(v,_SC("format too long")); + memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(SQChar)); + fmt[(n-start)+2] = '\0'; + return n; +} + +static int _string_format(HSQUIRRELVM v) +{ + const SQChar *format; + SQChar *dest; + SQChar fmt[MAX_FORMAT_LEN]; + sq_getstring(v,2,&format); + int allocated = (sq_getsize(v,2)+1)*sizeof(SQChar); + dest = sq_getscratchpad(v,allocated); + int n = 0,i = 0, nparam = 3, w; + while(format[n] != '\0') { + if(format[n] != '%') { + dest[i++] = format[n]; + n++; + } + else if(format[++n] == '%') { + dest[i++] = '%'; + } + else { + if( nparam > sq_gettop(v) ) + return sq_throwerror(v,_SC("not enough paramters for the given format string")); + n = validate_format(v,fmt,format,n,w); + if(n < 0) return -1; + int addlen = 0; + int valtype = 0; + const SQChar *ts; + SQInteger ti; + SQFloat tf; + switch(format[n]) { + case 's': + if(SQ_FAILED(sq_getstring(v,nparam,&ts))) + return sq_throwerror(v,_SC("string expected for the specified format")); + addlen = (sq_getsize(v,nparam)*sizeof(SQChar))+((w+1)*sizeof(SQChar)); + valtype = 's'; + break; + case 'i': case 'd': case 'c':case 'o': case 'u': case 'x': case 'X': + if(SQ_FAILED(sq_getinteger(v,nparam,&ti))) + return sq_throwerror(v,_SC("integer expected for the specified format")); + addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); + valtype = 'i'; + break; + case 'f': case 'g': case 'G': case 'e': case 'E': + if(SQ_FAILED(sq_getfloat(v,nparam,&tf))) + return sq_throwerror(v,_SC("float expected for the specified format")); + addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); + valtype = 'f'; + break; + default: + return sq_throwerror(v,_SC("invalid format")); + } + n++; + if((allocated-i) < addlen) + allocated += addlen - (allocated-i); + dest = sq_getscratchpad(v,allocated); + switch(valtype) { + case 's': i += scsprintf(&dest[i],fmt,ts); break; + case 'i': i += scsprintf(&dest[i],fmt,ti); break; + case 'f': i += scsprintf(&dest[i],fmt,tf); break; + }; + nparam ++; + } + } + sq_pushstring(v,dest,i); + return 1; +} + +#define SETUP_REX(v) \ + SQRex *self = NULL; \ + sq_getinstanceup(v,1,(SQUserPointer *)&self,0); + +static int _rexobj_releasehook(SQUserPointer p, int size) +{ + SQRex *self = ((SQRex *)p); + sqstd_rex_free(self); + return 1; +} + +static int _regexp_match(HSQUIRRELVM v) +{ + SETUP_REX(v); + const SQChar *str; + sq_getstring(v,2,&str); + if(sqstd_rex_match(self,str) == SQTrue) + { + sq_pushinteger(v,1); + return 1; + } + return 0; +} + +static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end) +{ + sq_newtable(v); + sq_pushstring(v,_SC("begin"),-1); + sq_pushinteger(v,begin - str); + sq_rawset(v,-3); + sq_pushstring(v,_SC("end"),-1); + sq_pushinteger(v,end - str); + sq_rawset(v,-3); +} + +static int _regexp_search(HSQUIRRELVM v) +{ + SETUP_REX(v); + const SQChar *str,*begin,*end; + SQInteger start = 0; + sq_getstring(v,2,&str); + if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); + if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { + _addrexmatch(v,str,begin,end); + return 1; + } + return 0; +} + +static int _regexp_capture(HSQUIRRELVM v) +{ + SETUP_REX(v); + const SQChar *str,*begin,*end; + SQInteger start = 0; + sq_getstring(v,2,&str); + if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); + if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { + SQInteger n = sqstd_rex_getsubexpcount(self); + SQRexMatch match; + sq_newarray(v,0); + for(SQInteger i = 0;i < n; i++) { + sqstd_rex_getsubexp(self,i,&match); + if(match.len > 0) + _addrexmatch(v,str,match.begin,match.begin+match.len); + else + _addrexmatch(v,str,str,str); //empty match + sq_arrayappend(v,-2); + } + return 1; + } + return 0; +} + +static int _regexp_subexpcount(HSQUIRRELVM v) +{ + SETUP_REX(v); + sq_pushinteger(v,sqstd_rex_getsubexpcount(self)); + return 1; +} + +static int _regexp_constructor(HSQUIRRELVM v) +{ + const SQChar *error,*pattern; + sq_getstring(v,2,&pattern); + SQRex *rex = sqstd_rex_compile(pattern,&error); + if(!rex) return sq_throwerror(v,error); + sq_setinstanceup(v,1,rex); + sq_setreleasehook(v,1,_rexobj_releasehook); + return 0; +} + +static int _regexp__typeof(HSQUIRRELVM v) +{ + sq_pushstring(v,_SC("regexp"),-1); + return 1; +} + +#define _DECL_REX_FUNC(name,nparams,pmask) {_SC(#name),_regexp_##name,nparams,pmask} +static SQRegFunction rexobj_funcs[]={ + _DECL_REX_FUNC(constructor,2,_SC(".s")), + _DECL_REX_FUNC(search,-2,_SC("xsn")), + _DECL_REX_FUNC(match,2,_SC("xs")), + _DECL_REX_FUNC(capture,-2,_SC("xsn")), + _DECL_REX_FUNC(subexpcount,1,_SC("x")), + _DECL_REX_FUNC(_typeof,1,_SC("x")), + {0,0} +}; + +#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask} +static SQRegFunction stringlib_funcs[]={ + _DECL_FUNC(format,-2,_SC(".s")), + {0,0} +}; + + +int sqstd_register_stringlib(HSQUIRRELVM v) +{ + sq_pushstring(v,_SC("regexp"),-1); + sq_newclass(v,SQFalse); + int i = 0; + while(rexobj_funcs[i].name != 0) { + SQRegFunction &f = rexobj_funcs[i]; + sq_pushstring(v,f.name,-1); + sq_newclosure(v,f.f,0); + sq_setparamscheck(v,f.nparamscheck,f.typemask); + sq_setnativeclosurename(v,-1,f.name); + sq_createslot(v,-3); + i++; + } + sq_createslot(v,-3); + + i = 0; + while(stringlib_funcs[i].name!=0) + { + sq_pushstring(v,stringlib_funcs[i].name,-1); + sq_newclosure(v,stringlib_funcs[i].f,0); + sq_setparamscheck(v,stringlib_funcs[i].nparamscheck,stringlib_funcs[i].typemask); + sq_setnativeclosurename(v,-1,stringlib_funcs[i].name); + sq_createslot(v,-3); + i++; + } + return 1; +} diff --git a/src/squirrel/sqstdlib/sqstdsystem.cpp b/src/squirrel/sqstdlib/sqstdsystem.cpp new file mode 100644 index 000000000..615a350bf --- /dev/null +++ b/src/squirrel/sqstdlib/sqstdsystem.cpp @@ -0,0 +1,145 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include +#include +#include + +#ifdef SQUNICODE +#include +#define scgetenv _wgetenv +#define scsystem _wsystem +#define scasctime _wasctime +#define scremove _wremove +#define screname _wrename +#else +#define scgetenv getenv +#define scsystem system +#define scasctime asctime +#define scremove remove +#define screname rename +#endif + +static int _system_getenv(HSQUIRRELVM v) +{ + const SQChar *s; + if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){ + sq_pushstring(v,scgetenv(s),-1); + return 1; + } + return 0; +} + + +static int _system_system(HSQUIRRELVM v) +{ + const SQChar *s; + if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){ + sq_pushinteger(v,scsystem(s)); + return 1; + } + return sq_throwerror(v,_SC("wrong param")); +} + + +static int _system_clock(HSQUIRRELVM v) +{ + sq_pushfloat(v,((SQFloat)clock())/(SQFloat)CLOCKS_PER_SEC); + return 1; +} + +static int _system_time(HSQUIRRELVM v) +{ + time_t t; + time(&t); + sq_pushinteger(v,*((SQInteger *)&t)); + return 1; +} + +static int _system_remove(HSQUIRRELVM v) +{ + const SQChar *s; + sq_getstring(v,2,&s); + if(scremove(s)==-1) + return sq_throwerror(v,_SC("remove() failed")); + return 0; +} + +static int _system_rename(HSQUIRRELVM v) +{ + const SQChar *oldn,*newn; + sq_getstring(v,2,&oldn); + sq_getstring(v,3,&newn); + if(screname(oldn,newn)==-1) + return sq_throwerror(v,_SC("rename() failed")); + return 0; +} + +static void _set_integer_slot(HSQUIRRELVM v,const SQChar *name,SQInteger val) +{ + sq_pushstring(v,name,-1); + sq_pushinteger(v,val); + sq_rawset(v,-3); +} + +static int _system_date(HSQUIRRELVM v) +{ + time_t t; + SQInteger format = 'l'; + if(sq_gettop(v) > 1) { + sq_getinteger(v,2,(SQInteger*)&t); + if(sq_gettop(v) > 2) { + sq_getinteger(v,3,(SQInteger*)&format); + } + } + else { + time(&t); + } + tm *date; + if(format == 'u') + date = gmtime(&t); + else + date = localtime(&t); + if(!date) + return sq_throwerror(v,_SC("crt api failure")); + sq_newtable(v); + _set_integer_slot(v, _SC("sec"), date->tm_sec); + _set_integer_slot(v, _SC("min"), date->tm_min); + _set_integer_slot(v, _SC("hour"), date->tm_hour); + _set_integer_slot(v, _SC("day"), date->tm_mday); + _set_integer_slot(v, _SC("month"), date->tm_mon); + _set_integer_slot(v, _SC("year"), date->tm_year+1900); + _set_integer_slot(v, _SC("wday"), date->tm_wday); + _set_integer_slot(v, _SC("yday"), date->tm_yday); + return 1; +} + + + +#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_system_##name,nparams,pmask} +static SQRegFunction systemlib_funcs[]={ + _DECL_FUNC(getenv,2,_SC(".s")), + _DECL_FUNC(system,2,_SC(".s")), + _DECL_FUNC(clock,1,NULL), + _DECL_FUNC(time,1,NULL), + _DECL_FUNC(date,-1,_SC(".nn")), + _DECL_FUNC(remove,2,_SC(".s")), + _DECL_FUNC(rename,3,_SC(".ss")), + {0,0} +}; + + +int sqstd_register_systemlib(HSQUIRRELVM v) +{ + int i=0; + while(systemlib_funcs[i].name!=0) + { + sq_pushstring(v,systemlib_funcs[i].name,-1); + sq_newclosure(v,systemlib_funcs[i].f,0); + sq_setparamscheck(v,systemlib_funcs[i].nparamscheck,systemlib_funcs[i].typemask); + sq_setnativeclosurename(v,-1,systemlib_funcs[i].name); + sq_createslot(v,-3); + i++; + } + return 1; +} diff --git a/src/squirrel/squirrel/Makefile b/src/squirrel/squirrel/Makefile new file mode 100644 index 000000000..98f2fe668 --- /dev/null +++ b/src/squirrel/squirrel/Makefile @@ -0,0 +1,42 @@ +SQUIRREL= .. + + +OUT= $(SQUIRREL)/lib/libsquirrel.a +INCZ= -I$(SQUIRREL)/include -I. -Iinclude +DEFS= +LIB= stdc++ + +OBJS= \ + sqapi.o \ + sqbaselib.o \ + sqcompiler.o \ + sqdebug.o \ + sqlexer.o \ + sqobject.o \ + sqparser.o \ + sqstate.o \ + sqtable.o \ + sqvm.o \ + sqmem.o \ + sqclass.o + +SRCS= \ + sqapi.cpp \ + sqbaselib.cpp \ + sqfuncstate.cpp \ + sqdebug.cpp \ + sqlexer.cpp \ + sqobject.cpp \ + sqcompiler.cpp \ + sqstate.cpp \ + sqtable.cpp \ + sqmem.cpp \ + sqvm.cpp \ + sqclass.cpp + + + +squirrellib: + gcc -O3 -Os -c $(SRCS) $(INCZ) $(DEFS) + ar rc $(OUT) *.o + rm *.o \ No newline at end of file diff --git a/src/squirrel/squirrel/sqapi.cpp b/src/squirrel/squirrel/sqapi.cpp new file mode 100644 index 000000000..2d269c2ce --- /dev/null +++ b/src/squirrel/squirrel/sqapi.cpp @@ -0,0 +1,1074 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "squserdata.h" +#include "sqfuncstate.h" +#include "sqcompiler.h" +#include "sqclass.h" + +bool sq_aux_gettypedarg(HSQUIRRELVM v,int idx,SQObjectType type,SQObjectPtr **o) +{ + *o = &stack_get(v,idx); + if(type(**o) != type){ + SQObjectPtr oval = v->PrintObjVal(**o); + v->Raise_Error(_SC("wrong argument type, expected '%s' got '%.50s'"),IdType2Name(type),_stringval(oval)); + return false; + } + return true; +} + +#define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; } + +#define sq_aux_paramscheck(v,count) \ +{ \ + if(sq_gettop(v) < count){ v->Raise_Error(_SC("not enough params in the stack")); return SQ_ERROR; }\ +} + +int sq_aux_throwobject(HSQUIRRELVM v,SQObjectPtr &e) +{ + v->_lasterror = e; + return SQ_ERROR; +} + +int sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type) +{ + scsprintf(_ss(v)->GetScratchPad(100), _SC("unexpected type %s"), IdType2Name(type)); + return sq_throwerror(v, _ss(v)->GetScratchPad(-1)); +} + +HSQUIRRELVM sq_open(int initialstacksize) +{ + SQSharedState *ss; + SQVM *v; + sq_new(ss, SQSharedState); + ss->Init(); + v = (SQVM *)SQ_MALLOC(sizeof(SQVM)); + new (v) SQVM(ss); + ss->_root_vm = v; + if(v->Init(NULL, initialstacksize)) { + return v; + } else { + sq_delete(v, SQVM); + return NULL; + } + return v; +} + +HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, int initialstacksize) +{ + SQSharedState *ss; + SQVM *v; + ss=_ss(friendvm); + + v= (SQVM *)SQ_MALLOC(sizeof(SQVM)); + new (v) SQVM(ss); + + if(v->Init(friendvm, initialstacksize)) { + friendvm->Push(v); + return v; + } else { + sq_delete(v, SQVM); + return NULL; + } +} + +int sq_getvmstate(HSQUIRRELVM v) +{ + if(v->_suspended) + return SQ_VMSTATE_SUSPENDED; + else { + if(v->_callsstack.size() != 0) return SQ_VMSTATE_RUNNING; + else return SQ_VMSTATE_IDLE; + } +} + +void sq_seterrorhandler(HSQUIRRELVM v) +{ + SQObject o = stack_get(v, -1); + if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { + v->_errorhandler = o; + v->Pop(); + } +} + +void sq_setdebughook(HSQUIRRELVM v) +{ + SQObject o = stack_get(v,-1); + if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { + v->_debughook = o; + v->Pop(); + } +} + +void sq_close(HSQUIRRELVM v) +{ + SQSharedState *ss = _ss(v); + _thread(ss->_root_vm)->Finalize(); + sq_delete(ss, SQSharedState); +} + +SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror) +{ + SQObjectPtr o; + if(Compile(v, read, p, sourcename, o, raiseerror?true:false, _ss(v)->_debuginfo)) { + v->Push(SQClosure::Create(_ss(v), _funcproto(o))); + return SQ_OK; + } + return SQ_ERROR; +} + +void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo) +{ + _ss(v)->_debuginfo = debuginfo?true:false; +} + +void sq_addref(HSQUIRRELVM v,HSQOBJECT *po) +{ + SQObjectPtr refs; + if(!ISREFCOUNTED(type(*po))) return; + if(_table(_ss(v)->_refs_table)->Get(*po, refs)) { + refs = _integer(refs) + 1; + } + else{ + refs = 1; + } + _table(_ss(v)->_refs_table)->NewSlot(*po, refs); +} + +SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po) +{ + SQObjectPtr refs; + if(!ISREFCOUNTED(type(*po))) return SQTrue; + if(_table(_ss(v)->_refs_table)->Get(*po, refs)) { + int n = _integer(refs) - 1; + if(n <= 0) { + _table(_ss(v)->_refs_table)->Remove(*po); + sq_resetobject(po); + } + else { + refs = n;_table(_ss(v)->_refs_table)->Set(*po, refs); + return SQFalse; + } + } + return SQTrue; +} + +const SQChar *sq_objtostring(HSQOBJECT *o) +{ + if(sq_type(*o) == OT_STRING) { + return o->_unVal.pString->_val; + } + return NULL; +} + +SQInteger sq_objtointeger(HSQOBJECT *o) +{ + if(sq_isnumeric(*o)) { + return tointeger(*o); + } + return 0; +} + +SQFloat sq_objtofloat(HSQOBJECT *o) +{ + if(sq_isnumeric(*o)) { + return tofloat(*o); + } + return 0; +} + +void sq_pushnull(HSQUIRRELVM v) +{ + v->Push(_null_); +} + +void sq_pushstring(HSQUIRRELVM v,const SQChar *s,int len) +{ + if(s) + v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len))); + else v->Push(_null_); +} + +void sq_pushinteger(HSQUIRRELVM v,SQInteger n) +{ + v->Push(n); +} + +void sq_pushbool(HSQUIRRELVM v,SQBool b) +{ + v->Push(b?true:false); +} + +void sq_pushfloat(HSQUIRRELVM v,SQFloat n) +{ + v->Push(n); +} + +void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p) +{ + v->Push(p); +} + +SQUserPointer sq_newuserdata(HSQUIRRELVM v,unsigned int size) +{ + SQUserData *ud = SQUserData::Create(_ss(v), size); + v->Push(ud); + return ud->_val; +} + +void sq_newtable(HSQUIRRELVM v) +{ + v->Push(SQTable::Create(_ss(v), 0)); +} + +void sq_newarray(HSQUIRRELVM v,int size) +{ + v->Push(SQArray::Create(_ss(v), size)); +} + +SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase) +{ + SQClass *baseclass = NULL; + if(hasbase) { + SQObjectPtr &base = stack_get(v,-1); + if(type(base) != OT_CLASS) + return sq_throwerror(v,_SC("invalid base type")); + baseclass = _class(base); + } + SQClass *newclass = SQClass::Create(_ss(v), baseclass); + if(baseclass) v->Pop(); + v->Push(newclass); + return SQ_OK; +} + +int sq_instanceof(HSQUIRRELVM v) +{ + SQObjectPtr &inst = stack_get(v,-1); + SQObjectPtr &cl = stack_get(v,-2); + if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS) + return sq_throwerror(v,_SC("invalid param type")); + return _instance(inst)->InstanceOf(_class(cl))?1:0; +} + +SQRESULT sq_arrayappend(HSQUIRRELVM v,int idx) +{ + sq_aux_paramscheck(v,2); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + _array(*arr)->Append(v->GetUp(-1)); + v->Pop(1); + return SQ_OK; +} + +SQRESULT sq_arraypop(HSQUIRRELVM v,int idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + if(_array(*arr)->Size() > 0) { + if(pushval != 0){ v->Push(_array(*arr)->Top()); } + _array(*arr)->Pop(); + return SQ_OK; + } + return sq_throwerror(v, _SC("empty array")); +} + +SQRESULT sq_arrayresize(HSQUIRRELVM v,int idx,int newsize) +{ + sq_aux_paramscheck(v,1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + if(_array(*arr)->Size() > 0) { + _array(*arr)->Resize(newsize); + return SQ_OK; + } + return sq_throwerror(v, _SC("empty array")); +} + +SQRESULT sq_arrayreverse(HSQUIRRELVM v,int idx) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *o; + _GETSAFE_OBJ(v, idx, OT_ARRAY,o); + SQArray *arr = _array(*o); + if(arr->Size() > 0) { + SQObjectPtr t; + int size = arr->Size(); + int n = size >> 1; size -= 1; + for(int i = 0; i < n; i++) { + t = arr->_values[i]; + arr->_values[i] = arr->_values[size-i]; + arr->_values[size-i] = t; + } + return SQ_OK; + } + return sq_throwerror(v, _SC("empty array")); +} + +void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,unsigned int nfreevars) +{ + SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func); + nc->_nparamscheck = 0; + for(unsigned int i = 0; i < nfreevars; i++) { + nc->_outervalues.push_back(v->Top()); + v->Pop(); + } + v->Push(SQObjectPtr(nc)); +} + +SQRESULT sq_getclosureinfo(HSQUIRRELVM v,int idx,unsigned int *nparams,unsigned int *nfreevars) +{ + SQObject o = stack_get(v, idx); + if(sq_isclosure(o)) { + SQClosure *c = _closure(o); + SQFunctionProto *proto = _funcproto(c->_function); + *nparams = (unsigned int)proto->_parameters.size(); + *nfreevars = (unsigned int)c->_outervalues.size(); + return SQ_OK; + } + return sq_throwerror(v,_SC("the object is not a closure")); +} + +SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,int idx,const SQChar *name) +{ + SQObject o = stack_get(v, idx); + if(sq_isnativeclosure(o)) { + SQNativeClosure *nc = _nativeclosure(o); + nc->_name = SQString::Create(_ss(v),name); + return SQ_OK; + } + return sq_throwerror(v,_SC("the object is not a nativeclosure")); +} + +SQRESULT sq_setparamscheck(HSQUIRRELVM v,int nparamscheck,const SQChar *typemask) +{ + SQObject o = stack_get(v, -1); + if(!sq_isnativeclosure(o)) + return sq_throwerror(v, _SC("native closure expected")); + SQNativeClosure *nc = _nativeclosure(o); + nc->_nparamscheck = nparamscheck; + if(typemask) { + SQIntVec res; + if(!CompileTypemask(res, typemask)) + return sq_throwerror(v, _SC("invalid typemask")); + nc->_typecheck.copy(res); + } + else { + nc->_typecheck.resize(0); + } + return SQ_OK; +} + +void sq_pushroottable(HSQUIRRELVM v) +{ + v->Push(v->_roottable); +} + +void sq_pushregistrytable(HSQUIRRELVM v) +{ + v->Push(_ss(v)->_registry); +} + +SQRESULT sq_setroottable(HSQUIRRELVM v) +{ + SQObject o = stack_get(v, -1); + if(sq_istable(o) || sq_isnull(o)) { + v->_roottable = o; + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v, _SC("ivalid type")); +} + +void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p) +{ + v->_foreignptr = p; +} + +SQUserPointer sq_getforeignptr(HSQUIRRELVM v) +{ + return v->_foreignptr; +} + +void sq_push(HSQUIRRELVM v,int idx) +{ + v->Push(stack_get(v, idx)); +} + +SQObjectType sq_gettype(HSQUIRRELVM v,int idx) +{ + return type(stack_get(v, idx)); +} + +SQRESULT sq_getinteger(HSQUIRRELVM v,int idx,SQInteger *i) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isnumeric(o)) { + *i = tointeger(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getfloat(HSQUIRRELVM v,int idx,SQFloat *f) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isnumeric(o)) { + *f = tofloat(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getbool(HSQUIRRELVM v,int idx,SQBool *b) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isbool(o)) { + *b = _integer(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getstring(HSQUIRRELVM v,int idx,const SQChar **c) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_STRING,o); + *c = _stringval(*o); + return SQ_OK; +} + +SQRESULT sq_getthread(HSQUIRRELVM v,int idx,HSQUIRRELVM *thread) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_THREAD,o); + *thread = _thread(*o); + return SQ_OK; +} + +SQRESULT sq_clone(HSQUIRRELVM v,int idx) +{ + SQObjectPtr &o = stack_get(v,idx); + v->Push(_null_); + if(!v->Clone(o, stack_get(v, -1))){ + v->Pop(); + return sq_aux_invalidtype(v, type(o)); + } + return SQ_OK; +} + +SQInteger sq_getsize(HSQUIRRELVM v, int idx) +{ + SQObjectPtr &o = stack_get(v, idx); + SQObjectType type = type(o); + switch(type) { + case OT_STRING: return _string(o)->_len; + case OT_TABLE: return _table(o)->CountUsed(); + case OT_ARRAY: return _array(o)->Size(); + case OT_USERDATA: return _userdata(o)->_size; + default: + return sq_aux_invalidtype(v, type); + } +} + +SQRESULT sq_getuserdata(HSQUIRRELVM v,int idx,SQUserPointer *p,unsigned int *typetag) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_USERDATA,o); + (*p) = _userdataval(*o); + if(typetag) *typetag = _userdata(*o)->_typetag; + return SQ_OK; +} + +SQRESULT sq_settypetag(HSQUIRRELVM v,int idx,unsigned int typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + switch(type(o)) { + case OT_USERDATA: _userdata(o)->_typetag = typetag; break; + case OT_CLASS: _class(o)->_typetag = typetag; break; + default: return sq_throwerror(v,_SC("invalid object type")); + } + return SQ_OK; +} + +SQRESULT sq_gettypetag(HSQUIRRELVM v,int idx,unsigned int *typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + switch(type(o)) { + case OT_USERDATA: *typetag = _userdata(o)->_typetag; break; + case OT_CLASS: *typetag = _class(o)->_typetag; break; + default: return sq_throwerror(v,_SC("invalid object type")); + } + return SQ_OK; +} + +SQRESULT sq_getuserpointer(HSQUIRRELVM v, int idx, SQUserPointer *p) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o); + (*p) = _userpointer(*o); + return SQ_OK; +} + +SQRESULT sq_setinstanceup(HSQUIRRELVM v, int idx, SQUserPointer p) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance")); + _instance(o)->_userpointer = p; + return SQ_OK; +} + +SQRESULT sq_getinstanceup(HSQUIRRELVM v, int idx, SQUserPointer *p,unsigned int typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance")); + (*p) = _instance(o)->_userpointer; + if(typetag != 0) { + SQClass *cl = _instance(o)->_class; + do{ + if(cl->_typetag == typetag) + return SQ_OK; + cl = cl->_base; + }while(cl != NULL); + return sq_throwerror(v,_SC("invalid type tag")); + } + return SQ_OK; +} + +int sq_gettop(HSQUIRRELVM v) +{ + return (v->_top) - v->_stackbase; +} + +void sq_settop(HSQUIRRELVM v, int newtop) +{ + int top = sq_gettop(v); + if(top > newtop) + sq_pop(v, top - newtop); + else + while(top < newtop) sq_pushnull(v); +} + +void sq_pop(HSQUIRRELVM v, int nelemstopop) +{ + assert(v->_top >= nelemstopop); + v->Pop(nelemstopop); +} + +void sq_remove(HSQUIRRELVM v, int idx) +{ + v->Remove(idx); +} + +int sq_cmp(HSQUIRRELVM v) +{ + int res; + v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res); + return res; +} + +SQRESULT sq_createslot(HSQUIRRELVM v, int idx) +{ + sq_aux_paramscheck(v, 3); + SQObjectPtr &self = stack_get(v, idx); + if(type(self) == OT_TABLE || type(self) == OT_CLASS) { + SQObjectPtr &key = v->GetUp(-2); + if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); + v->NewSlot(self, key, v->GetUp(-1)); + v->Pop(2); + } + return SQ_OK; +} + +SQRESULT sq_deleteslot(HSQUIRRELVM v,int idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 2); + SQObjectPtr *self; + _GETSAFE_OBJ(v, idx, OT_TABLE,self); + SQObjectPtr &key = v->GetUp(-1); + if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); + SQObjectPtr res; + if(!v->DeleteSlot(*self, key, res)){ + return SQ_ERROR; + } + if(pushval) v->GetUp(-1) = res; + else v->Pop(1); + return SQ_OK; +} + +SQRESULT sq_set(HSQUIRRELVM v,int idx) +{ + SQObjectPtr &self = stack_get(v, idx); + if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { + v->Pop(2); + return SQ_OK; + } + v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; +} + +SQRESULT sq_rawset(HSQUIRRELVM v,int idx) +{ + SQObjectPtr &self = stack_get(v, idx); + if(type(v->GetUp(-2)) == OT_NULL) return sq_throwerror(v, _SC("null key")); + switch(type(self)) { + case OT_TABLE: + _table(self)->NewSlot(v->GetUp(-2), v->GetUp(-1)); + v->Pop(2); + return SQ_OK; + break; + case OT_CLASS: + _class(self)->NewSlot(v->GetUp(-2), v->GetUp(-1)); + v->Pop(2); + return SQ_OK; + break; + case OT_INSTANCE: + if(_instance(self)->Set(v->GetUp(-2), v->GetUp(-1))) { + v->Pop(2); + return SQ_OK; + } + break; + case OT_ARRAY: + if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { + v->Pop(2); + return SQ_OK; + } + break; + default: + v->Pop(2); + return sq_throwerror(v, _SC("rawset works only on arrays,tables,calsses and instances")); + } + v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; +} + +SQRESULT sq_setdelegate(HSQUIRRELVM v,int idx) +{ + SQObjectPtr &self = stack_get(v, idx); + SQObjectPtr &mt = v->GetUp(-1); + SQObjectType type = type(self); + switch(type) { + case OT_TABLE: + if(type(mt) == OT_TABLE) { + if(!_table(self)->SetDelegate(_table(mt))) return sq_throwerror(v, _SC("delagate cycle")); v->Pop();} + else if(type(mt)==OT_NULL) { + _table(self)->SetDelegate(NULL); v->Pop(); } + else return sq_aux_invalidtype(v,type); + break; + case OT_USERDATA: + if(type(mt)==OT_TABLE) { + _userdata(self)->SetDelegate(_table(mt)); v->Pop(); } + else if(type(mt)==OT_NULL) { + _userdata(self)->SetDelegate(NULL); v->Pop(); } + else return sq_aux_invalidtype(v, type); + break; + default: + return sq_aux_invalidtype(v, type); + break; + } + return SQ_OK; +} + +SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,int idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 2); + SQObjectPtr *self; + _GETSAFE_OBJ(v, idx, OT_TABLE,self); + SQObjectPtr &key = v->GetUp(-1); + SQObjectPtr t; + if(_table(*self)->Get(key,t)) { + _table(*self)->Remove(key); + } + if(pushval != 0) + if(pushval) v->GetUp(-1) = t; + else + v->Pop(1); + return SQ_OK; +} + +SQRESULT sq_getdelegate(HSQUIRRELVM v,int idx) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)){ + case OT_TABLE: + if(!_table(self)->_delegate)break; + v->Push(SQObjectPtr(_table(self)->_delegate)); + return SQ_OK; + break; + case OT_USERDATA: + if(!_userdata(self)->_delegate)break; + v->Push(SQObjectPtr(_userdata(self)->_delegate)); + return SQ_OK; + break; + } + return sq_throwerror(v,_SC("wrong type")); +} + +SQRESULT sq_get(HSQUIRRELVM v,int idx) +{ + SQObjectPtr &self=stack_get(v,idx); + if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false)) + return SQ_OK; + v->Pop(1); + return sq_throwerror(v,_SC("the index doesn't exist")); +} + +SQRESULT sq_rawget(HSQUIRRELVM v,int idx) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)) { + case OT_TABLE: + if(_table(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_CLASS: + if(_class(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_INSTANCE: + if(_instance(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_ARRAY: + if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false)) + return SQ_OK; + break; + default: + v->Pop(1); + return sq_throwerror(v,_SC("rawget works only on arrays and tables")); + } + v->Pop(1); + return sq_throwerror(v,_SC("the index doesn't exist")); +} + +SQRESULT sq_getstackobj(HSQUIRRELVM v,int idx,HSQOBJECT *po) +{ + *po=stack_get(v,idx); + return SQ_OK; +} + +const SQChar *sq_getlocal(HSQUIRRELVM v,unsigned int level,unsigned int idx) +{ + unsigned int cstksize=v->_callsstack.size(); + unsigned int lvl=(cstksize-level)-1; + int stackbase=v->_stackbase; + if(lvl_callsstack[(cstksize-i)-1]; + stackbase-=ci._prevstkbase; + } + SQVM::CallInfo &ci=v->_callsstack[lvl]; + if(type(ci._closure)!=OT_CLOSURE) + return NULL; + SQClosure *c=_closure(ci._closure); + SQFunctionProto *func=_funcproto(c->_function); + return func->GetLocal(v,stackbase,idx,(ci._ip-func->_instructions._vals)-1); + } + return NULL; +} + +void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj) +{ + v->Push(SQObjectPtr(obj)); +} + +void sq_resetobject(HSQOBJECT *po) +{ + po->_unVal.pUserPointer=NULL;po->_type=OT_NULL; +} + +SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err) +{ + v->_lasterror=SQString::Create(_ss(v),err); + return -1; +} + +void sq_reseterror(HSQUIRRELVM v) +{ + v->_lasterror = _null_; +} + +void sq_getlasterror(HSQUIRRELVM v) +{ + v->Push(v->_lasterror); +} + +void sq_reservestack(HSQUIRRELVM v,int nsize) +{ + if (((unsigned int)v->_top + nsize) > v->_stack.size()) { + v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size())); + } +} + +SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval) +{ + if(type(v->GetUp(-1))==OT_GENERATOR){ + v->Push(_null_); //retval + if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),SQVM::ET_RESUME_GENERATOR)) + {v->Raise_Error(v->_lasterror); return SQ_ERROR;} + if(!retval) + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v,_SC("only generators can be resumed")); +} + +SQRESULT sq_call(HSQUIRRELVM v,int params,SQBool retval) +{ + SQObjectPtr res; + if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res)){ + v->Pop(params);//pop closure and args + if(retval){ + v->Push(res); return SQ_OK; + } + return SQ_OK; + } + else { + v->Pop(params); + return SQ_ERROR; + } + if(!v->_suspended) + v->Pop(params); + return sq_throwerror(v,_SC("call failed")); +} + +SQRESULT sq_suspendvm(HSQUIRRELVM v) +{ + return v->Suspend(); +} + +SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval) +{ + SQObjectPtr ret; + if(!v->_suspended) + return sq_throwerror(v,_SC("cannot resume a vm that is not running any code")); + if(wakeupret) { + v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval + v->Pop(); + } else v->GetAt(v->_stackbase+v->_suspended_target)=_null_; + if(!v->Execute(_null_,v->_top,-1,-1,ret,SQVM::ET_RESUME_VM)) + return SQ_ERROR; + if(sq_getvmstate(v) == SQ_VMSTATE_IDLE) { + while (v->_top > 1) v->_stack[--v->_top] = _null_; + } + if(retval) + v->Push(ret); + return SQ_OK; +} + +void sq_setreleasehook(HSQUIRRELVM v,int idx,SQRELEASEHOOK hook) +{ + if(sq_gettop(v) >= 1){ + SQObjectPtr &ud=stack_get(v,idx); + switch( type(ud) ) { + case OT_USERDATA: + _userdata(ud)->_hook = hook; + break; + case OT_INSTANCE: + _instance(ud)->_hook = hook; + break; + } + } +} + +void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f) +{ + _ss(v)->_compilererrorhandler = f; +} + +SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, -1, OT_CLOSURE,o); + SQClosure *c=_closure(*o); + unsigned short tag = SQ_BYTECODE_STREAM_TAG; + if(w(up,&tag,2) != 2) + return sq_throwerror(v,_SC("io error")); + if(!_closure(*o)->Save(v,up,w)) + return SQ_ERROR; + return SQ_OK; +} + +SQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up) +{ + SQObjectPtr func=SQFunctionProto::Create(); + SQObjectPtr closure=SQClosure::Create(_ss(v),_funcproto(func)); + unsigned short tag; + if(r(up,&tag,2) != 2) + return sq_throwerror(v,_SC("io error")); + if(tag != SQ_BYTECODE_STREAM_TAG) + return sq_throwerror(v,_SC("invalid stream")); + if(!_closure(closure)->Load(v,up,r)) + return SQ_ERROR; + v->Push(closure); + return SQ_OK; +} + +SQChar *sq_getscratchpad(HSQUIRRELVM v,int minsize) +{ + return _ss(v)->GetScratchPad(minsize); +} + +int sq_collectgarbage(HSQUIRRELVM v) +{ +#ifndef NO_GARBAGE_COLLECTOR + return _ss(v)->CollectGarbage(v); +#else + return -1; +#endif +} + +SQRESULT sq_setfreevariable(HSQUIRRELVM v,int idx,unsigned int nval) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)) + { + case OT_CLOSURE: + if(_closure(self)->_outervalues.size()>nval){ + _closure(self)->_outervalues[nval]=stack_get(v,-1); + } + else return sq_throwerror(v,_SC("invalid free var index")); + break; + case OT_NATIVECLOSURE: + if(_nativeclosure(self)->_outervalues.size()>nval){ + _nativeclosure(self)->_outervalues[nval]=stack_get(v,-1); + } + else return sq_throwerror(v,_SC("invalid free var index")); + break; + default: + return sq_aux_invalidtype(v,type(self)); + } + v->Pop(1); + return SQ_OK; +} + +SQRESULT sq_setattributes(HSQUIRRELVM v,int idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + SQObjectPtr &key = stack_get(v,-2); + SQObjectPtr &val = stack_get(v,-1); + SQObjectPtr attrs; + if(type(key) == OT_NULL) { + attrs = _class(*o)->_attributes; + _class(*o)->_attributes = val; + v->Pop(2); + v->Push(attrs); + return SQ_OK; + }else if(_class(*o)->GetAttributes(key,attrs)) { + _class(*o)->SetAttributes(key,val); + v->Pop(2); + v->Push(attrs); + return SQ_OK; + } + return sq_throwerror(v,_SC("wrong index")); +} + +SQRESULT sq_getattributes(HSQUIRRELVM v,int idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + SQObjectPtr &key = stack_get(v,-1); + SQObjectPtr attrs; + if(type(key) == OT_NULL) { + attrs = _class(*o)->_attributes; + v->Pop(); + v->Push(attrs); + return SQ_OK; + } + else if(_class(*o)->GetAttributes(key,attrs)) { + v->Pop(); + v->Push(attrs); + return SQ_OK; + } + return sq_throwerror(v,_SC("wrong index")); +} + +SQRESULT sq_getclass(HSQUIRRELVM v,int idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_INSTANCE,o); + v->Push(SQObjectPtr(_instance(*o)->_class)); + return SQ_OK; +} + +SQRESULT sq_createinstance(HSQUIRRELVM v,int idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + v->Push(_class(*o)->CreateInstance()); + return SQ_OK; +} + +SQRESULT sq_next(HSQUIRRELVM v,int idx) +{ + SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val; + if(type(o) == OT_GENERATOR) { + return sq_throwerror(v,_SC("cannot iterate a generator")); + } + bool finished; + if(!v->FOREACH_OP(o,realkey,val,refpos,0,finished)) + return SQ_ERROR; + if(!finished) { + v->Push(realkey); + v->Push(val); + return SQ_OK; + } + return SQ_ERROR; +} + +struct BufState{ + const SQChar *buf; + int ptr; + int size; +}; + +SQInteger buf_lexfeed(SQUserPointer file) +{ + BufState *buf=(BufState*)file; + if(buf->size<(buf->ptr+1)) + return 0; + return buf->buf[buf->ptr++]; +} + +SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,int size,const SQChar *sourcename,SQBool raiseerror) { + BufState buf; + buf.buf = s; + buf.size = size; + buf.ptr = 0; + return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror); +} + +void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,int idx) +{ + dest->Push(stack_get(src,idx)); +} + +void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc) +{ + _ss(v)->_printfunc = printfunc; +} + +SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v) +{ + return _ss(v)->_printfunc; +} + +void *sq_malloc(unsigned int size) +{ + return SQ_MALLOC(size); +} + +void *sq_realloc(void* p,unsigned int oldsize,unsigned int newsize) +{ + return SQ_REALLOC(p,oldsize,newsize); +} +void sq_free(void *p,unsigned int size) +{ + SQ_FREE(p,size); +} diff --git a/src/squirrel/squirrel/sqarray.h b/src/squirrel/squirrel/sqarray.h new file mode 100644 index 000000000..b747e07f5 --- /dev/null +++ b/src/squirrel/squirrel/sqarray.h @@ -0,0 +1,77 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQARRAY_H_ +#define _SQARRAY_H_ + +struct SQArray : public CHAINABLE_OBJ +{ +private: + SQArray(SQSharedState *ss,int nsize){_values.resize(nsize);_uiRef=0;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} + ~SQArray() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } +public: + static SQArray* Create(SQSharedState *ss,int nInitialSize){ + SQArray *newarray=(SQArray*)SQ_MALLOC(sizeof(SQArray)); + new (newarray) SQArray(ss,nInitialSize); + return newarray; + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + void Finalize(){ + _values.resize(0); + } + bool Get(const int nidx,SQObjectPtr &val) + { + if(nidx>=0 && nidx<(int)_values.size()){ + val=_values[nidx]; + return true; + } + else return false; + } + bool Set(const int nidx,const SQObjectPtr &val) + { + if(nidx>=0 && nidx<(int)_values.size()){ + _values[nidx]=val; + return true; + } + else return false; + } + int Next(const SQObjectPtr &refpos,SQObjectPtr &outkey,SQObjectPtr &outval) + { + unsigned int idx=TranslateIndex(refpos); + while(idx<_values.size()){ + //first found + outkey=(SQInteger)idx; + outval=_values[idx]; + //return idx for the next iteration + return ++idx; + } + //nothing to iterate anymore + return -1; + } + SQArray *Clone(){SQArray *anew=Create(_opt_ss(this),Size()); anew->_values.copy(_values); return anew; } + int Size() const {return _values.size();} + void Resize(int size,SQObjectPtr &fill = _null_) { _values.resize(size,fill); ShrinkIfNeeded(); } + void Reserve(int size) { _values.reserve(size); } + void Append(const SQObject &o){_values.push_back(o);} + void Extend(const SQArray *a); + SQObjectPtr &Top(){return _values.top();} + void Pop(){_values.pop_back(); ShrinkIfNeeded(); } + void Insert(const SQObject& idx,const SQObject &val){_values.insert((unsigned int)tointeger(idx),val);} + void ShrinkIfNeeded() { + if(_values.size() <= _values.capacity()>>2) //shrink the array + _values.shrinktofit(); + } + void Remove(unsigned int idx){ + _values.remove(idx); + ShrinkIfNeeded(); + } + void Release() + { + sq_delete(this,SQArray); + } + SQObjectPtrVec _values; +}; +#endif //_SQARRAY_H_ diff --git a/src/squirrel/squirrel/sqbaselib.cpp b/src/squirrel/squirrel/sqbaselib.cpp new file mode 100644 index 000000000..c22f793b1 --- /dev/null +++ b/src/squirrel/squirrel/sqbaselib.cpp @@ -0,0 +1,781 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqclass.h" +#include +#include +#include + +bool str2num(const SQChar *s,SQObjectPtr &res) +{ + SQChar *end; + if(scstrstr(s,_SC("."))){ + SQFloat r = SQFloat(scstrtod(s,&end)); + if(s == end) return false; + while (scisspace((*end)) ) end++; + if (*end != _SC('\0')) return false; + res = r; + return true; + } + else{ + const SQChar *t = s; + while(*t != _SC('\0')) if(!scisdigit(*t++)) return false; + res = SQInteger(scatoi(s)); + return true; + } +} + +#ifndef NO_GARBAGE_COLLECTOR +static int base_collectgarbage(HSQUIRRELVM v) +{ + sq_pushinteger(v, sq_collectgarbage(v)); + return 1; +} +#endif + +static int base_getroottable(HSQUIRRELVM v) +{ + v->Push(v->_roottable); + return 1; +} + +static int base_setroottable(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,2); + if(SQ_FAILED(sq_setroottable(v))) return SQ_ERROR; + v->Push(o); + return 1; +} + +static int base_seterrorhandler(HSQUIRRELVM v) +{ + sq_seterrorhandler(v); + return 0; +} + +static int base_setdebughook(HSQUIRRELVM v) +{ + sq_setdebughook(v); + return 0; +} + +static int base_enabledebuginfo(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,2); + sq_enabledebuginfo(v,(type(o) != OT_NULL)?1:0); + return 0; +} + +static int base_getstackinfos(HSQUIRRELVM v) +{ + SQInteger level; + SQStackInfos si; + int seq = 0; + const SQChar *name = NULL; + sq_getinteger(v, -1, &level); + if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si))) + { + const SQChar *fn = _SC("unknown"); + const SQChar *src = _SC("unknown"); + if(si.funcname)fn = si.funcname; + if(si.source)src = si.source; + sq_newtable(v); + sq_pushstring(v, _SC("func"), -1); + sq_pushstring(v, fn, -1); + sq_createslot(v, -3); + sq_pushstring(v, _SC("src"), -1); + sq_pushstring(v, src, -1); + sq_createslot(v, -3); + sq_pushstring(v, _SC("line"), -1); + sq_pushinteger(v, si.line); + sq_createslot(v, -3); + sq_pushstring(v, _SC("locals"), -1); + sq_newtable(v); + seq=0; + while (name = sq_getlocal(v, level, seq)) { + sq_pushstring(v, name, -1); + sq_push(v, -2); + sq_createslot(v, -4); + sq_pop(v, 1); + seq++; + } + sq_createslot(v, -3); + return 1; + } + + return 0; +} + +static int base_assert(HSQUIRRELVM v) +{ + if(v->IsFalse(stack_get(v,2))){ + return sq_throwerror(v,_SC("assertion failed")); + } + return 0; +} + +static int get_slice_params(HSQUIRRELVM v,int &sidx,int &eidx,SQObjectPtr &o) +{ + int top = sq_gettop(v); + sidx=0; + eidx=0; + o=stack_get(v,1); + SQObjectPtr &start=stack_get(v,2); + if(type(start)!=OT_NULL && sq_isnumeric(start)){ + sidx=tointeger(start); + } + if(top>2){ + SQObjectPtr &end=stack_get(v,3); + if(sq_isnumeric(end)){ + eidx=tointeger(end); + } + } + else { + eidx = sq_getsize(v,1); + } + return 1; +} + +static int base_print(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,2); + switch(type(o)){ + case OT_STRING: + if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("%s"),_stringval(o)); + break; + case OT_INTEGER: + if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("%d"),_integer(o)); + break; + case OT_FLOAT: + if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("%.14g"),_float(o)); + break; + default:{ + SQObjectPtr tname; + v->TypeOf(o,tname); + if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("(%s)"),_stringval(tname)); + } + break; + } + return 0; +} + +static int base_compilestring(HSQUIRRELVM v) +{ + int nargs=sq_gettop(v); + const SQChar *src=NULL,*name=_SC("unnamedbuffer"); + SQInteger size; + sq_getstring(v,2,&src); + size=sq_getsize(v,2); + if(nargs>2){ + sq_getstring(v,3,&name); + } + if(SQ_SUCCEEDED(sq_compilebuffer(v,src,size,name,SQFalse))) + return 1; + else + return SQ_ERROR; +} + +static int base_newthread(HSQUIRRELVM v) +{ + SQObjectPtr &func = stack_get(v,2); + int stksize = (_funcproto(_closure(func)->_function)->_stacksize << 1) +2; + HSQUIRRELVM newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize); + sq_move(newv,v,-2); + return 1; +} + +static int base_suspend(HSQUIRRELVM v) +{ + return sq_suspendvm(v); +} + +static int base_array(HSQUIRRELVM v) +{ + SQArray *a; + SQObject &size = stack_get(v,2); + if(sq_gettop(v) > 2) { + a = SQArray::Create(_ss(v),0); + a->Resize(tointeger(size),stack_get(v,3)); + } + else { + a = SQArray::Create(_ss(v),tointeger(size)); + } + v->Push(a); + return 1; +} + +static int base_type(HSQUIRRELVM v) +{ + SQObjectPtr &o = stack_get(v,2); + v->Push(SQString::Create(_ss(v),GetTypeName(o),-1)); + return 1; +} + +static SQRegFunction base_funcs[]={ + //generic + {_SC("seterrorhandler"),base_seterrorhandler,2, NULL}, + {_SC("setdebughook"),base_setdebughook,2, NULL}, + {_SC("enabledebuginfo"),base_enabledebuginfo,2, NULL}, + {_SC("getstackinfos"),base_getstackinfos,2, _SC(".n")}, + {_SC("getroottable"),base_getroottable,1, NULL}, + {_SC("setroottable"),base_setroottable,2, NULL}, + {_SC("assert"),base_assert,2, NULL}, + {_SC("print"),base_print,2, NULL}, + {_SC("compilestring"),base_compilestring,-2, _SC(".ss")}, + {_SC("newthread"),base_newthread,2, _SC(".c")}, + {_SC("suspend"),base_suspend,-1, NULL}, + {_SC("array"),base_array,-2, _SC(".n")}, + {_SC("type"),base_type,2, NULL}, +#ifndef NO_GARBAGE_COLLECTOR + {_SC("collectgarbage"),base_collectgarbage,1, _SC("t")}, +#endif + {0,0} +}; + +void sq_base_register(HSQUIRRELVM v) +{ + int i=0; + sq_pushroottable(v); + while(base_funcs[i].name!=0) { + sq_pushstring(v,base_funcs[i].name,-1); + sq_newclosure(v,base_funcs[i].f,0); + sq_setnativeclosurename(v,-1,base_funcs[i].name); + sq_setparamscheck(v,base_funcs[i].nparamscheck,base_funcs[i].typemask); + sq_createslot(v,-3); + i++; + } + sq_pushstring(v,_SC("_charsize_"),-1); + sq_pushinteger(v,sizeof(SQChar)); + sq_createslot(v,-3); + sq_pop(v,1); +} + +static int default_delegate_len(HSQUIRRELVM v) +{ + v->Push(SQInteger(sq_getsize(v,1))); + return 1; +} + +static int default_delegate_tofloat(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,1); + switch(type(o)){ + case OT_STRING:{ + SQObjectPtr res; + if(str2num(_stringval(o),res)){ + v->Push(SQObjectPtr(tofloat(res))); + break; + }} + case OT_INTEGER:case OT_FLOAT: + v->Push(SQObjectPtr(tofloat(o))); + break; + case OT_BOOL: + v->Push(SQObjectPtr((SQFloat)(_integer(o)?1:0))); + break; + default: + v->Push(_null_); + break; + } + return 1; +} + +static int default_delegate_tointeger(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,1); + switch(type(o)){ + case OT_STRING:{ + SQObjectPtr res; + if(str2num(_stringval(o),res)){ + v->Push(SQObjectPtr(tointeger(res))); + break; + }} + case OT_INTEGER:case OT_FLOAT: + v->Push(SQObjectPtr(tointeger(o))); + break; + case OT_BOOL: + v->Push(SQObjectPtr(_integer(o)?1:0)); + break; + default: + v->Push(_null_); + break; + } + return 1; +} + +static int default_delegate_tostring(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,1); + switch(type(o)){ + case OT_STRING: + v->Push(o); + break; + case OT_INTEGER: + scsprintf(_ss(v)->GetScratchPad(rsl(NUMBER_MAX_CHAR+1)),_SC("%d"),_integer(o)); + v->Push(SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1))); + break; + case OT_FLOAT: + scsprintf(_ss(v)->GetScratchPad(rsl(NUMBER_MAX_CHAR+1)),_SC("%.14g"),_float(o)); + v->Push(SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1))); + break; + case OT_BOOL: + v->Push(SQObjectPtr(SQString::Create(_ss(v),_integer(o)?_SC("true"):_SC("false")))); + break; + default: + v->Push(_null_); + break; + } + return 1; +} + +static int number_delegate_tochar(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + SQChar c=tointeger(o); + v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1)); + return 1; +} + + +///////////////////////////////////////////////////////////////// +//TABLE DEFAULT DELEGATE + +static int table_rawdelete(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_rawdeleteslot(v,1,SQTrue))) + return SQ_ERROR; + return 1; +} + + +static int container_rawexists(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_rawget(v,-2))) { + sq_pushbool(v,SQTrue); + return 1; + } + sq_pushbool(v,SQFalse); + return 1; +} + +static int table_rawset(HSQUIRRELVM v) +{ + return sq_rawset(v,-3); +} + + +static int table_rawget(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR; +} + +SQRegFunction SQSharedState::_table_default_delegate_funcz[]={ + {_SC("len"),default_delegate_len,1, _SC("t")}, + {_SC("rawget"),table_rawget,2, _SC("t")}, + {_SC("rawset"),table_rawset,3, _SC("t")}, + {_SC("rawdelete"),table_rawdelete,2, _SC("t")}, + {_SC("rawin"),container_rawexists,2, _SC("t")}, + {0,0} +}; + +//ARRAY DEFAULT DELEGATE/////////////////////////////////////// + +static int array_append(HSQUIRRELVM v) +{ + return sq_arrayappend(v,-2); +} + +static int array_extend(HSQUIRRELVM v) +{ + _array(stack_get(v,1))->Extend(_array(stack_get(v,2))); + return 0; +} + +static int array_reverse(HSQUIRRELVM v) +{ + return sq_arrayreverse(v,-1); +} + +static int array_pop(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR; +} + +static int array_top(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + if(_array(o)->Size()>0){ + v->Push(_array(o)->Top()); + return 1; + } + else return sq_throwerror(v,_SC("top() on a empty array")); +} + +static int array_insert(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + SQObject &idx=stack_get(v,2); + SQObject &val=stack_get(v,3); + _array(o)->Insert(idx,val); + return 0; +} + +static int array_remove(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v, 1); + SQObject &idx = stack_get(v, 2); + if(!sq_isnumeric(idx)) return sq_throwerror(v, _SC("wrong type")); + SQObjectPtr val; + if(_array(o)->Get(tointeger(idx), val)) { + _array(o)->Remove(tointeger(idx)); + v->Push(val); + return 1; + } + return sq_throwerror(v, _SC("idx out of range")); +} + +static int array_resize(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v, 1); + SQObject &nsize = stack_get(v, 2); + SQObjectPtr fill; + if(sq_isnumeric(nsize)) { + if(sq_gettop(v) > 2) + fill = stack_get(v, 3); + _array(o)->Resize(tointeger(nsize),fill); + return 0; + } + return sq_throwerror(v, _SC("size must be a number")); +} + + +//QSORT ala Sedgewick +bool _qsort_compare(HSQUIRRELVM v,SQObjectPtr &arr,SQObjectPtr &a,SQObjectPtr &b,int func,int &ret) +{ + if(func < 0) { + if(!v->ObjCmp(a,b,ret)) return false; + } + else { + int top = sq_gettop(v); + sq_push(v, func); + sq_pushroottable(v); + v->Push(a); + v->Push(b); + if(SQ_FAILED(sq_call(v, 3, SQTrue))) { + v->Raise_Error(_SC("compare func failed")); + return false; + } + sq_getinteger(v, -1, &ret); + sq_settop(v, top); + return true; + } + return true; +} +//QSORT ala Sedgewick +bool _qsort(HSQUIRRELVM v,SQObjectPtr &arr, int l, int r,int func) +{ + int i, j; + SQArray *a=_array(arr); + SQObjectPtr pivot,t; + if( l < r ){ + pivot = a->_values[l]; + i = l; j = r+1; + while(1){ + int ret; + do { + ++i; + if(i > r) break; + if(!_qsort_compare(v,arr,a->_values[i],pivot,func,ret)) + return false; + } while( ret <= 0); + do { + --j; + if(!_qsort_compare(v,arr,a->_values[j],pivot,func,ret)) + return false; + } + while( ret > 0 ); + if( i >= j ) break; + t = a->_values[i]; a->_values[i] = a->_values[j]; a->_values[j] = t; + } + t = a->_values[l]; a->_values[l] = a->_values[j]; a->_values[j] = t; + if(!_qsort( v, arr, l, j-1,func)) return false; + if(!_qsort( v, arr, j+1, r,func)) return false; + } + return true; +} + +static int array_sort(HSQUIRRELVM v) +{ + //SQ_TRY { + int func = -1; + SQObjectPtr &o = stack_get(v,1); + SQObject &funcobj = stack_get(v,2); + if(_array(o)->Size() > 1) { + if(type(funcobj) == OT_CLOSURE || type(funcobj) == OT_NATIVECLOSURE) func = 2; + if(!_qsort(v, o, 0, _array(o)->Size()-1, func)) + return SQ_ERROR; + + } + return 0; +} +static int array_slice(HSQUIRRELVM v) +{ + int sidx,eidx; + SQObjectPtr o; + if(get_slice_params(v,sidx,eidx,o)==-1)return -1; + if(sidx<0)sidx=_array(o)->Size()+sidx; + if(eidx<0)eidx=_array(o)->Size()+eidx; + if(eidx <= sidx)return sq_throwerror(v,_SC("wrong indexes")); + SQArray *arr=SQArray::Create(_ss(v),eidx-sidx); + SQObjectPtr t; + int count=0; + for(int i=sidx;iGet(i,t); + arr->Set(count++,t); + } + v->Push(arr); + return 1; + +} + +SQRegFunction SQSharedState::_array_default_delegate_funcz[]={ + {_SC("len"),default_delegate_len,1, _SC("a")}, + {_SC("append"),array_append,2, _SC("a")}, + {_SC("extend"),array_extend,2, _SC("aa")}, + {_SC("push"),array_append,2, _SC("a")}, + {_SC("pop"),array_pop,1, _SC("a")}, + {_SC("top"),array_top,1, _SC("a")}, + {_SC("insert"),array_insert,3, _SC("an")}, + {_SC("remove"),array_remove,2, _SC("an")}, + {_SC("resize"),array_resize,-2, _SC("an")}, + {_SC("reverse"),array_reverse,1, _SC("a")}, + {_SC("sort"),array_sort,-1, _SC("ac")}, + {_SC("slice"),array_slice,-1, _SC("ann")}, + {0,0} +}; + +//STRING DEFAULT DELEGATE////////////////////////// +static int string_slice(HSQUIRRELVM v) +{ + int sidx,eidx; + SQObjectPtr o; + if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1; + if(sidx<0)sidx=_string(o)->_len+sidx; + if(eidx<0)eidx=_string(o)->_len+eidx; + if(eidxPush(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx)); + return 1; +} + +static int string_find(HSQUIRRELVM v) +{ + int top,start_idx=0; + const SQChar *str,*substr,*ret; + if(((top=sq_gettop(v))>1) && SQ_SUCCEEDED(sq_getstring(v,1,&str)) && SQ_SUCCEEDED(sq_getstring(v,2,&substr))){ + if(top>2)sq_getinteger(v,3,&start_idx); + if((sq_getsize(v,1)>start_idx) && (start_idx>=0)){ + ret=scstrstr(&str[start_idx],substr); + if(ret){ + sq_pushinteger(v,(int)(ret-str)); + return 1; + } + } + return 0; + } + return sq_throwerror(v,_SC("invalid param")); +} + +#define STRING_TOFUNCZ(func) static int string_##func(HSQUIRRELVM v) \ +{ \ + SQObject str=stack_get(v,1); \ + int len=_string(str)->_len; \ + const SQChar *sThis=_stringval(str); \ + SQChar *sNew=(_ss(v)->GetScratchPad(rsl(len))); \ + for(int i=0;iPush(SQString::Create(_ss(v),sNew,len)); \ + return 1; \ +} + + +STRING_TOFUNCZ(tolower) +STRING_TOFUNCZ(toupper) + +SQRegFunction SQSharedState::_string_default_delegate_funcz[]={ + {_SC("len"),default_delegate_len,1, _SC("s")}, + {_SC("tointeger"),default_delegate_tointeger,1, _SC("s")}, + {_SC("tofloat"),default_delegate_tofloat,1, _SC("s")}, + {_SC("tostring"),default_delegate_tostring,1, _SC("s")}, + {_SC("slice"),string_slice,-1, _SC(" s n n")}, + {_SC("find"),string_find,-2, _SC("s s n ")}, + {_SC("tolower"),string_tolower,1, _SC("s")}, + {_SC("toupper"),string_toupper,1, _SC("s")}, + {0,0} +}; + +//INTEGER DEFAULT DELEGATE////////////////////////// +SQRegFunction SQSharedState::_number_default_delegate_funcz[]={ + {_SC("tointeger"),default_delegate_tointeger,1, _SC("n|b")}, + {_SC("tofloat"),default_delegate_tofloat,1, _SC("n|b")}, + {_SC("tostring"),default_delegate_tostring,1, _SC("n|b")}, + {_SC("tochar"),number_delegate_tochar,1, _SC("n|b")}, + {0,0} +}; + +//CLOSURE DEFAULT DELEGATE////////////////////////// +static int closure_call(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue))?1:SQ_ERROR; +} + +static int closure_acall(HSQUIRRELVM v) +{ + SQArray *aparams=_array(stack_get(v,2)); + int nparams=aparams->Size(); + v->Push(stack_get(v,1)); + for(int i=0;iPush(aparams->_values[i]); + return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue))?1:SQ_ERROR; +} + +SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={ + {_SC("call"),closure_call,-1, _SC("c")}, + {_SC("acall"),closure_acall,2, _SC("ca")}, + {0,0} +}; + +//GENERATOR DEFAULT DELEGATE +static int generator_getstatus(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + switch(_generator(o)->_state){ + case SQGenerator::eSuspended:v->Push(SQString::Create(_ss(v),_SC("suspended")));break; + case SQGenerator::eRunning:v->Push(SQString::Create(_ss(v),_SC("running")));break; + case SQGenerator::eDead:v->Push(SQString::Create(_ss(v),_SC("dead")));break; + } + return 1; +} + +SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={ + {_SC("getstatus"),generator_getstatus,1, _SC("g")}, + {0,0} +}; + +//THREAD DEFAULT DELEGATE + +static int thread_call(HSQUIRRELVM v) +{ + SQObjectPtr o = stack_get(v,1); + if(type(o) == OT_THREAD) { + int nparams = sq_gettop(v); + _thread(o)->Push(_thread(o)->_roottable); + for(int i = 2; i<(nparams+1); i++) + sq_move(_thread(o),v,i); + if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue))) { + sq_move(v,_thread(o),-1); + return 1; + } + return SQ_ERROR; + } + return sq_throwerror(v,_SC("wrong parameter")); +} + +static int thread_wakeup(HSQUIRRELVM v) +{ + SQObjectPtr o = stack_get(v,1); + if(type(o) == OT_THREAD) { + SQVM *thread = _thread(o); + int state = sq_getvmstate(thread); + if(state != SQ_VMSTATE_SUSPENDED) { + switch(state) { + case SQ_VMSTATE_IDLE: + return sq_throwerror(v,_SC("cannot wakeup a idle thread")); + break; + case SQ_VMSTATE_RUNNING: + return sq_throwerror(v,_SC("cannot wakeup a running thread")); + break; + } + } + + int wakeupret = sq_gettop(v)>1?1:0; + if(wakeupret) { + sq_move(thread,v,2); + } + if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,1))) { + sq_move(v,thread,-1); + sq_pop(thread,1); + if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) { + sq_pop(thread,1); + } + return 1; + } + return SQ_ERROR; + } + return sq_throwerror(v,_SC("wrong parameter")); +} + +static int thread_getstatus(HSQUIRRELVM v) +{ + SQObjectPtr &o = stack_get(v,1); + switch(sq_getvmstate(_thread(o))) { + case SQ_VMSTATE_IDLE: + sq_pushstring(v,_SC("idle"),-1); + break; + case SQ_VMSTATE_RUNNING: + sq_pushstring(v,_SC("running"),-1); + break; + case SQ_VMSTATE_SUSPENDED: + sq_pushstring(v,_SC("suspended"),-1); + break; + default: + return sq_throwerror(v,_SC("internal VM error")); + } + return 1; +} + +SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = { + {_SC("call"), thread_call, -1, _SC("v")}, + {_SC("wakeup"), thread_wakeup, -1, _SC("v")}, + {_SC("getstatus"), thread_getstatus, 1, _SC("v")}, + {0,0}, +}; + +static int class_getattributes(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_getattributes(v,-2))) + return 1; + return SQ_ERROR; +} + +static int class_setattributes(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_setattributes(v,-3))) + return 1; + return SQ_ERROR; +} + +SQRegFunction SQSharedState::_class_default_delegate_funcz[] = { + {_SC("getattributes"), class_getattributes, 2, _SC("y.")}, + {_SC("setattributes"), class_setattributes, 3, _SC("y..")}, + {_SC("rawin"),container_rawexists,2, _SC("y")}, + {0,0} +}; + +static int instance_getclass(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_getclass(v,1))) + return 1; + return SQ_ERROR; +} + +SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = { + {_SC("getclass"), instance_getclass, 1, _SC("x")}, + {_SC("rawin"),container_rawexists,2, _SC("x")}, + {0,0} +}; + diff --git a/src/squirrel/squirrel/sqclass.cpp b/src/squirrel/squirrel/sqclass.cpp new file mode 100644 index 000000000..b9dcd9e37 --- /dev/null +++ b/src/squirrel/squirrel/sqclass.cpp @@ -0,0 +1,184 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqtable.h" +#include "sqclass.h" +#include "sqclosure.h" + +SQClass::SQClass(SQSharedState *ss,SQClass *base) +{ + _uiRef=0; + _base = base; + _typetag = 0; + _metamethods.resize(MT_LAST); //size it to max size + if(_base) { + _defaultvalues.copy(base->_defaultvalues); + _methods.copy(base->_methods); + _metamethods.copy(base->_metamethods); + __ObjAddRef(_base); + } + _members = base?base->_members->Clone() : SQTable::Create(ss,0); + __ObjAddRef(_members); + _locked = false; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); +} + +void SQClass::Finalize() { + _attributes = _null_; + _defaultvalues.resize(0); + _methods.resize(0); + _metamethods.resize(0); + __ObjRelease(_members); + if(_base) { + __ObjRelease(_base); + } +} + +SQClass::~SQClass() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + Finalize(); +} + +bool SQClass::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) +{ + SQObjectPtr temp; + if(_locked) + return false; //the slot already exists + if(_members->Get(key,temp) && type(temp) == OT_INTEGER) //overrides the default value + { + _defaultvalues[_integer(temp)].val = val; + return true; + } + if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) { + SQInteger mmidx; + if((mmidx = _sharedstate->GetMetaMethodIdxByName(key)) != -1) { + _metamethods[mmidx] = val; + } + else { + if(type(temp) == OT_NULL) { + SQClassMemeber m; + m.val = val; + _members->NewSlot(key,SQObjectPtr((SQUserPointer)_methods.size())); + _methods.push_back(m); + } + else { + _methods[(int)_userpointer(temp)].val = val; + } + } + return true; + } + SQClassMemeber m; + m.val = val; + _members->NewSlot(key,SQObjectPtr((SQInteger)_defaultvalues.size())); + _defaultvalues.push_back(m); + return true; +} + +SQInstance *SQClass::CreateInstance() +{ + if(!_locked) Lock(); + return SQInstance::Create(_opt_ss(this),this); +} + +int SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + SQObjectPtr oval; + int idx = _members->Next(refpos,outkey,oval); + if(idx != -1) { + if(type(oval) != OT_INTEGER) { + outval = _methods[(int)_userpointer(oval)].val; + } + else { + outval = _defaultvalues[_integer(oval)].val; + } + } + return idx; +} + +bool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val) +{ + SQObjectPtr idx; + if(_members->Get(key,idx)) { + if(type(idx) == OT_INTEGER) + _defaultvalues[_integer(idx)].attrs = val; + else + _methods[(int)_userpointer(idx)].attrs = val; + return true; + } + return false; +} + +bool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval) +{ + SQObjectPtr idx; + if(_members->Get(key,idx)) { + outval = (type(idx) == OT_INTEGER?_defaultvalues[_integer(idx)].attrs:_methods[(int)_userpointer(idx)].attrs); + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////// +void SQInstance::Init(SQSharedState *ss) +{ + _uiRef = 0; + _userpointer = NULL; + _hook = NULL; + __ObjAddRef(_class); + _delegate = _class->_members; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); +} + +SQInstance::SQInstance(SQSharedState *ss, SQClass *c) +{ + _class = c; + _values.resize(_class->_defaultvalues.size()); + for(unsigned int i = 0; i < _class->_defaultvalues.size(); i++) { + _values[i] = _class->_defaultvalues[i].val; + } + Init(ss); +} + +SQInstance::SQInstance(SQSharedState *ss, SQInstance *i) +{ + _class = i->_class; + _values.copy(i->_values); + Init(ss); +} + +void SQInstance::Finalize() +{ + __ObjRelease(_class); + _values.resize(0); +} + +SQInstance::~SQInstance() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + Finalize(); +} + +bool SQInstance::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res) +{ + if(type(_class->_metamethods[mm]) != OT_NULL) { + res = _class->_metamethods[mm]; + return true; + } + return false; +} + +bool SQInstance::InstanceOf(SQClass *trg) +{ + SQClass *parent = _class; + while(parent != NULL) { + if(parent == trg) + return true; + parent = parent->_base; + } + return false; +} diff --git a/src/squirrel/squirrel/sqclass.h b/src/squirrel/squirrel/sqclass.h new file mode 100644 index 000000000..b510f2600 --- /dev/null +++ b/src/squirrel/squirrel/sqclass.h @@ -0,0 +1,104 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQCLASS_H_ +#define _SQCLASS_H_ + +struct SQInstance; + +struct SQClassMemeber { + SQClassMemeber(){} + SQClassMemeber(const SQClassMemeber &o) { + val = o.val; + attrs = o.attrs; + } + SQObjectPtr val; + SQObjectPtr attrs; +}; + +typedef sqvector SQClassMemeberVec; + +struct SQClass : public CHAINABLE_OBJ +{ + SQClass(SQSharedState *ss,SQClass *base); +public: + static SQClass* Create(SQSharedState *ss,SQClass *base) { + SQClass *newclass = (SQClass *)SQ_MALLOC(sizeof(SQClass)); + new (newclass) SQClass(ss, base); + return newclass; + } + ~SQClass(); + bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val); + bool Get(const SQObjectPtr &key,SQObjectPtr &val) { + if(_members->Get(key,val)) { + val = (type(val) == OT_INTEGER?_defaultvalues[_integer(val)].val:_methods[(int)_userpointer(val)].val); + return true; + } + return false; + } + bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val); + bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval); + void Lock() { _locked = true; if(_base) _base->Lock(); } + void Release() { sq_delete(this, SQClass); } + void Finalize(); + void Mark(SQCollectable ** ); + int Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + SQInstance *CreateInstance(); + SQTable *_members; + //SQTable *_properties; + SQClass *_base; + SQClassMemeberVec _defaultvalues; + SQClassMemeberVec _methods; + SQObjectPtrVec _metamethods; + SQObjectPtr _attributes; + unsigned int _typetag; + bool _locked; +}; + +struct SQInstance : public SQDelegable +{ + void Init(SQSharedState *ss); + SQInstance(SQSharedState *ss, SQClass *c); + SQInstance(SQSharedState *ss, SQInstance *c); +public: + static SQInstance* Create(SQSharedState *ss,SQClass *theclass) { + SQInstance *newinst = (SQInstance *)SQ_MALLOC(sizeof(SQInstance)); + new (newinst) SQInstance(ss, theclass); + return newinst; + } + SQInstance *Clone(SQSharedState *ss) + { + SQInstance *newinst = (SQInstance *)SQ_MALLOC(sizeof(SQInstance)); + new (newinst) SQInstance(ss, this); + return newinst; + } + ~SQInstance(); + bool Get(const SQObjectPtr &key,SQObjectPtr &val) { + if(_class->_members->Get(key,val)) { + val = (type(val) == OT_INTEGER?_values[_integer(val)]:_class->_methods[(int)_userpointer(val)].val); + return true; + } + return false; + } + bool Set(const SQObjectPtr &key,const SQObjectPtr &val) { + SQObjectPtr idx; + if(_class->_members->Get(key,idx) && type(idx) == OT_INTEGER) { + _values[_integer(idx)] = val; + return true; + } + return false; + } + void Release() { + if (_hook) { _hook(_userpointer,0);} + sq_delete(this, SQInstance); + } + void Finalize(); + void Mark(SQCollectable ** ); + bool InstanceOf(SQClass *trg); + bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res); + + SQClass *_class; + SQUserPointer _userpointer; + SQRELEASEHOOK _hook; + SQObjectPtrVec _values; +}; + +#endif //_SQCLASS_H_ diff --git a/src/squirrel/squirrel/sqclosure.h b/src/squirrel/squirrel/sqclosure.h new file mode 100644 index 000000000..724019a69 --- /dev/null +++ b/src/squirrel/squirrel/sqclosure.h @@ -0,0 +1,101 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQCLOSURE_H_ +#define _SQCLOSURE_H_ + +struct SQFunctionProto; + +struct SQClosure : public CHAINABLE_OBJ +{ +private: + SQClosure(SQSharedState *ss,SQFunctionProto *func){_uiRef=0;_function=func; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} +public: + static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func){ + SQClosure *nc=(SQClosure*)SQ_MALLOC(sizeof(SQClosure)); + new (nc) SQClosure(ss,func); + return nc; + } + void Release(){ + sq_delete(this,SQClosure); + } + ~SQClosure() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); + bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){_outervalues.resize(0); } +#endif + SQObjectPtr _function; + SQObjectPtrVec _outervalues; +}; +////////////////////////////////////////////// +struct SQGenerator : public CHAINABLE_OBJ +{ + enum SQGeneratorState{eRunning,eSuspended,eDead}; +private: + SQGenerator(SQSharedState *ss,SQClosure *closure){_uiRef=0;_closure=closure;_state=eRunning;_ci._generator=_null_;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} +public: + static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){ + SQGenerator *nc=(SQGenerator*)SQ_MALLOC(sizeof(SQGenerator)); + new (nc) SQGenerator(ss,closure); + return nc; + } + ~SQGenerator() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + void Kill(){ + _state=eDead; + _stack.resize(0); + _closure=_null_;} + void Release(){ + sq_delete(this,SQGenerator); + } + bool Yield(SQVM *v); + bool Resume(SQVM *v,int target); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){_stack.resize(0);_closure=_null_;} +#endif + SQObjectPtr _closure; + SQObjectPtrVec _stack; + SQObjectPtrVec _vargsstack; + SQVM::CallInfo _ci; + ExceptionsTraps _etraps; + SQGeneratorState _state; +}; + +struct SQNativeClosure : public CHAINABLE_OBJ +{ +private: + SQNativeClosure(SQSharedState *ss,SQFUNCTION func){_uiRef=0;_function=func;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } +public: + static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func) + { + SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(sizeof(SQNativeClosure)); + new (nc) SQNativeClosure(ss,func); + return nc; + } + ~SQNativeClosure() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + void Release(){ + sq_delete(this,SQNativeClosure); + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){_outervalues.resize(0);} +#endif + SQFUNCTION _function; + SQObjectPtr _name; + SQObjectPtrVec _outervalues; + SQIntVec _typecheck; + int _nparamscheck; +}; + + + +#endif //_SQCLOSURE_H_ diff --git a/src/squirrel/squirrel/sqcompiler.cpp b/src/squirrel/squirrel/sqcompiler.cpp new file mode 100644 index 000000000..116bac845 --- /dev/null +++ b/src/squirrel/squirrel/sqcompiler.cpp @@ -0,0 +1,1188 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include +#include "sqopcodes.h" +#include "sqstring.h" +#include "sqfuncproto.h" +#include "sqfuncstate.h" +#include "sqcompiler.h" +#include "sqlexer.h" +#include "sqvm.h" + +#define DEREF_NO_DEREF -1 +#define DEREF_FIELD -2 + +struct ExpState +{ + ExpState() + { + _deref = DEREF_NO_DEREF; + _freevar = false; + _class_or_delete = false; + _funcarg = false; + } + bool _class_or_delete; + bool _funcarg; + bool _freevar; + int _deref; +}; + +typedef sqvector ExpStateVec; + +#define _exst (_expstates.top()) + +#define BEGIN_BREAKBLE_BLOCK() int __nbreaks__=_fs->_unresolvedbreaks.size(); \ + int __ncontinues__=_fs->_unresolvedcontinues.size(); \ + _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0); + +#define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \ + __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \ + if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \ + if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \ + _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();} + +class SQCompiler +{ +public: + SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) + { + _vm=v; + _lex.Init(_ss(v), rg, up); + _sourcename = SQString::Create(_ss(v), sourcename); + _lineinfo = lineinfo;_raiseerror = raiseerror; + } + void Error(const SQChar *s, ...) + { + static SQChar temp[256]; + va_list vl; + va_start(vl, s); + scvsprintf(temp, s, vl); + va_end(vl); + throw ParserException(temp); + } + void Lex(){ _token = _lex.Lex();} + void PushExpState(){ _expstates.push_back(ExpState()); } + bool IsDerefToken(int tok) + { + switch(tok){ + case _SC('='): case _SC('('): case TK_NEWSLOT: + case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: return true; + } + return false; + } + ExpState PopExpState() + { + ExpState ret = _expstates.top(); + _expstates.pop_back(); + return ret; + } + SQObjectPtr Expect(int tok) + { + SQObjectPtr ret; + if(_token != tok) { + if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) { + //ret = SQString::Create(_ss(_vm),_SC("constructor")); + //do nothing + } + else { + if(tok > 255) { + switch(tok) + { + case TK_IDENTIFIER: + ret = SQString::Create(_ss(_vm), _SC("IDENTIFIER")); + break; + case TK_STRING_LITERAL: + ret = SQString::Create(_ss(_vm), _SC("STRING_LITERAL")); + break; + case TK_INTEGER: + ret = SQString::Create(_ss(_vm), _SC("INTEGER")); + break; + case TK_FLOAT: + ret = SQString::Create(_ss(_vm), _SC("FLOAT")); + break; + default: + ret = _lex.Tok2Str(tok); + } + Error(_SC("expected '%s'"), _stringval(ret)); + } + Error(_SC("expected '%c'"), tok); + } + } + switch(tok) + { + case TK_IDENTIFIER: + ret = SQString::Create(_ss(_vm), _lex._svalue); + break; + case TK_STRING_LITERAL: + ret = SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1); + break; + case TK_INTEGER: + ret = _lex._nvalue; + break; + case TK_FLOAT: + ret = _lex._fvalue; + break; + } + Lex(); + return ret; + } + bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); } + void OptionalSemicolon() + { + if(_token == _SC(';')) { Lex(); return; } + if(!IsEndOfStatement()) { + Error(_SC("end of statement expected (; or lf)")); + } + } + void MoveIfCurrentTargetIsLocal() { + int trg = _fs->TopTarget(); + if(_fs->IsLocal(trg)) { + trg = _fs->PopTarget(); //no pops the target and move it + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg); + } + } + bool Compile(SQObjectPtr &o) + { + SQ_TRY { + _debugline = 1; + _debugop = 0; + Lex(); + SQFuncState funcstate(_ss(_vm), SQFunctionProto::Create(), NULL); + _funcproto(funcstate._func)->_name = SQString::Create(_ss(_vm), _SC("main")); + _fs = &funcstate; + _fs->AddParameter(SQString::Create(_ss(_vm), _SC("this"))); + _funcproto(_fs->_func)->_sourcename = _sourcename; + int stacksize = _fs->GetStackSize(); + while(_token > 0){ + Statement(); + if(_lex._prevtoken != _SC('}')) OptionalSemicolon(); + } + CleanStack(stacksize); + _fs->AddLineInfos(_lex._currentline, _lineinfo, true); + _fs->AddInstruction(_OP_RETURN, 0xFF); + _funcproto(_fs->_func)->_stacksize = _fs->_stacksize; + _fs->SetStackSize(0); + _fs->Finalize(); + o = _fs->_func; +#ifdef _DEBUG_DUMP + _fs->Dump(); +#endif + } + SQ_CATCH(ParserException,ex){ + if(_raiseerror && _ss(_vm)->_compilererrorhandler){ + SQObjectPtr ret; + _ss(_vm)->_compilererrorhandler(_vm, ex.desc, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"), + _lex._currentline, _lex._currentcolumn); + } + _vm->_lasterror = SQString::Create(_ss(_vm), ex.desc, -1); + return false; + } + return true; + } + void Statements() + { + while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) { + Statement(); + if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon(); + } + } + void Statement() + { + _fs->AddLineInfos(_lex._currentline, _lineinfo); + switch(_token){ + case _SC(';'): Lex(); break; + case TK_IF: IfStatement(); break; + case TK_WHILE: WhileStatement(); break; + case TK_DO: DoWhileStatement(); break; + case TK_FOR: ForStatement(); break; + case TK_FOREACH: ForEachStatement(); break; + case TK_SWITCH: SwitchStatement(); break; + case TK_LOCAL: LocalDeclStatement(); break; + case TK_RETURN: + case TK_YIELD: { + SQOpcode op; + if(_token == TK_RETURN) { + op = _OP_RETURN; + + } + else { + op = _OP_YIELD; + _funcproto(_fs->_func)->_bgenerator = true; + } + Lex(); + if(!IsEndOfStatement()) { + int retexp = _fs->GetCurrentPos()+1; + CommaExpr(); + if(op == _OP_RETURN && _fs->_traps > 0) + _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0); + _fs->_returnexp = retexp; + _fs->AddInstruction(op, 1, _fs->PopTarget()); + } + else{ + if(op == _OP_RETURN && _fs->_traps > 0) + _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0); + _fs->_returnexp = -1; + _fs->AddInstruction(op, 0xFF); + } + break;} + case TK_BREAK: + if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block")); + if(_fs->_breaktargets.top() > 0){ + _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0); + } + _fs->AddInstruction(_OP_JMP, 0, -1234); + _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos()); + Lex(); + break; + case TK_CONTINUE: + if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block")); + if(_fs->_continuetargets.top() > 0) { + _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0); + } + _fs->AddInstruction(_OP_JMP, 0, -1234); + _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos()); + Lex(); + break; + case TK_FUNCTION: + FunctionStatement(); + break; + case TK_CLASS: + ClassStatement(); + break; + case _SC('{'):{ + int stacksize = _fs->GetStackSize(); + Lex(); + Statements(); + Expect(_SC('}')); + _fs->SetStackSize(stacksize); + } + break; + case TK_TRY: + TryCatchStatement(); + break; + case TK_THROW: + Lex(); + CommaExpr(); + _fs->AddInstruction(_OP_THROW, _fs->PopTarget()); + break; + default: + CommaExpr(); + _fs->PopTarget(); + break; + } + _fs->SnoozeOpt(); + } + void EmitDerefOp(SQOpcode op) + { + int val = _fs->PopTarget(); + int key = _fs->PopTarget(); + int src = _fs->PopTarget(); + _fs->AddInstruction(op,_fs->PushTarget(),src,key,val); + } + void Emit2ArgsOP(SQOpcode op, int p3 = 0) + { + int p2 = _fs->PopTarget(); //src in OP_GET + int p1 = _fs->PopTarget(); //key in OP_GET + _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3); + } + void EmitCompoundArith(int tok,bool deref) + { + int oper; + switch(tok){ + case TK_MINUSEQ: oper = '-'; break; + case TK_PLUSEQ: oper = '+'; break; + case TK_MULEQ: oper = '*'; break; + case TK_DIVEQ: oper = '/'; break; + case TK_MODEQ: oper = '%'; break; + default: assert(0); break; + }; + if(deref) { + int val = _fs->PopTarget(); + int key = _fs->PopTarget(); + int src = _fs->PopTarget(); + //mixes dest obj and source val in the arg1(hack?) + _fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper); + } + else { + Emit2ArgsOP(_OP_COMPARITHL, oper); + } + } + void CommaExpr() + { + for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr()); + } + ExpState Expression(bool funcarg = false) + { + PushExpState(); + _exst._class_or_delete = false; + _exst._funcarg = funcarg; + LogicalOrExp(); + switch(_token) { + case _SC('='): + case TK_NEWSLOT: + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MODEQ: + { + int op = _token; + int ds = _exst._deref; + bool freevar = _exst._freevar; + if(ds == DEREF_NO_DEREF) Error(_SC("can't assign expression")); + Lex(); Expression(); + + switch(op){ + case TK_NEWSLOT: + if(freevar) Error(_SC("free variables cannot be modified")); + if(ds == DEREF_FIELD) + EmitDerefOp(_OP_NEWSLOT); + else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local + Error(_SC("can't 'create' a local slot")); + break; + case _SC('='): //ASSIGN + if(freevar) Error(_SC("free variables cannot be modified")); + if(ds == DEREF_FIELD) + EmitDerefOp(_OP_SET); + else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local + int p2 = _fs->PopTarget(); //src in OP_GET + int p1 = _fs->TopTarget(); //key in OP_GET + _fs->AddInstruction(_OP_MOVE, p1, p2); + } + break; + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MODEQ: + EmitCompoundArith(op,ds == DEREF_FIELD); + break; + } + } + break; + case _SC('?'): { + Lex(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + int jzpos = _fs->GetCurrentPos(); + int trg = _fs->PushTarget(); + Expression(); + int first_exp = _fs->PopTarget(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + int endfirstexp = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_JMP, 0, 0); + Expect(_SC(':')); + int jmppos = _fs->GetCurrentPos(); + Expression(); + int second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); + _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1); + _fs->SnoozeOpt(); + } + break; + } + return PopExpState(); + } + void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),int op3 = 0) + { + Lex(); (this->*f)(); + int op1 = _fs->PopTarget();int op2 = _fs->PopTarget(); + _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3); + } + void LogicalOrExp() + { + LogicalAndExp(); + for(;;) if(_token == TK_OR) { + int first_exp = _fs->PopTarget(); + int trg = _fs->PushTarget(); + _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0); + int jpos = _fs->GetCurrentPos(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + Lex(); LogicalOrExp(); + _fs->SnoozeOpt(); + int second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SnoozeOpt(); + _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); + break; + }else return; + } + void LogicalAndExp() + { + BitwiseOrExp(); + for(;;) switch(_token) { + case TK_AND: { + int first_exp = _fs->PopTarget(); + int trg = _fs->PushTarget(); + _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0); + int jpos = _fs->GetCurrentPos(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + Lex(); LogicalAndExp(); + _fs->SnoozeOpt(); + int second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SnoozeOpt(); + _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); + break; + } + case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break; + case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break; + default: + return; + } + } + void BitwiseOrExp() + { + BitwiseXorExp(); + for(;;) if(_token == _SC('|')) + {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR); + }else return; + } + void BitwiseXorExp() + { + BitwiseAndExp(); + for(;;) if(_token == _SC('^')) + {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR); + }else return; + } + void BitwiseAndExp() + { + CompExp(); + for(;;) if(_token == _SC('&')) + {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND); + }else return; + } + void CompExp() + { + ShiftExp(); + for(;;) switch(_token) { + case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break; + case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break; + case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break; + case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break; + case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break; + case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break; + default: return; + } + } + void ShiftExp() + { + PlusExp(); + for(;;) switch(_token) { + case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break; + case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break; + case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break; + default: return; + } + } + void PlusExp() + { + MultExp(); + for(;;) switch(_token) { + case _SC('+'): case _SC('-'): + BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break; + default: return; + } + } + + void MultExp() + { + PrefixedExpr(); + for(;;) switch(_token) { + case _SC('*'): case _SC('/'): case _SC('%'): + BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break; + default: return; + } + } + //if 'pos' != -1 the previous variable is a local variable + void PrefixedExpr() + { + int pos = Factor(); + for(;;) { + switch(_token) { + case _SC('.'): { + pos = -1; + SQObjectPtr idx; + Lex(); + if(_token == TK_PARENT) { + Lex(); + if(!NeedGet()) + Error(_SC("parent cannot be set")); + int src = _fs->PopTarget(); + _fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src); + } + else { + idx = Expect(TK_IDENTIFIER); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetStringConstant(_stringval(idx))); + if(NeedGet()) Emit2ArgsOP(_OP_GET); + } + _exst._deref = DEREF_FIELD; + _exst._freevar = false; + } + break; + case _SC('['): + if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration")); + Lex(); Expression(); Expect(_SC(']')); + pos = -1; + if(NeedGet()) Emit2ArgsOP(_OP_GET); + _exst._deref = DEREF_FIELD; + _exst._freevar = false; + break; + case TK_MINUSMINUS: + case TK_PLUSPLUS: + if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) { + int tok = _token; Lex(); + if(pos < 0) + Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1); + else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local + int src = _fs->PopTarget(); + _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1); + } + + } + return; + break; + case _SC('('): + { + if(_exst._deref != DEREF_NO_DEREF) { + if(pos<0) { + int key = _fs->PopTarget(); //key + int table = _fs->PopTarget(); //table etc... + int closure = _fs->PushTarget(); + int ttarget = _fs->PushTarget(); + _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget); + } + else{ + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + } + } + else + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + _exst._deref = DEREF_NO_DEREF; + Lex(); + FunctionCallArgs(); + } + break; + default: return; + } + } + } + int Factor() + { + switch(_token) + { + case TK_STRING_LITERAL: { + SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1)); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetStringConstant(_stringval(id))); + Lex(); + } + break; + case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break; + case TK_VARGV: { Lex(); + Expect(_SC('[')); + Expression(); + Expect(_SC(']')); + int src = _fs->PopTarget(); + _fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src); + } + break; + case TK_IDENTIFIER: + case TK_CONSTRUCTOR: + case TK_THIS:{ + _exst._freevar = false; + SQObjectPtr id; + switch(_token) { + case TK_IDENTIFIER: id = SQString::Create(_ss(_vm), _lex._svalue); break; + case TK_THIS: id = SQString::Create(_ss(_vm), _SC("this")); break; + case TK_CONSTRUCTOR: id = SQString::Create(_ss(_vm), _SC("constructor")); break; + } + int pos = -1; + Lex(); + if((pos = _fs->GetLocalVariable(id)) == -1) { + //checks if is a free variable + if((pos = _fs->GetOuterVariable(id)) != -1) { + _exst._deref = _fs->PushTarget(); + _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos); + _exst._freevar = true; + } else { + _fs->PushTarget(0); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetStringConstant(_stringval(id))); + if(NeedGet()) Emit2ArgsOP(_OP_GET); + _exst._deref = DEREF_FIELD; + } + } + else{ + _fs->PushTarget(pos); + _exst._deref = pos; + } + return _exst._deref; + } + break; + case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break; + case TK_DOUBLE_COLON: // "::" + _fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget()); + _exst._deref = DEREF_FIELD; + _token = _SC('.'); //hack + return -1; + break; + case TK_NULL: + _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); + Lex(); + break; + case TK_INTEGER: + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue)); + Lex(); + break; + case TK_FLOAT: + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue)); + Lex(); + break; + case TK_TRUE: case TK_FALSE: + _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0); + Lex(); + break; + case _SC('['): { + _fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget()); + int apos = _fs->GetCurrentPos(),key = 0; + Lex(); + while(_token != _SC(']')) { + Expression(); + if(_token == _SC(',')) Lex(); + int val = _fs->PopTarget(); + int array = _fs->TopTarget(); + _fs->AddInstruction(_OP_APPENDARRAY, array, val); + key++; + } + _fs->SetIntructionParam(apos, 1, key); + Lex(); + } + break; + case _SC('{'):{ + _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); + Lex();ParseTableOrClass(_SC(',')); + } + break; + case TK_FUNCTION: FunctionExp(_token);break; + case TK_CLASS: Lex(); ClassExp();break; + case _SC('-'): UnaryOP(_OP_NEG); break; + case _SC('!'): UnaryOP(_OP_NOT); break; + case _SC('~'): UnaryOP(_OP_BWNOT); break; + case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break; + case TK_RESUME : UnaryOP(_OP_RESUME); break; + case TK_CLONE : UnaryOP(_OP_CLONE); break; + case TK_MINUSMINUS : + case TK_PLUSPLUS :PrefixIncDec(_token); break; + case TK_DELETE : DeleteExpr(); break; + case TK_DELEGATE : DelegateExpr(); break; + case _SC('('): Lex(); CommaExpr(); Expect(_SC(')')); + break; + default: Error(_SC("expression expected")); + } + return -1; + } + void UnaryOP(SQOpcode op) + { + Lex(); PrefixedExpr(); + int src = _fs->PopTarget(); + _fs->AddInstruction(op, _fs->PushTarget(), src); + } + bool NeedGet() + { + switch(_token) { + case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS: + case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ: + return false; + } + return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == _SC('.') || _token == _SC('['))); + } + + void FunctionCallArgs() + { + int nargs = 1;//this + while(_token != _SC(')')) { + Expression(true); + MoveIfCurrentTargetIsLocal(); + nargs++; + if(_token == _SC(',')){ + Lex(); + if(_token == ')') Error(_SC("expression expected, found ')'")); + } + } + Lex(); + for(int i = 0; i < (nargs - 1); i++) _fs->PopTarget(); + int stackbase = _fs->PopTarget(); + int closure = _fs->PopTarget(); + _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs); + } + void ParseTableOrClass(int separator,int terminator = '}') + { + int tpos = _fs->GetCurrentPos(),nkeys = 0; + + while(_token != terminator) { + bool hasattrs = false; + //check if is an attribute + if(separator == ';' && _token == TK_ATTR_OPEN) { + _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex(); + ParseTableOrClass(',',TK_ATTR_CLOSE); + hasattrs = true; + } + switch(_token) { + case TK_FUNCTION: + case TK_CONSTRUCTOR:{ + int tk = _token; + Lex(); + SQObjectPtr id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : SQString::Create(_ss(_vm),_SC("constructor")); + Expect(_SC('(')); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetStringConstant(_stringval(id))); + CreateFunction(id); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); + } + break; + case _SC('['): + Lex(); CommaExpr(); Expect(_SC(']')); + Expect(_SC('=')); Expression(); + break; + default : + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetStringConstant(_stringval(Expect(TK_IDENTIFIER)))); + Expect(_SC('=')); Expression(); + } + + if(_token == separator) Lex();//optional comma/semicolon + nkeys++; + int val = _fs->PopTarget(); + int key = _fs->PopTarget(); + int attrs = hasattrs ? _fs->PopTarget():-1; + assert(hasattrs && attrs == key-1 || !hasattrs); + int table = _fs->TopTarget(); //<AddInstruction(hasattrs?_OP_NEWSLOTA:_OP_NEWSLOT, _fs->PushTarget(), table, key, val); + _fs->PopTarget(); + } + if(separator == _SC(',')) //hack recognizes a table from the separator + _fs->SetIntructionParam(tpos, 1, nkeys); + Lex(); + } + void LocalDeclStatement() + { + SQObjectPtr varname; + do { + Lex(); varname = Expect(TK_IDENTIFIER); + if(_token == _SC('=')) { + Lex(); Expression(); + int src = _fs->PopTarget(); + int dest = _fs->PushTarget(); + if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src); + } + else{ + _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); + } + _fs->PopTarget(); + _fs->PushLocalVariable(varname); + + } while(_token == _SC(',')); + } + void IfStatement() + { + int jmppos; + bool haselse = false; + Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + int jnepos = _fs->GetCurrentPos(); + int stacksize = _fs->GetStackSize(); + + Statement(); + // + if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon(); + + CleanStack(stacksize); + int endifblock = _fs->GetCurrentPos(); + if(_token == TK_ELSE){ + haselse = true; + stacksize = _fs->GetStackSize(); + _fs->AddInstruction(_OP_JMP); + jmppos = _fs->GetCurrentPos(); + Lex(); + Statement(); OptionalSemicolon(); + CleanStack(stacksize); + _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); + } + _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0)); + } + void WhileStatement() + { + int jzpos, jmppos; + int stacksize = _fs->GetStackSize(); + jmppos = _fs->GetCurrentPos(); + Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + + BEGIN_BREAKBLE_BLOCK(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + jzpos = _fs->GetCurrentPos(); + stacksize = _fs->GetStackSize(); + + Statement(); + + CleanStack(stacksize); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); + + END_BREAKBLE_BLOCK(jmppos); + } + void DoWhileStatement() + { + Lex(); + int jzpos = _fs->GetCurrentPos(); + int stacksize = _fs->GetStackSize(); + BEGIN_BREAKBLE_BLOCK() + Statement(); + CleanStack(stacksize); + Expect(TK_WHILE); + int continuetrg = _fs->GetCurrentPos(); + Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + _fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1); + END_BREAKBLE_BLOCK(continuetrg); + } + void ForStatement() + { + Lex(); + int stacksize = _fs->GetStackSize(); + Expect(_SC('(')); + if(_token == TK_LOCAL) LocalDeclStatement(); + else if(_token != _SC(';')){ + CommaExpr(); + _fs->PopTarget(); + } + Expect(_SC(';')); + _fs->SnoozeOpt(); + int jmppos = _fs->GetCurrentPos(); + int jzpos = -1; + if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); } + Expect(_SC(';')); + _fs->SnoozeOpt(); + int expstart = _fs->GetCurrentPos() + 1; + if(_token != _SC(')')) { + CommaExpr(); + _fs->PopTarget(); + } + Expect(_SC(')')); + _fs->SnoozeOpt(); + int expend = _fs->GetCurrentPos(); + int expsize = (expend - expstart) + 1; + SQInstructionVec exp; + if(expsize > 0) { + for(int i = 0; i < expsize; i++) + exp.push_back(_fs->GetInstruction(expstart + i)); + _fs->PopInstructions(expsize); + } + BEGIN_BREAKBLE_BLOCK() + Statement(); + int continuetrg = _fs->GetCurrentPos(); + if(expsize > 0) { + for(int i = 0; i < expsize; i++) + _fs->AddInstruction(exp[i]); + } + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0); + if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); + CleanStack(stacksize); + + END_BREAKBLE_BLOCK(continuetrg); + } + void ForEachStatement() + { + SQObjectPtr idxname, valname; + Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER); + if(_token == _SC(',')) { + idxname = valname; + Lex(); valname = Expect(TK_IDENTIFIER); + } + else{ + idxname = SQString::Create(_ss(_vm), _SC("@INDEX@")); + } + Expect(TK_IN); + + //save the stack size + int stacksize = _fs->GetStackSize(); + //put the table in the stack(evaluate the table expression) + Expression(); Expect(_SC(')')); + int container = _fs->TopTarget(); + //push the index local var + int indexpos = _fs->PushLocalVariable(idxname); + _fs->AddInstruction(_OP_LOADNULLS, indexpos,1); + //push the value local var + int valuepos = _fs->PushLocalVariable(valname); + _fs->AddInstruction(_OP_LOADNULLS, valuepos,1); + //push reference index + int itrpos = _fs->PushLocalVariable(SQString::Create(_ss(_vm), _SC("@ITERATOR@"))); //use invalid id to make it inaccessible + _fs->AddInstruction(_OP_LOADNULLS, itrpos,1); + int jmppos = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos); + int foreachpos = _fs->GetCurrentPos(); + //generate the statement code + BEGIN_BREAKBLE_BLOCK() + Statement(); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos); + //restore the local variable stack(remove index,val and ref idx) + CleanStack(stacksize); + END_BREAKBLE_BLOCK(foreachpos - 1); + } + void SwitchStatement() + { + Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + Expect(_SC('{')); + int expr = _fs->TopTarget(); + bool bfirst = true; + int tonextcondjmp = -1; + int skipcondjmp = -1; + int __nbreaks__ = _fs->_unresolvedbreaks.size(); + _fs->_breaktargets.push_back(0); + while(_token == TK_CASE) { + if(!bfirst) { + _fs->AddInstruction(_OP_JMP, 0, 0); + skipcondjmp = _fs->GetCurrentPos(); + _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); + } + //condition + Lex(); Expression(); Expect(_SC(':')); + int trg = _fs->PopTarget(); + _fs->AddInstruction(_OP_EQ, trg, trg, expr); + _fs->AddInstruction(_OP_JZ, trg, 0); + //end condition + if(skipcondjmp != -1) { + _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp)); + } + tonextcondjmp = _fs->GetCurrentPos(); + int stacksize = _fs->GetStackSize(); + Statements(); + _fs->SetStackSize(stacksize); + bfirst = false; + } + if(tonextcondjmp != -1) + _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); + if(_token == TK_DEFAULT) { + Lex(); Expect(_SC(':')); + int stacksize = _fs->GetStackSize(); + Statements(); + _fs->SetStackSize(stacksize); + } + Expect(_SC('}')); + _fs->PopTarget(); + __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__; + if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__); + _fs->_breaktargets.pop_back(); + + } + void FunctionStatement() + { + SQObjectPtr id; + Lex(); id = Expect(TK_IDENTIFIER); + _fs->PushTarget(0); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetStringConstant(_stringval(id))); + if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); + + while(_token == TK_DOUBLE_COLON) { + Lex(); + id = Expect(TK_IDENTIFIER); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetStringConstant(_stringval(id))); + if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); + } + Expect(_SC('(')); + CreateFunction(id); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); + EmitDerefOp(_OP_NEWSLOT); + _fs->PopTarget(); + } + void ClassStatement() + { + ExpState es; + Lex(); PushExpState(); + _exst._class_or_delete = true; + _exst._funcarg = false; + PrefixedExpr(); + es = PopExpState(); + if(es._deref == DEREF_NO_DEREF) Error(_SC("invalid class name")); + if(es._deref == DEREF_FIELD) { + ClassExp(); + EmitDerefOp(_OP_NEWSLOT); + _fs->PopTarget(); + } + else Error(_SC("cannot create a class in a local with the syntax(class )")); + } + void TryCatchStatement() + { + SQObjectPtr exid; + Lex(); + _fs->AddInstruction(_OP_PUSHTRAP,0,0); + _fs->_traps++; + if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++; + if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++; + int trappos = _fs->GetCurrentPos(); + Statement(); + _fs->_traps--; + _fs->AddInstruction(_OP_POPTRAP, 1, 0); + if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--; + if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--; + _fs->AddInstruction(_OP_JMP, 0, 0); + int jmppos = _fs->GetCurrentPos(); + _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos)); + Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')')); + int stacksize = _fs->GetStackSize(); + int ex_target = _fs->PushLocalVariable(exid); + _fs->SetIntructionParam(trappos, 0, ex_target); + Statement(); + _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0); + CleanStack(stacksize); + } + void FunctionExp(int ftype) + { + Lex(); Expect(_SC('(')); + CreateFunction(_null_); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1); + } + void ClassExp() + { + int base = -1; + int attrs = -1; + if(_token == TK_EXTENDS) { + Lex(); Expression(); + base = _fs->TopTarget(); + } + if(_token == TK_ATTR_OPEN) { + Lex(); + _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); + ParseTableOrClass(_SC(','),TK_ATTR_CLOSE); + attrs = _fs->TopTarget(); + } + Expect(_SC('{')); + if(attrs != -1) _fs->PopTarget(); + if(base != -1) _fs->PopTarget(); + _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs); + ParseTableOrClass(_SC(';')); + } + void DelegateExpr() + { + Lex(); CommaExpr(); + Expect(_SC(':')); + CommaExpr(); + int table = _fs->PopTarget(), delegate = _fs->PopTarget(); + _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate); + } + void DeleteExpr() + { + ExpState es; + Lex(); PushExpState(); + _exst._class_or_delete = true; + _exst._funcarg = false; + PrefixedExpr(); + es = PopExpState(); + if(es._deref == DEREF_NO_DEREF) Error(_SC("can't delete an expression")); + if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE); + else Error(_SC("cannot delete a local")); + } + void PrefixIncDec(int token) + { + ExpState es; + Lex(); PushExpState(); + _exst._class_or_delete = true; + _exst._funcarg = false; + PrefixedExpr(); + es = PopExpState(); + if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1); + else { + int src = _fs->PopTarget(); + _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1); + } + } + void CreateFunction(SQObjectPtr name) + { + SQFuncState funcstate(_ss(_vm), SQFunctionProto::Create(), _fs); + _funcproto(funcstate._func)->_name = name; + SQObjectPtr paramname; + funcstate.AddParameter(SQString::Create(_ss(_vm), _SC("this"))); + _funcproto(funcstate._func)->_sourcename = _sourcename; + while(_token!=_SC(')')) { + if(_token == TK_VARPARAMS) { + funcstate._varparams = true; + Lex(); + if(_token != _SC(')')) Error(_SC("expected ')'")); + break; + } + else { + paramname = Expect(TK_IDENTIFIER); + funcstate.AddParameter(paramname); + if(_token == _SC(',')) Lex(); + else if(_token != _SC(')')) Error(_SC("expected ')' or ','")); + } + } + Expect(_SC(')')); + //outer values + if(_token == _SC(':')) { + Lex(); Expect(_SC('(')); + while(_token != _SC(')')) { + paramname = Expect(TK_IDENTIFIER); + //outers are treated as implicit local variables + funcstate.AddOuterValue(paramname); + if(_token == _SC(',')) Lex(); + else if(_token != _SC(')')) Error(_SC("expected ')' or ','")); + } + Lex(); + } + + SQFuncState *currchunk = _fs; + _fs = &funcstate; + Statement(); + funcstate.AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true); + funcstate.AddInstruction(_OP_RETURN, -1); + funcstate.SetStackSize(0); + _funcproto(_fs->_func)->_stacksize = _fs->_stacksize; + funcstate.Finalize(); +#ifdef _DEBUG_DUMP + funcstate.Dump(); +#endif + _fs = currchunk; + _fs->_functions.push_back(funcstate._func); + } + void CleanStack(int stacksize) + { + if(_fs->GetStackSize() != stacksize) + _fs->SetStackSize(stacksize); + } + void ResolveBreaks(SQFuncState *funcstate, int ntoresolve) + { + while(ntoresolve > 0) { + int pos = funcstate->_unresolvedbreaks.back(); + funcstate->_unresolvedbreaks.pop_back(); + //set the jmp instruction + funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0); + ntoresolve--; + } + } + void ResolveContinues(SQFuncState *funcstate, int ntoresolve, int targetpos) + { + while(ntoresolve > 0) { + int pos = funcstate->_unresolvedcontinues.back(); + funcstate->_unresolvedcontinues.pop_back(); + //set the jmp instruction + funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0); + ntoresolve--; + } + } +private: + int _token; + SQFuncState *_fs; + SQObjectPtr _sourcename; + SQLexer _lex; + bool _lineinfo; + bool _raiseerror; + int _debugline; + int _debugop; + ExpStateVec _expstates; + SQVM *_vm; +}; + +bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo) +{ + SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo); + return p.Compile(out); +} diff --git a/src/squirrel/squirrel/sqcompiler.h b/src/squirrel/squirrel/sqcompiler.h new file mode 100644 index 000000000..1d29e9681 --- /dev/null +++ b/src/squirrel/squirrel/sqcompiler.h @@ -0,0 +1,74 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQCOMPILER_H_ +#define _SQCOMPILER_H_ + +struct SQVM; + +#define TK_IDENTIFIER 258 +#define TK_STRING_LITERAL 259 +#define TK_INTEGER 260 +#define TK_FLOAT 261 +#define TK_DELEGATE 262 +#define TK_DELETE 263 +#define TK_EQ 264 +#define TK_NE 265 +#define TK_LE 266 +#define TK_GE 267 +#define TK_SWITCH 268 +#define TK_ARROW 269 +#define TK_AND 270 +#define TK_OR 271 +#define TK_IF 272 +#define TK_ELSE 273 +#define TK_WHILE 274 +#define TK_BREAK 275 +#define TK_FOR 276 +#define TK_DO 277 +#define TK_NULL 278 +#define TK_FOREACH 279 +#define TK_IN 280 +#define TK_NEWSLOT 281 +#define TK_MODULO 282 +#define TK_LOCAL 283 +#define TK_CLONE 284 +#define TK_FUNCTION 285 +#define TK_RETURN 286 +#define TK_TYPEOF 287 +#define TK_UMINUS 288 +#define TK_PLUSEQ 289 +#define TK_MINUSEQ 290 +#define TK_CONTINUE 291 +#define TK_YIELD 292 +#define TK_TRY 293 +#define TK_CATCH 294 +#define TK_THROW 295 +#define TK_SHIFTL 296 +#define TK_SHIFTR 297 +#define TK_RESUME 298 +#define TK_DOUBLE_COLON 299 +#define TK_CASE 300 +#define TK_DEFAULT 301 +#define TK_THIS 302 +#define TK_PLUSPLUS 303 +#define TK_MINUSMINUS 304 +#define TK_PARENT 305 +#define TK_USHIFTR 306 +#define TK_CLASS 307 +#define TK_EXTENDS 308 +#define TK_CONSTRUCTOR 310 +#define TK_INSTANCEOF 311 +#define TK_VARPARAMS 312 +#define TK_VARGC 313 +#define TK_VARGV 314 +#define TK_TRUE 315 +#define TK_FALSE 316 +#define TK_MULEQ 317 +#define TK_DIVEQ 318 +#define TK_MODEQ 319 +#define TK_ATTR_OPEN 320 +#define TK_ATTR_CLOSE 321 + + +struct ParserException{ SQChar *desc; ParserException(SQChar *err):desc(err) {} }; +bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo); +#endif //_SQCOMPILER_H_ diff --git a/src/squirrel/squirrel/sqdebug.cpp b/src/squirrel/squirrel/sqdebug.cpp new file mode 100644 index 000000000..89663ba4c --- /dev/null +++ b/src/squirrel/squirrel/sqdebug.cpp @@ -0,0 +1,98 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" + +SQRESULT sq_stackinfos(HSQUIRRELVM v, int level, SQStackInfos *si) +{ + int cssize = v->_callsstack.size(); + if (cssize > level) { + memset(si, 0, sizeof(SQStackInfos)); + SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; + switch (type(ci._closure)) { + case OT_CLOSURE:{ + SQFunctionProto *func = _funcproto(_closure(ci._closure)->_function); + if (type(func->_name) == OT_STRING) + si->funcname = _stringval(func->_name); + if (type(func->_sourcename) == OT_STRING) + si->source = _stringval(func->_sourcename); + si->line = func->GetLine(ci._ip); + } + break; + case OT_NATIVECLOSURE: + si->source = _SC("NATIVE"); + si->funcname = _SC("unknown"); + if(type(_nativeclosure(ci._closure)->_name) == OT_STRING) + si->funcname = _stringval(_nativeclosure(ci._closure)->_name); + si->line = -1; + break; + } + return SQ_OK; + } + return SQ_ERROR; +} + +void SQVM::Raise_Error(const SQChar *s, ...) +{ + va_list vl; + va_start(vl, s); + scvsprintf(_sp(rsl(scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl); + va_end(vl); + _lasterror = SQString::Create(_ss(this),_spval,-1); +} + +void SQVM::Raise_Error(SQObjectPtr &desc) +{ + _lasterror = desc; +} + +SQString *SQVM::PrintObjVal(const SQObject &o) +{ + switch(type(o)) { + case OT_STRING: return _string(o); + case OT_INTEGER: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), _SC("%d"), _integer(o)); + return SQString::Create(_ss(this), _spval); + break; + case OT_FLOAT: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), _SC("%.14g"), _float(o)); + return SQString::Create(_ss(this), _spval); + break; + default: + return SQString::Create(_ss(this), GetTypeName(o)); + } +} + +void SQVM::Raise_IdxError(SQObject &o) +{ + SQObjectPtr oval = PrintObjVal(o); + Raise_Error(_SC("the index '%.50s' does not exist"), _stringval(oval)); +} + +void SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2) +{ + SQObjectPtr oval1 = PrintObjVal(o1), oval2 = PrintObjVal(o2); + Raise_Error(_SC("comparsion between '%.50s' and '%.50s'"), _stringval(oval1), _stringval(oval2)); +} + + +void SQVM::Raise_ParamTypeError(int nparam,int typemask,int type) +{ + SQObjectPtr exptypes = SQString::Create(_ss(this), _SC(""), -1); + int found = 0; + for(int i=0; i<16; i++) + { + int mask = 0x00000001 << i; + if(typemask & (mask)) { + if(found>0) StringCat(exptypes,SQString::Create(_ss(this), _SC("|"), -1), exptypes); + found ++; + StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes); + } + } + Raise_Error(_SC("parameter %d has an invalid type '%s' ; expected: '%s'"), nparam, IdType2Name((SQObjectType)type), _stringval(exptypes)); +} diff --git a/src/squirrel/squirrel/sqfuncproto.h b/src/squirrel/squirrel/sqfuncproto.h new file mode 100644 index 000000000..ab45ba243 --- /dev/null +++ b/src/squirrel/squirrel/sqfuncproto.h @@ -0,0 +1,89 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQFUNCTION_H_ +#define _SQFUNCTION_H_ + +#include "sqopcodes.h" + +enum SQOuterType { + otLOCAL = 0, + otSYMBOL = 1, + otOUTER = 2 +}; + +struct SQOuterVar +{ + + SQOuterVar(){} + SQOuterVar(const SQObjectPtr &name,const SQObjectPtr &src,SQOuterType t) + { + _name = name; + _src=src; + _type=t; + } + SQOuterVar(const SQOuterVar &ov) + { + _type=ov._type; + _src=ov._src; + _name=ov._name; + } + SQOuterType _type; + SQObjectPtr _name; + SQObjectPtr _src; +}; + +struct SQLocalVarInfo +{ + SQLocalVarInfo():_start_op(0),_end_op(0){} + SQLocalVarInfo(const SQLocalVarInfo &lvi) + { + _name=lvi._name; + _start_op=lvi._start_op; + _end_op=lvi._end_op; + _pos=lvi._pos; + } + SQObjectPtr _name; + unsigned int _start_op; + unsigned int _end_op; + unsigned int _pos; +}; + +struct SQLineInfo { int _line;int _op; }; + +typedef sqvector SQOuterVarVec; +typedef sqvector SQLocalVarInfoVec; +typedef sqvector SQLineInfoVec; + +struct SQFunctionProto : public SQRefCounted +{ +private: + SQFunctionProto(){ + _uiRef=0; + _stacksize=0; + _bgenerator=false;} +public: + static SQFunctionProto *Create() + { + SQFunctionProto *f; + sq_new(f,SQFunctionProto); + return f; + } + void Release(){ sq_delete(this,SQFunctionProto);} + const SQChar* GetLocal(SQVM *v,unsigned int stackbase,unsigned int nseq,unsigned int nop); + int GetLine(SQInstruction *curr); + bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); + bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read); + SQObjectPtrVec _literals; + SQObjectPtrVec _functions; + SQObjectPtrVec _parameters; + SQOuterVarVec _outervalues; + SQInstructionVec _instructions; + SQObjectPtr _sourcename; + SQObjectPtr _name; + SQLocalVarInfoVec _localvarinfos; + SQLineInfoVec _lineinfos; + int _stacksize; + bool _bgenerator; + bool _varparams; +}; + +#endif //_SQFUNCTION_H_ diff --git a/src/squirrel/squirrel/sqfuncstate.cpp b/src/squirrel/squirrel/sqfuncstate.cpp new file mode 100644 index 000000000..b070809f7 --- /dev/null +++ b/src/squirrel/squirrel/sqfuncstate.cpp @@ -0,0 +1,482 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqcompiler.h" +#include "sqfuncproto.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqopcodes.h" +#include "sqfuncstate.h" + +#ifdef _DEBUG_DUMP +SQInstructionDesc g_InstrDesc[]={ + {_SC("_OP_LINE")}, + {_SC("_OP_LOAD")}, + {_SC("_OP_TAILCALL")}, + {_SC("_OP_CALL")}, + {_SC("_OP_PREPCALL")}, + {_SC("_OP_PREPCALLK")}, + {_SC("_OP_GETK")}, + {_SC("_OP_MOVE")}, + {_SC("_OP_NEWSLOT")}, + {_SC("_OP_DELETE")}, + {_SC("_OP_SET")}, + {_SC("_OP_GET")}, + {_SC("_OP_EQ")}, + {_SC("_OP_NE")}, + {_SC("_OP_ARITH")}, + {_SC("_OP_BITW")}, + {_SC("_OP_RETURN")}, + {_SC("_OP_LOADNULLS")}, + {_SC("_OP_LOADROOTTABLE")}, + {_SC("_OP_DMOVE")}, + {_SC("_OP_JMP")}, + {_SC("_OP_JNZ")}, + {_SC("_OP_JZ")}, + {_SC("_OP_LOADFREEVAR")}, + {_SC("_OP_VARGC")}, + {_SC("_OP_GETVARGV")}, + {_SC("_OP_NEWTABLE")}, + {_SC("_OP_NEWARRAY")}, + {_SC("_OP_APPENDARRAY")}, + {_SC("_OP_GETPARENT")}, + {_SC("_OP_COMPARITH")}, + {_SC("_OP_COMPARITHL")}, + {_SC("_OP_INC")}, + {_SC("_OP_INCL")}, + {_SC("_OP_PINC")}, + {_SC("_OP_PINCL")}, + {_SC("_OP_CMP")}, + {_SC("_OP_EXISTS")}, + {_SC("_OP_INSTANCEOF")}, + {_SC("_OP_AND")}, + {_SC("_OP_OR")}, + {_SC("_OP_NEG")}, + {_SC("_OP_NOT")}, + {_SC("_OP_BWNOT")}, + {_SC("_OP_CLOSURE")}, + {_SC("_OP_YIELD")}, + {_SC("_OP_RESUME")}, + {_SC("_OP_FOREACH")}, + {_SC("_OP_DELEGATE")}, + {_SC("_OP_CLONE")}, + {_SC("_OP_TYPEOF")}, + {_SC("_OP_PUSHTRAP")}, + {_SC("_OP_POPTRAP")}, + {_SC("_OP_THROW")}, + {_SC("_OP_CLASS")}, + {_SC("_OP_NEWSLOTA")}, + {_SC("_OP_LOADBOOL")} +}; +#endif +void DumpLiteral(SQObjectPtr &o) +{ + switch(type(o)){ + case OT_STRING: scprintf(_SC("\"%s\""),_stringval(o));break; + case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break; + case OT_INTEGER: scprintf(_SC("{%d}"),_integer(o));break; + } +} + +SQFuncState::SQFuncState(SQSharedState *ss,SQFunctionProto *func,SQFuncState *parent) +{ + _nliterals = 0; + _literals = SQTable::Create(ss,0); + _sharedstate = ss; + _lastline = 0; + _optimization = true; + _func = func; + _parent = parent; + _stacksize = 0; + _traps = 0; + _returnexp = 0; + _varparams = false; +} + +#ifdef _DEBUG_DUMP +void SQFuncState::Dump() +{ + unsigned int n=0,i; + SQFunctionProto *func=_funcproto(_func); + scprintf(_SC("SQInstruction sizeof %d\n"),sizeof(SQInstruction)); + scprintf(_SC("SQObject sizeof %d\n"),sizeof(SQObject)); + scprintf(_SC("--------------------------------------------------------------------\n")); + scprintf(_SC("*****FUNCTION [%s]\n"),type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown")); + scprintf(_SC("-----LITERALS\n")); + SQObjectPtr refidx,key,val; + SQInteger idx; + SQObjectPtrVec templiterals; + templiterals.resize(_nliterals); + while((idx=_table(_literals)->Next(refidx,key,val))!=-1) { + refidx=idx; + templiterals[_integer(val)]=key; + } + for(i=0;i>\n")); + n=0; + for(i=0;i<_parameters.size();i++){ + scprintf(_SC("[%d] "),n); + DumpLiteral(_parameters[i]); + scprintf(_SC("\n")); + n++; + } + scprintf(_SC("-----LOCALS\n")); + for(i=0;i_localvarinfos.size();i++){ + SQLocalVarInfo lvi=func->_localvarinfos[i]; + scprintf(_SC("[%d] %s \t%d %d\n"),lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op); + n++; + } + scprintf(_SC("-----LINE INFO\n")); + for(i=0;i<_lineinfos.size();i++){ + SQLineInfo li=_lineinfos[i]; + scprintf(_SC("op [%d] line [%d] \n"),li._op,li._line); + n++; + } + scprintf(_SC("-----dump\n")); + n=0; + for(i=0;i<_instructions.size();i++){ + SQInstruction &inst=_instructions[i]; + if(inst.op==_OP_LOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){ + + int lidx = inst._arg1; + scprintf(_SC("[%03d] %15s %d "),n,g_InstrDesc[inst.op].name,inst._arg0); + if(lidx >= 0xFFFFFFFF) + scprintf(_SC("null")); + else { + int refidx; + SQObjectPtr val,key,refo; + while(((refidx=_table(_literals)->Next(refo,key,val))!= -1) && (_integer(val) != lidx)) { + refo = refidx; + } + DumpLiteral(key); + } + scprintf(_SC(" %d %d \n"),inst._arg2,inst._arg3); + } + else if(inst.op==_OP_ARITH){ + scprintf(_SC("[%03d] %15s %d %d %d %c\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); + } + else + scprintf(_SC("[%03d] %15s %d %d %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); + n++; + } + scprintf(_SC("-----\n")); + scprintf(_SC("stack size[%d]\n"),func->_stacksize); + scprintf(_SC("--------------------------------------------------------------------\n\n")); +} +#endif +int SQFuncState::GetStringConstant(const SQChar *cons) +{ + return GetConstant(SQString::Create(_sharedstate,cons)); +} + +int SQFuncState::GetNumericConstant(const SQInteger cons) +{ + return GetConstant(cons); +} + +int SQFuncState::GetNumericConstant(const SQFloat cons) +{ + return GetConstant(cons); +} + +int SQFuncState::GetConstant(SQObjectPtr cons) +{ + int n=0; + SQObjectPtr val; + if(!_table(_literals)->Get(cons,val)) + { + val = _nliterals; + _table(_literals)->NewSlot(cons,val); + _nliterals++; + if(_nliterals > MAX_LITERALS) throw ParserException(_SC("internal compiler error: too many literals")); + } + return _integer(val); +} + +void SQFuncState::SetIntructionParams(int pos,int arg0,int arg1,int arg2,int arg3) +{ + _instructions[pos]._arg0=*((unsigned int *)&arg0); + _instructions[pos]._arg1=*((unsigned int *)&arg1); + _instructions[pos]._arg2=*((unsigned int *)&arg2); + _instructions[pos]._arg3=*((unsigned int *)&arg3); +} + +void SQFuncState::SetIntructionParam(int pos,int arg,int val) +{ + switch(arg){ + case 0:_instructions[pos]._arg0=*((unsigned int *)&val);break; + case 1:_instructions[pos]._arg1=*((unsigned int *)&val);break; + case 2:_instructions[pos]._arg2=*((unsigned int *)&val);break; + case 3:_instructions[pos]._arg3=*((unsigned int *)&val);break; + case 4:_instructions[pos]._arg1=*((unsigned int *)&val);break; + }; +} + +int SQFuncState::AllocStackPos() +{ + int npos=_vlocals.size(); + _vlocals.push_back(SQLocalVarInfo()); + if(_vlocals.size()>((unsigned int)_stacksize)) { + if(_stacksize>MAX_FUNC_STACKSIZE) throw ParserException(_SC("internal compiler error: too many locals")); + _stacksize=_vlocals.size(); + } + return npos; +} + +int SQFuncState::PushTarget(int n) +{ + if(n!=-1){ + _targetstack.push_back(n); + return n; + } + n=AllocStackPos(); + _targetstack.push_back(n); + return n; +} + +int SQFuncState::GetUpTarget(int n){ + return _targetstack[((_targetstack.size()-1)-n)]; +} + +int SQFuncState::TopTarget(){ + return _targetstack.back(); +} +int SQFuncState::PopTarget() +{ + int npos=_targetstack.back(); + SQLocalVarInfo t=_vlocals[_targetstack.back()]; + if(type(t._name)==OT_NULL){ + _vlocals.pop_back(); + } + _targetstack.pop_back(); + return npos; +} + +int SQFuncState::GetStackSize() +{ + return _vlocals.size(); +} + +void SQFuncState::SetStackSize(int n) +{ + int size=_vlocals.size(); + while(size>n){ + size--; + SQLocalVarInfo lvi=_vlocals.back(); + if(type(lvi._name)!=OT_NULL){ + lvi._end_op=GetCurrentPos(); + _localvarinfos.push_back(lvi); + } + _vlocals.pop_back(); + } +} + +bool SQFuncState::IsLocal(unsigned int stkpos) +{ + if(stkpos>=_vlocals.size())return false; + else if(type(_vlocals[stkpos]._name)!=OT_NULL)return true; + return false; +} + +int SQFuncState::PushLocalVariable(const SQObjectPtr &name) +{ + int pos=_vlocals.size(); + SQLocalVarInfo lvi; + lvi._name=name; + lvi._start_op=GetCurrentPos()+1; + lvi._pos=_vlocals.size(); + _vlocals.push_back(lvi); + if(_vlocals.size()>((unsigned int)_stacksize))_stacksize=_vlocals.size(); + + return pos; +} + +int SQFuncState::GetLocalVariable(const SQObjectPtr &name) +{ + int locals=_vlocals.size(); + while(locals>=1){ + if(type(_vlocals[locals-1]._name)==OT_STRING && _string(_vlocals[locals-1]._name)==_string(name)){ + return locals-1; + } + locals--; + } + return -1; +} + +int SQFuncState::GetOuterVariable(const SQObjectPtr &name) +{ + int outers = _outervalues.size(); + for(int i = 0; iGetLocalVariable(name); + if(pos == -1) { + pos = _parent->GetOuterVariable(name); + if(pos != -1) { + _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local + return; + } + } + else { + _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local + return; + } + } + _outervalues.push_back(SQOuterVar(name,name,otSYMBOL)); //global +} + +void SQFuncState::AddParameter(const SQObjectPtr &name) +{ + PushLocalVariable(name); + _parameters.push_back(name); +} + +void SQFuncState::AddLineInfos(int line,bool lineop,bool force) +{ + if(_lastline!=line || force){ + SQLineInfo li; + li._line=line;li._op=(GetCurrentPos()+1); + if(lineop)AddInstruction(_OP_LINE,0,line); + _lineinfos.push_back(li); + _lastline=line; + } +} + +void SQFuncState::AddInstruction(SQInstruction &i) +{ + int size = _instructions.size(); + if(size > 0 && _optimization){ //simple optimizer + SQInstruction &pi = _instructions[size-1];//previous instruction + switch(i.op) { + case _OP_RETURN: + if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) { + pi.op = _OP_TAILCALL; + } + break; + case _OP_GET: + if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){ + pi._arg1 = pi._arg1; + pi._arg2 = (unsigned char)i._arg1; + pi.op = _OP_GETK; + pi._arg0 = i._arg0; + + return; + } + break; + case _OP_PREPCALL: + if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ + pi.op = _OP_PREPCALLK; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = i._arg2; + pi._arg3 = i._arg3; + return; + } + break; + case _OP_APPENDARRAY: + if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ + pi.op = _OP_APPENDARRAY; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = MAX_FUNC_STACKSIZE; + pi._arg3 = MAX_FUNC_STACKSIZE; + return; + } + break; + case _OP_MOVE: + if((pi.op == _OP_GET || pi.op == _OP_ARITH || pi.op == _OP_BITW) && (pi._arg0 == i._arg1)) + { + pi._arg0 = i._arg0; + _optimization = false; + return; + } + + if(pi.op == _OP_MOVE) + { + pi.op = _OP_DMOVE; + pi._arg2 = i._arg0; + pi._arg3 = (unsigned char)i._arg1; + return; + } + break; + + case _OP_EQ:case _OP_NE: + if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) )) + { + pi.op = i.op; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = i._arg2; + pi._arg3 = MAX_FUNC_STACKSIZE; + return; + } + break; + case _OP_LOADNULLS: + //case _OP_LOADNULL: + if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) { + + pi._arg1 = pi._arg1 + 1; + pi.op = _OP_LOADNULLS; + return; + } + break; + case _OP_LINE: + if(pi.op == _OP_LINE) { + _instructions.pop_back(); + _lineinfos.pop_back(); + } + break; + } + } + _optimization = true; + _instructions.push_back(i); +} + +SQObject SQFuncState::CreateString(const SQChar *s) +{ + SQObjectPtr ns(SQString::Create(_sharedstate,s)); + _stringrefs.push_back(ns); + return ns; +} + +void SQFuncState::Finalize() +{ + SQFunctionProto *f=_funcproto(_func); + f->_literals.resize(_nliterals); + SQObjectPtr refidx,key,val; + SQInteger idx; + while((idx=_table(_literals)->Next(refidx,key,val))!=-1) { + f->_literals[_integer(val)]=key; + refidx=idx; + } + f->_functions.resize(_functions.size()); + f->_functions.copy(_functions); + f->_parameters.resize(_parameters.size()); + f->_parameters.copy(_parameters); + f->_outervalues.resize(_outervalues.size()); + f->_outervalues.copy(_outervalues); + f->_instructions.resize(_instructions.size()); + f->_instructions.copy(_instructions); + f->_localvarinfos.resize(_localvarinfos.size()); + f->_localvarinfos.copy(_localvarinfos); + f->_lineinfos.resize(_lineinfos.size()); + f->_lineinfos.copy(_lineinfos); + f->_varparams = _varparams; +} diff --git a/src/squirrel/squirrel/sqfuncstate.h b/src/squirrel/squirrel/sqfuncstate.h new file mode 100644 index 000000000..d35e963a9 --- /dev/null +++ b/src/squirrel/squirrel/sqfuncstate.h @@ -0,0 +1,74 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQFUNCSTATE_H_ +#define _SQFUNCSTATE_H_ +/////////////////////////////////// +#include "squtils.h" + + + +struct SQFuncState +{ + SQFuncState(SQSharedState *ss,SQFunctionProto *func,SQFuncState *parent); +#ifdef _DEBUG_DUMP + void Dump(); +#endif + void AddInstruction(SQOpcode _op,int arg0=0,int arg1=0,int arg2=0,int arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);} + void AddInstruction(SQInstruction &i); + void SetIntructionParams(int pos,int arg0,int arg1,int arg2=0,int arg3=0); + void SetIntructionParam(int pos,int arg,int val); + SQInstruction &GetInstruction(int pos){return _instructions[pos];} + void PopInstructions(int size){for(int i=0;i +#include +#include "sqtable.h" +#include "sqstring.h" +#include "sqcompiler.h" +#include "sqlexer.h" + +#define CUR_CHAR (_currdata) +#define RETURN_TOKEN(t) { _prevtoken = _curtoken; _curtoken = t; return t;} +#define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB) +#define NEXT() {Next();_currentcolumn++;} +#define INIT_TEMP_STRING() { _longstr.resize(0);} +#define APPEND_CHAR(c) { _longstr.push_back(c);} +#define TERMINATE_BUFFER() {_longstr.push_back(_SC('\0'));} +#define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, _SC(#key)) ,SQInteger(id)) + +SQLexer::SQLexer(){} +SQLexer::~SQLexer() +{ + _keywords->Release(); +} + +void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up) +{ + _sharedstate = ss; + _keywords = SQTable::Create(ss, 26); + ADD_KEYWORD(while, TK_WHILE); + ADD_KEYWORD(do, TK_DO); + ADD_KEYWORD(if, TK_IF); + ADD_KEYWORD(else, TK_ELSE); + ADD_KEYWORD(break, TK_BREAK); + ADD_KEYWORD(continue, TK_CONTINUE); + ADD_KEYWORD(return, TK_RETURN); + ADD_KEYWORD(null, TK_NULL); + ADD_KEYWORD(function, TK_FUNCTION); + ADD_KEYWORD(local, TK_LOCAL); + ADD_KEYWORD(for, TK_FOR); + ADD_KEYWORD(foreach, TK_FOREACH); + ADD_KEYWORD(in, TK_IN); + ADD_KEYWORD(typeof, TK_TYPEOF); + ADD_KEYWORD(delegate, TK_DELEGATE); + ADD_KEYWORD(delete, TK_DELETE); + ADD_KEYWORD(try, TK_TRY); + ADD_KEYWORD(catch, TK_CATCH); + ADD_KEYWORD(throw, TK_THROW); + ADD_KEYWORD(clone, TK_CLONE); + ADD_KEYWORD(yield, TK_YIELD); + ADD_KEYWORD(resume, TK_RESUME); + ADD_KEYWORD(switch, TK_SWITCH); + ADD_KEYWORD(case, TK_CASE); + ADD_KEYWORD(default, TK_DEFAULT); + ADD_KEYWORD(this, TK_THIS); + ADD_KEYWORD(parent,TK_PARENT); + ADD_KEYWORD(class,TK_CLASS); + ADD_KEYWORD(extends,TK_EXTENDS); + ADD_KEYWORD(constructor,TK_CONSTRUCTOR); + ADD_KEYWORD(instanceof,TK_INSTANCEOF); + ADD_KEYWORD(vargc,TK_VARGC); + ADD_KEYWORD(vargv,TK_VARGV); + ADD_KEYWORD(true,TK_TRUE); + ADD_KEYWORD(false,TK_FALSE); + + _readf = rg; + _up = up; + _lasttokenline = _currentline = 1; + _currentcolumn = 0; + _prevtoken = -1; + Next(); +} + +void SQLexer::Next() +{ + SQInteger t = _readf(_up); + if(t > MAX_CHAR) throw ParserException(_SC("Invalid character")); + if(t != 0) { + _currdata = t; + return; + } + _currdata = SQUIRREL_EOB; +} + +SQObjectPtr SQLexer::Tok2Str(int tok) +{ + SQObjectPtr itr, key, val; + int nitr; + while((nitr = _keywords->Next(itr, key, val)) != -1) { + itr = (SQInteger)nitr; + if(((int)_integer(val)) == tok) + return key; + } + return SQObjectPtr(); +} + +void SQLexer::LexBlockComment() +{ + bool done = false; + while(!done) { + switch(CUR_CHAR) { + case _SC('*'): { NEXT(); if(CUR_CHAR == _SC('/')) { done = true; NEXT(); }}; continue; + //case _SC('/'): { NEXT(); if(CUR_CHAR == _SC('*')) { nest++; NEXT(); }}; continue; + case _SC('\n'): _currentline++; NEXT(); continue; + case SQUIRREL_EOB: throw ParserException(_SC("missing \"*/\" in comment")); + default: NEXT(); + } + } +} + +int SQLexer::Lex() +{ + _lasttokenline = _currentline; + while(CUR_CHAR != SQUIRREL_EOB) { + switch(CUR_CHAR){ + case _SC('\t'): case _SC('\r'): case _SC(' '): NEXT(); continue; + case _SC('\n'): + _currentline++; + _prevtoken=_curtoken; + _curtoken=_SC('\n'); + NEXT(); + _currentcolumn=1; + continue; + case _SC('/'): + NEXT(); + switch(CUR_CHAR){ + case _SC('*'): + NEXT(); + LexBlockComment(); + continue; + case _SC('/'): + do { NEXT(); } while (CUR_CHAR != _SC('\n') && (!IS_EOB())); + continue; + case _SC('='): + NEXT(); + RETURN_TOKEN(TK_DIVEQ); + continue; + case _SC('>'): + NEXT(); + RETURN_TOKEN(TK_ATTR_CLOSE); + continue; + default: + RETURN_TOKEN('/'); + } + case _SC('='): + NEXT(); + if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('=') } + else { NEXT(); RETURN_TOKEN(TK_EQ); } + case _SC('<'): + NEXT(); + if ( CUR_CHAR == _SC('=') ) { NEXT(); RETURN_TOKEN(TK_LE) } + else if ( CUR_CHAR == _SC('-') ) { NEXT(); RETURN_TOKEN(TK_NEWSLOT); } + else if ( CUR_CHAR == _SC('<') ) { NEXT(); RETURN_TOKEN(TK_SHIFTL); } + else if ( CUR_CHAR == _SC('/') ) { NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); } + //else if ( CUR_CHAR == _SC('[') ) { NEXT(); ReadMultilineString(); RETURN_TOKEN(TK_STRING_LITERAL); } + else { RETURN_TOKEN('<') } + case _SC('>'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_GE);} + else if(CUR_CHAR == _SC('>')){ + NEXT(); + if(CUR_CHAR == _SC('>')){ + NEXT(); + RETURN_TOKEN(TK_USHIFTR); + } + RETURN_TOKEN(TK_SHIFTR); + } + else { RETURN_TOKEN('>') } + case _SC('!'): + NEXT(); + if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('!')} + else { NEXT(); RETURN_TOKEN(TK_NE); } + case _SC('@'): { + int stype; + NEXT(); + if(CUR_CHAR != _SC('"')) + throw ParserException(_SC("string expected")); + if((stype=ReadString('"',true))!=-1) { + RETURN_TOKEN(stype); + } + throw ParserException(_SC("error parsing the string")); + } + case _SC('"'): + case _SC('\''): { + int stype; + if((stype=ReadString(CUR_CHAR,false))!=-1){ + RETURN_TOKEN(stype); + } + throw ParserException(_SC("error parsing the string")); + } + case _SC('{'): case _SC('}'): case _SC('('): case _SC(')'): case _SC('['): case _SC(']'): + case _SC(';'): case _SC(','): case _SC('?'): case _SC('^'): case _SC('~'): + {int ret = CUR_CHAR; + NEXT(); RETURN_TOKEN(ret); } + case _SC('.'): + NEXT(); + if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') } + NEXT(); + if (CUR_CHAR != _SC('.')){ throw ParserException(_SC("invalid token '..'")); } + NEXT(); + RETURN_TOKEN(TK_VARPARAMS); + case _SC('&'): + NEXT(); + if (CUR_CHAR != _SC('&')){ RETURN_TOKEN('&') } + else { NEXT(); RETURN_TOKEN(TK_AND); } + case _SC('|'): + NEXT(); + if (CUR_CHAR != _SC('|')){ RETURN_TOKEN('|') } + else { NEXT(); RETURN_TOKEN(TK_OR); } + case _SC(':'): + NEXT(); + if (CUR_CHAR != _SC(':')){ RETURN_TOKEN(':') } + else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); } + case _SC('*'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MULEQ);} + else RETURN_TOKEN('*'); + case _SC('%'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MODEQ);} + else RETURN_TOKEN('%'); + case _SC('-'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);} + else if (CUR_CHAR == _SC('-')){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);} + else RETURN_TOKEN('-'); + case _SC('+'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);} + else if (CUR_CHAR == _SC('+')){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);} + else RETURN_TOKEN('+'); + case SQUIRREL_EOB: + return 0; + default:{ + if (scisdigit(CUR_CHAR)) { + int ret = ReadNumber(); + RETURN_TOKEN(ret); + } + else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) { + int t = ReadID(); + RETURN_TOKEN(t); + } + else { + int c = CUR_CHAR; + if (sciscntrl(c)) throw ParserException(_SC("unexpected character(control)")); + NEXT(); + RETURN_TOKEN(c); + } + RETURN_TOKEN(0); + } + } + } + return 0; +} + +int SQLexer::GetIDType(SQChar *s) +{ + SQObjectPtr t; + if(_keywords->Get(SQString::Create(_sharedstate, s), t)) { + return int(_integer(t)); + } + return TK_IDENTIFIER; +} + + +int SQLexer::ReadString(int ndelim,bool verbatim) +{ + INIT_TEMP_STRING(); + NEXT(); + if(IS_EOB()) return -1; + for(;;) { + while(CUR_CHAR != ndelim) { + switch(CUR_CHAR) { + case SQUIRREL_EOB: + throw ParserException(_SC("unfinished string")); + return -1; + case _SC('\n'): + if(!verbatim) throw ParserException(_SC("newline in a constant")); + APPEND_CHAR(CUR_CHAR); NEXT(); + break; + case _SC('\\'): + if(verbatim) { + APPEND_CHAR('\\'); NEXT(); + } + else { + + NEXT(); + switch(CUR_CHAR) { + case _SC('t'): APPEND_CHAR(_SC('\t')); NEXT(); break; + case _SC('a'): APPEND_CHAR(_SC('\a')); NEXT(); break; + case _SC('b'): APPEND_CHAR(_SC('\b')); NEXT(); break; + case _SC('n'): APPEND_CHAR(_SC('\n')); NEXT(); break; + case _SC('r'): APPEND_CHAR(_SC('\r')); NEXT(); break; + case _SC('v'): APPEND_CHAR(_SC('\v')); NEXT(); break; + case _SC('f'): APPEND_CHAR(_SC('\f')); NEXT(); break; + case _SC('0'): APPEND_CHAR(_SC('\0')); NEXT(); break; + case _SC('\\'): APPEND_CHAR(_SC('\\')); NEXT(); break; + case _SC('"'): APPEND_CHAR(_SC('"')); NEXT(); break; + case _SC('\''): APPEND_CHAR(_SC('\'')); NEXT(); break; + default: + throw ParserException(_SC("unrecognised escaper char")); + break; + } + } + break; + default: + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + } + NEXT(); + if(verbatim && CUR_CHAR == '"') { //double quotation + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + else { + break; + } + } + TERMINATE_BUFFER(); + int len = _longstr.size()-1; + if(ndelim == _SC('\'')) { + if(len == 0) throw ParserException(_SC("empty constant")); + if(len > 1) throw ParserException(_SC("constant too long")); + _nvalue = _longstr[0]; + return TK_INTEGER; + } + _svalue = &_longstr[0]; + return TK_STRING_LITERAL; +} + +int isexponent(int c) { return c == 'e' || c=='E'; } + +int SQLexer::ReadNumber() +{ +#define TINT 1 +#define TFLOAT 2 +#define THEX 3 +#define TSCIENTIFIC 4 + int type = TINT, firstchar = CUR_CHAR; + bool isfloat = false; + SQChar *sTemp; + INIT_TEMP_STRING(); + NEXT(); + if(firstchar == _SC('0') && toupper(CUR_CHAR) == _SC('X')) { + NEXT(); + type = THEX; + while(isxdigit(CUR_CHAR)) { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(_longstr.size() > 8) throw ParserException(_SC("Hex number over 8 digits")); + } + else { + APPEND_CHAR(firstchar); + while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) { + if(CUR_CHAR == _SC('.')) type = TFLOAT; + if(isexponent(CUR_CHAR)) { + if(type != TFLOAT) throw ParserException(_SC("invalid numeric format")); + type = TSCIENTIFIC; + APPEND_CHAR(CUR_CHAR); + NEXT(); + if(CUR_CHAR == '+' || CUR_CHAR == '-'){ + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(!scisdigit(CUR_CHAR)) throw ParserException(_SC("exponent expected")); + } + + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + } + TERMINATE_BUFFER(); + switch(type) { + case TSCIENTIFIC: + case TFLOAT: + _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp); + return TK_FLOAT; + case TINT: + _nvalue = (SQInteger)scatoi(&_longstr[0]); + return TK_INTEGER; + case THEX: + *((unsigned long *)&_nvalue) = scstrtoul(&_longstr[0],&sTemp,16); + return TK_INTEGER; + } + return 0; +} + +int SQLexer::ReadID() +{ + int res, size = 0; + INIT_TEMP_STRING(); + do { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_')); + TERMINATE_BUFFER(); + res = GetIDType(&_longstr[0]); + if(res == TK_IDENTIFIER) { + _svalue = &_longstr[0]; + } + return res; +} diff --git a/src/squirrel/squirrel/sqlexer.h b/src/squirrel/squirrel/sqlexer.h new file mode 100644 index 000000000..3f13c6be4 --- /dev/null +++ b/src/squirrel/squirrel/sqlexer.h @@ -0,0 +1,42 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQLEXER_H_ +#define _SQLEXER_H_ + +#define MAX_STRING 2024 + +struct SQLexer +{ + SQLexer(); + ~SQLexer(); + void Init(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up); + int Lex(); + SQObjectPtr Tok2Str(int tok); +private: + int GetIDType(SQChar *s); + int ReadString(int ndelim,bool verbatim); + int ReadNumber(); + void LexBlockComment(); + int ReadID(); + void Next(); + int _curtoken; + SQTable *_keywords; +public: + int _prevtoken; + int _currentline; + int _lasttokenline; + int _currentcolumn; + const SQChar *_svalue; + SQInteger _nvalue; + SQFloat _fvalue; + SQLEXREADFUNC _readf; + SQUserPointer _up; +#ifdef _UNICODE + SQChar _currdata; +#else + unsigned char _currdata; +#endif + SQSharedState *_sharedstate; + sqvector _longstr; +}; + +#endif diff --git a/src/squirrel/squirrel/sqmem.cpp b/src/squirrel/squirrel/sqmem.cpp new file mode 100644 index 000000000..f85c887f0 --- /dev/null +++ b/src/squirrel/squirrel/sqmem.cpp @@ -0,0 +1,9 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +void *sq_vm_malloc(unsigned int size){ return malloc(size); } + +void *sq_vm_realloc(void *p, unsigned int oldsize, unsigned int size){ return realloc(p, size); } + +void sq_vm_free(void *p, unsigned int size){ free(p); } diff --git a/src/squirrel/squirrel/sqobject.cpp b/src/squirrel/squirrel/sqobject.cpp new file mode 100644 index 000000000..cf5aa8e71 --- /dev/null +++ b/src/squirrel/squirrel/sqobject.cpp @@ -0,0 +1,464 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqarray.h" +#include "sqtable.h" +#include "squserdata.h" +#include "sqfuncproto.h" +#include "sqclass.h" +#include "sqclosure.h" + +SQString *SQString::Create(SQSharedState *ss,const SQChar *s,int len) +{ + SQString *str=ADD_STRING(ss,s,len); + str->_sharedstate=ss; + return str; +} + +void SQString::Release() +{ + REMOVE_STRING(_sharedstate,this); +} + +unsigned int TranslateIndex(const SQObjectPtr &idx) +{ + switch(type(idx)){ + case OT_NULL: + return 0; + case OT_INTEGER: + return (unsigned int)_integer(idx); + } + assert(0); + return 0; +} + +bool SQDelegable::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res) { + if(_delegate) { + return _delegate->Get((*_ss(this)->_metamethods)[mm],res); + } + return false; +} + +bool SQGenerator::Yield(SQVM *v) +{ + if(_state==eSuspended) { v->Raise_Error(_SC("internal vm error, yielding dead generator")); return false;} + if(_state==eDead) { v->Raise_Error(_SC("internal vm error, yielding a dead generator")); return false; } + int size = v->_top-v->_stackbase; + _ci=*v->ci; + _stack.resize(size); + for(int n =0; n_stack[v->_stackbase+n]; + v->_stack[v->_stackbase+n] = _null_; + } + int nvargs = v->ci->_vargs.size; + int vargsbase = v->ci->_vargs.base; + for(int j = nvargs - 1; j >= 0; j--) { + _vargsstack.push_back(v->_vargsstack[vargsbase+j]); + } + _ci._generator=_null_; + for(int i=0;i<_ci._etraps;i++) { + _etraps.push_back(v->_etraps.top()); + v->_etraps.pop_back(); + } + _state=eSuspended; + return true; +} + +bool SQGenerator::Resume(SQVM *v,int target) +{ + int size=_stack.size(); + if(_state==eDead){ v->Raise_Error(_SC("resuming dead generator")); return false; } + if(_state==eRunning){ v->Raise_Error(_SC("resuming active generator")); return false; } + int prevtop=v->_top-v->_stackbase; + PUSH_CALLINFO(v,_ci); + int oldstackbase=v->_stackbase; + v->_stackbase=v->_top; + v->ci->_target=target; + v->ci->_generator=SQObjectPtr(this); + v->ci->_vargs.size = _vargsstack.size(); + + for(int i=0;i<_ci._etraps;i++) { + v->_etraps.push_back(_etraps.top()); + _etraps.pop_back(); + } + for(int n =0; n_stack[v->_stackbase+n] = _stack._vals[n]; + _stack._vals[0] = _null_; + } + while(_vargsstack.size()) { + v->_vargsstack.push_back(_vargsstack.back()); + _vargsstack.pop_back(); + } + v->ci->_vargs.base = v->_vargsstack.size() - v->ci->_vargs.size; + v->_top=v->_stackbase+size; + v->ci->_prevtop=prevtop; + v->ci->_prevstkbase=v->_stackbase-oldstackbase; + _state=eRunning; + return true; +} + +void SQArray::Extend(const SQArray *a){ + int xlen; + if((xlen=a->Size())) + for(int i=0;i_values[i]); +} + +const SQChar* SQFunctionProto::GetLocal(SQVM *vm,unsigned int stackbase,unsigned int nseq,unsigned int nop) +{ + unsigned int nvars=_localvarinfos.size(); + const SQChar *res=NULL; + if(nvars>=nseq){ + for(unsigned int i=0;i=nop) + { + if(nseq==0){ + vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]); + res=_stringval(_localvarinfos[i]._name); + break; + } + nseq--; + } + } + } + return res; +} + +int SQFunctionProto::GetLine(SQInstruction *curr) +{ + int op=(curr-_instructions._vals); + int line=_lineinfos[0]._line; + for(unsigned int i=1;i<_lineinfos.size();i++){ + if(_lineinfos[i]._op>=op) + return line; + line=_lineinfos[i]._line; + } + return line; +} + +//#define _ERROR_TRAP() error_trap: +#define _CHECK_IO(exp) { if(!exp)return false; } +bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,int size) +{ + if(write(up,dest,size) != size) { + v->Raise_Error(_SC("io error (write function failure)")); + return false; + } + return true; +} + +bool SafeRead(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUserPointer dest,int size) +{ + if(size && read(up,dest,size) != size) { + v->Raise_Error(_SC("io error, read function failure, the origin stream could be corrupted/trucated")); + return false; + } + return true; +} + +bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,int tag) +{ + return SafeWrite(v,write,up,&tag,sizeof(tag)); +} + +bool CheckTag(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,int tag) +{ + int t; + _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t))); + if(t != tag){ + v->Raise_Error(_SC("invalid or corrupted closure stream")); + return false; + } + return true; +} + +bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o) +{ + _CHECK_IO(SafeWrite(v,write,up,&type(o),sizeof(SQObjectType))); + switch(type(o)){ + case OT_STRING: + _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger))); + _CHECK_IO(SafeWrite(v,write,up,_stringval(o),rsl(_string(o)->_len))); + break; + case OT_INTEGER: + _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break; + case OT_FLOAT: + _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break; + case OT_NULL: + break; + default: + v->Raise_Error(_SC("cannot serialize a %s"),GetTypeName(o)); + return false; + } + return true; +} + +bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o) +{ + SQObjectType t; + _CHECK_IO(SafeRead(v,read,up,&t,sizeof(SQObjectType))); + switch(t){ + case OT_STRING:{ + int len; + _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger))); + _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(rsl(len)),rsl(len))); + o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len); + } + break; + case OT_INTEGER:{ + SQInteger i; + _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break; + } + case OT_FLOAT:{ + SQFloat f; + _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break; + } + case OT_NULL: + o=_null_; + break; + default: + v->Raise_Error(_SC("cannot serialize a %s"),IdType2Name(t)); + return false; + } + return true; +} + +bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) +{ + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD)); + _CHECK_IO(WriteTag(v,write,up,sizeof(SQChar))); + _CHECK_IO(_funcproto(_function)->Save(v,up,write)); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL)); + return true; +} + +bool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read) +{ + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD)); + _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar))); + _CHECK_IO(_funcproto(_function)->Load(v,up,read)); + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL)); + return true; +} + +bool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) +{ + int i,nsize=_literals.size(); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(WriteObject(v,up,write,_sourcename)); + _CHECK_IO(WriteObject(v,up,write,_name)); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeWrite(v,write,up,&nsize,sizeof(nsize))); + for(i=0;iSave(v,up,write)); + } + _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize))); + _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator))); + _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams))); + return true; +} + +bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read) +{ + int i, nsize = _literals.size(); + SQObjectPtr o; + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(ReadObject(v, up, read, _sourcename)); + _CHECK_IO(ReadObject(v, up, read, _name)); + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); + for(i = 0;i < nsize; i++){ + _CHECK_IO(ReadObject(v, up, read, o)); + _literals.push_back(o); + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); + for(i = 0; i < nsize; i++){ + _CHECK_IO(ReadObject(v, up, read, o)); + _parameters.push_back(o); + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up,&nsize,sizeof(nsize))); + for(i = 0; i < nsize; i++){ + unsigned int type; + SQObjectPtr name; + _CHECK_IO(SafeRead(v,read,up, &type, sizeof(unsigned int))); + _CHECK_IO(ReadObject(v, up, read, o)); + _CHECK_IO(ReadObject(v, up, read, name)); + _outervalues.push_back(SQOuterVar(name,o, (SQOuterType)type)); + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up,&nsize, sizeof(nsize))); + for(i = 0; i < nsize; i++){ + SQLocalVarInfo lvi; + _CHECK_IO(ReadObject(v, up, read, lvi._name)); + _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(unsigned int))); + _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(unsigned int))); + _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(unsigned int))); + _localvarinfos.push_back(lvi); + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nsize,sizeof(nsize))); + _lineinfos.resize(nsize); + _CHECK_IO(SafeRead(v,read,up, &_lineinfos[0], sizeof(SQLineInfo)*nsize)); + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); + _instructions.resize(nsize); + _CHECK_IO(SafeRead(v,read,up, &_instructions[0], sizeof(SQInstruction)*nsize)); + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nsize, sizeof(nsize))); + for(i = 0; i < nsize; i++){ + o = SQFunctionProto::Create(); + _CHECK_IO(_funcproto(o)->Load(v, up, read)); + _functions.push_back(o); + } + _CHECK_IO(SafeRead(v,read,up, &_stacksize, sizeof(_stacksize))); + _CHECK_IO(SafeRead(v,read,up, &_bgenerator, sizeof(_bgenerator))); + _CHECK_IO(SafeRead(v,read,up, &_varparams, sizeof(_varparams))); + return true; +} + +#ifndef NO_GARBAGE_COLLECTOR + +#define START_MARK() if(!(_uiRef&MARK_FLAG)){ \ + _uiRef|=MARK_FLAG; + +#define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \ + AddToChain(chain, this); } + +void SQVM::Mark(SQCollectable **chain) +{ + START_MARK() + SQSharedState::MarkObject(_lasterror,chain); + SQSharedState::MarkObject(_errorhandler,chain); + SQSharedState::MarkObject(_debughook,chain); + SQSharedState::MarkObject(_roottable, chain); + SQSharedState::MarkObject(temp_reg, chain); + for(unsigned int i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); + for(unsigned int j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); + END_MARK() +} + +void SQArray::Mark(SQCollectable **chain) +{ + START_MARK() + int len = _values.size(); + for(int i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain); + END_MARK() +} +void SQTable::Mark(SQCollectable **chain) +{ + START_MARK() + if(_delegate) _delegate->Mark(chain); + int len = _numofnodes; + for(int i = 0; i < len; i++){ + SQSharedState::MarkObject(_nodes[i].key, chain); + SQSharedState::MarkObject(_nodes[i].val, chain); + } + END_MARK() +} + +void SQClass::Mark(SQCollectable **chain) +{ + START_MARK() + _members->Mark(chain); + if(_base) _base->Mark(chain); + SQSharedState::MarkObject(_attributes, chain); + for(unsigned int i =0; i< _defaultvalues.size(); i++) { + SQSharedState::MarkObject(_defaultvalues[i].val, chain); + SQSharedState::MarkObject(_defaultvalues[i].attrs, chain); + } + for(unsigned int j =0; j< _methods.size(); j++) { + SQSharedState::MarkObject(_methods[j].val, chain); + SQSharedState::MarkObject(_methods[j].attrs, chain); + } + for(unsigned int k =0; k< _metamethods.size(); k++) { + SQSharedState::MarkObject(_metamethods[k], chain); + } + END_MARK() +} + +void SQInstance::Mark(SQCollectable **chain) +{ + START_MARK() + _class->Mark(chain); + for(unsigned int i =0; i< _values.size(); i++) { + SQSharedState::MarkObject(_values[i], chain); + } + END_MARK() +} + +void SQGenerator::Mark(SQCollectable **chain) +{ + START_MARK() + for(unsigned int i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); + for(unsigned int j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); + SQSharedState::MarkObject(_closure, chain); + END_MARK() +} + +void SQClosure::Mark(SQCollectable **chain) +{ + START_MARK() + for(unsigned int i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); + END_MARK() +} + +void SQNativeClosure::Mark(SQCollectable **chain) +{ + START_MARK() + for(unsigned int i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); + END_MARK() +} + +void SQUserData::Mark(SQCollectable **chain){ + START_MARK() + if(_delegate) _delegate->Mark(chain); + END_MARK() +} + +void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; } + +#endif + diff --git a/src/squirrel/squirrel/sqobject.h b/src/squirrel/squirrel/sqobject.h new file mode 100644 index 000000000..8c900b7d7 --- /dev/null +++ b/src/squirrel/squirrel/sqobject.h @@ -0,0 +1,304 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQOBJECT_H_ +#define _SQOBJECT_H_ + +#include "squtils.h" + +#define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R')) +#define SQ_CLOSURESTREAM_PART (('P'<<24)|('A'<<16)|('R'<<8)|('T')) +#define SQ_CLOSURESTREAM_TAIL (('T'<<24)|('A'<<16)|('I'<<8)|('L')) + +#define SQ_TRY try +#define SQ_CATCH(type, ex) catch(type &ex) + +struct SQSharedState; + +enum SQMetaMethod{ + MT_ADD=0, + MT_SUB=1, + MT_MUL=2, + MT_DIV=3, + MT_UNM=4, + MT_MODULO=5, + MT_SET=6, + MT_GET=7, + MT_TYPEOF=8, + MT_NEXTI=9, + MT_CMP=10, + MT_CALL=11, + MT_CLONED=12, + MT_NEWSLOT=13, + MT_DELSLOT=14, + MT_LAST = 15, +}; + +#define MM_ADD _SC("_add") +#define MM_SUB _SC("_sub") +#define MM_MUL _SC("_mul") +#define MM_DIV _SC("_div") +#define MM_UNM _SC("_unm") +#define MM_MODULO _SC("_modulo") +#define MM_SET _SC("_set") +#define MM_GET _SC("_get") +#define MM_TYPEOF _SC("_typeof") +#define MM_NEXTI _SC("_nexti") +#define MM_CMP _SC("_cmp") +#define MM_CALL _SC("_call") +#define MM_CLONED _SC("_cloned") +#define MM_NEWSLOT _SC("_newslot") +#define MM_DELSLOT _SC("_delslot") + +#define MINPOWER2 4 + +struct SQRefCounted +{ + virtual ~SQRefCounted() {} + + unsigned int _uiRef; + virtual void Release()=0; +}; + +struct SQObjectPtr; + +#define __AddRef(type,unval) if(ISREFCOUNTED(type)) \ + { \ + unval.pRefCounted->_uiRef++; \ + } + +#define __Release(type,unval) if(ISREFCOUNTED(type) && ((--unval.pRefCounted->_uiRef)<=0)) \ + { \ + unval.pRefCounted->Release(); \ + } + +#define __ObjRelease(obj) { \ + if((obj)) { \ + (obj)->_uiRef--; \ + if((obj)->_uiRef == 0) \ + (obj)->Release(); \ + (obj) = NULL; \ + } \ +} + +#define __ObjAddRef(obj) { \ + (obj)->_uiRef++; \ +} + +#define type(obj) ((obj)._type) +#define is_delegable(t) (type(t)&SQOBJECT_DELEGABLE) +#define raw_type(obj) _RAW_TYPE((obj)._type) + +#define _integer(obj) ((obj)._unVal.nInteger) +#define _float(obj) ((obj)._unVal.fFloat) +#define _string(obj) ((obj)._unVal.pString) +#define _table(obj) ((obj)._unVal.pTable) +#define _array(obj) ((obj)._unVal.pArray) +#define _closure(obj) ((obj)._unVal.pClosure) +#define _generator(obj) ((obj)._unVal.pGenerator) +#define _nativeclosure(obj) ((obj)._unVal.pNativeClosure) +#define _userdata(obj) ((obj)._unVal.pUserData) +#define _userpointer(obj) ((obj)._unVal.pUserPointer) +#define _thread(obj) ((obj)._unVal.pThread) +#define _funcproto(obj) ((obj)._unVal.pFunctionProto) +#define _class(obj) ((obj)._unVal.pClass) +#define _instance(obj) ((obj)._unVal.pInstance) +#define _delegable(obj) ((SQDelegable *)(obj)._unVal.pDelegable) +#define _rawval(obj) ((obj)._unVal.pRefCounted) + +#define _stringval(obj) (obj)._unVal.pString->_val +#define _userdataval(obj) (obj)._unVal.pUserData->_val + +#define tofloat(num) ((type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num)) +#define tointeger(num) ((type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num)) +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +struct SQObjectPtr : public SQObject +{ + SQObjectPtr() + { + _type=OT_NULL; + _unVal.pUserPointer=NULL; + } + SQObjectPtr(const SQObjectPtr &o) + { + _type=o._type; + _unVal=o._unVal; + __AddRef(_type,_unVal); + } + SQObjectPtr(const SQObject &o) + { + _type=o._type; + _unVal=o._unVal; + __AddRef(_type,_unVal); + } + SQObjectPtr(SQTable *pTable) + { + _type=OT_TABLE; + _unVal.pTable=pTable; + assert(_unVal.pTable); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQClass *pClass) + { + _type=OT_CLASS; + _unVal.pClass=pClass; + assert(_unVal.pClass); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQInstance *pInstance) + { + _type=OT_INSTANCE; + _unVal.pInstance=pInstance; + assert(_unVal.pInstance); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQArray *pArray) + { + _type=OT_ARRAY; + _unVal.pArray=pArray; + assert(_unVal.pArray); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQClosure *pClosure) + { + _type=OT_CLOSURE; + _unVal.pClosure=pClosure; + assert(_unVal.pClosure); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQGenerator *pGenerator) + { + _type=OT_GENERATOR; + _unVal.pGenerator=pGenerator; + assert(_unVal.pGenerator); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQNativeClosure *pNativeClosure) + { + _type=OT_NATIVECLOSURE; + _unVal.pNativeClosure=pNativeClosure; + assert(_unVal.pNativeClosure); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQString *pString) + { + _type=OT_STRING; + _unVal.pString=pString; + assert(_unVal.pString); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQUserData *pUserData) + { + _type=OT_USERDATA; + _unVal.pUserData=pUserData; + assert(_unVal.pUserData); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQVM *pThread) + { + _type=OT_THREAD; + _unVal.pThread=pThread; + assert(_unVal.pThread); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQFunctionProto *pFunctionProto) + { + _type=OT_FUNCPROTO; + _unVal.pFunctionProto=pFunctionProto; + assert(_unVal.pFunctionProto); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQInteger nInteger) + { + _type=OT_INTEGER; + _unVal.nInteger=nInteger; + } + SQObjectPtr(SQFloat fFloat) + { + _type=OT_FLOAT; + _unVal.fFloat=fFloat; + } + SQObjectPtr(bool bBool) + { + _type = OT_BOOL; + _unVal.nInteger = bBool?1:0; + } + SQObjectPtr(SQUserPointer pUserPointer) + { + _type=OT_USERPOINTER; + _unVal.pUserPointer=pUserPointer; + } + ~SQObjectPtr() + { + __Release(_type,_unVal); + } + void Null() + { + __Release(_type,_unVal); + _type=OT_NULL; + _unVal.pUserPointer=NULL; + } + SQObjectPtr& operator=(const SQObjectPtr& obj) + { + SQObjectType tOldType; + SQObjectValue unOldVal; + tOldType=_type; + unOldVal=_unVal; + _unVal = obj._unVal; + _type = obj._type; + __AddRef(_type,_unVal); + __Release(tOldType,unOldVal); + return *this; + } + SQObjectPtr& operator=(const SQObject& obj) + { + SQObjectType tOldType; + SQObjectValue unOldVal; + tOldType=_type; + unOldVal=_unVal; + _unVal = obj._unVal; + _type = obj._type; + __AddRef(_type,_unVal); + __Release(tOldType,unOldVal); + return *this; + } + private: + SQObjectPtr(const SQChar *){} //safety +}; +///////////////////////////////////////////////////////////////////////////////////// +#ifndef NO_GARBAGE_COLLECTOR +#define MARK_FLAG 0x80000000 +struct SQCollectable : public SQRefCounted { + SQCollectable *_next; + SQCollectable *_prev; + SQSharedState *_sharedstate; + virtual void Release()=0; + virtual void Mark(SQCollectable **chain)=0; + void UnMark(); + virtual void Finalize()=0; + static void AddToChain(SQCollectable **chain,SQCollectable *c); + static void RemoveFromChain(SQCollectable **chain,SQCollectable *c); +}; + + +#define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj) +#define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);} +#define CHAINABLE_OBJ SQCollectable +#define INIT_CHAIN() {_next=NULL;_prev=NULL;_sharedstate=ss;} +#else + +#define ADD_TO_CHAIN(chain,obj) ((void)0) +#define REMOVE_FROM_CHAIN(chain,obj) ((void)0) +#define CHAINABLE_OBJ SQRefCounted +#define INIT_CHAIN() ((void)0) +#endif + +struct SQDelegable : public CHAINABLE_OBJ { + virtual bool GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res); + SQTable *_delegate; +}; + +unsigned int TranslateIndex(const SQObjectPtr &idx); +typedef sqvector SQObjectPtrVec; +typedef sqvector SQIntVec; + +#endif //_SQOBJECT_H_ diff --git a/src/squirrel/squirrel/sqopcodes.h b/src/squirrel/squirrel/sqopcodes.h new file mode 100644 index 000000000..81abae0dd --- /dev/null +++ b/src/squirrel/squirrel/sqopcodes.h @@ -0,0 +1,107 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQOPCODES_H_ +#define _SQOPCODES_H_ + +#define MAX_FUNC_STACKSIZE 0xFF +#define MAX_LITERALS 0xFFFFFFFF + +enum BitWiseOP { + BW_AND = 0, + BW_OR = 2, //like ADD + BW_XOR = 3, + BW_SHIFTL = 4, + BW_SHIFTR = 5, + BW_USHIFTR = 6 +}; + +enum CmpOP { + CMP_G = 0, + CMP_GE = 2, //like ADD + CMP_L = 3, + CMP_LE = 4 +}; +enum SQOpcode +{ + _OP_LINE= 0x00, + _OP_LOAD= 0x01, + _OP_TAILCALL= 0x02, + _OP_CALL= 0x03, + _OP_PREPCALL= 0x04, + _OP_PREPCALLK= 0x05, + _OP_GETK= 0x06, + _OP_MOVE= 0x07, + _OP_NEWSLOT= 0x08, + _OP_DELETE= 0x09, + _OP_SET= 0x0A, + _OP_GET= 0x0B, + _OP_EQ= 0x0C, + _OP_NE= 0x0D, + _OP_ARITH= 0x0E, + _OP_BITW= 0x0F, + _OP_RETURN= 0x10, + _OP_LOADNULLS= 0x11, + _OP_LOADROOTTABLE= 0x12, + _OP_DMOVE= 0x13, + _OP_JMP= 0x14, + _OP_JNZ= 0x15, + _OP_JZ= 0x16, + _OP_LOADFREEVAR= 0x17, + _OP_VARGC= 0x18, + _OP_GETVARGV= 0x19, + _OP_NEWTABLE= 0x1A, + _OP_NEWARRAY= 0x1B, + _OP_APPENDARRAY= 0x1C, + _OP_GETPARENT= 0x1D, + _OP_COMPARITH= 0x1E, + _OP_COMPARITHL= 0x1F, + _OP_INC= 0x20, + _OP_INCL= 0x21, + _OP_PINC= 0x22, + _OP_PINCL= 0x23, + _OP_CMP= 0x24, + _OP_EXISTS= 0x25, + _OP_INSTANCEOF= 0x26, + _OP_AND= 0x27, + _OP_OR= 0x28, + _OP_NEG= 0x29, + _OP_NOT= 0x2A, + _OP_BWNOT= 0x2B, + _OP_CLOSURE= 0x2C, + _OP_YIELD= 0x2D, + _OP_RESUME= 0x2E, + _OP_FOREACH= 0x2F, + _OP_DELEGATE= 0x30, + _OP_CLONE= 0x31, + _OP_TYPEOF= 0x32, + _OP_PUSHTRAP= 0x33, + _OP_POPTRAP= 0x34, + _OP_THROW= 0x35, + _OP_CLASS= 0x36, + _OP_NEWSLOTA= 0x37, + _OP_LOADBOOL= 0x38 +}; +struct SQInstructionDesc { + const SQChar *name; +}; + +struct SQInstruction +{ + SQInstruction(){}; + SQInstruction(SQOpcode _op,int a0=0,int a1=0,int a2=0,int a3=0) + { op = _op; + _arg0 = a0;_arg1 = a1; + _arg2 = a2;_arg3 = a3; + } + + + unsigned int _arg1; + unsigned char op; + unsigned char _arg0; + unsigned char _arg2; + unsigned char _arg3; +}; + +#include "squtils.h" +typedef sqvector SQInstructionVec; + +#endif // _SQOPCODES_H_ diff --git a/src/squirrel/squirrel/sqpcheader.h b/src/squirrel/squirrel/sqpcheader.h new file mode 100644 index 000000000..f0e5cf2df --- /dev/null +++ b/src/squirrel/squirrel/sqpcheader.h @@ -0,0 +1,19 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQPCHEADER_H_ +#define _SQPCHEADER_H_ + +#if defined(_MSC_VER) && defined(_DEBUG) +#include +#endif + +#include +#include +#include +#include +#include +//squirrel stuff +#include +#include "sqobject.h" +#include "sqstate.h" + +#endif //_SQPCHEADER_H_ diff --git a/src/squirrel/squirrel/sqstate.cpp b/src/squirrel/squirrel/sqstate.cpp new file mode 100644 index 000000000..e352e2529 --- /dev/null +++ b/src/squirrel/squirrel/sqstate.cpp @@ -0,0 +1,426 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqopcodes.h" +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "squserdata.h" +#include "sqclass.h" + +SQObjectPtr _null_; +SQObjectPtr _true_(true); +SQObjectPtr _false_(false); +SQObjectPtr _one_(1); +SQObjectPtr _minusone_(-1); + +SQSharedState::SQSharedState() +{ + _compilererrorhandler = NULL; + _printfunc = NULL; + _debuginfo = false; +} + +#define newsysstring(s) { \ + _systemstrings->push_back(SQString::Create(this,s)); \ + } + +#define newmetamethod(s) { \ + _metamethods->push_back(SQString::Create(this,s)); \ + _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \ + } + +bool CompileTypemask(SQIntVec &res,const SQChar *typemask) +{ + int i = 0; + + int mask = 0; + while(typemask[i] != 0) { + + switch(typemask[i]){ + case 'i': mask |= _RT_INTEGER; break; + case 'f': mask |= _RT_FLOAT; break; + case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break; + case 's': mask |= _RT_STRING; break; + case 't': mask |= _RT_TABLE; break; + case 'a': mask |= _RT_ARRAY; break; + case 'u': mask |= _RT_USERDATA; break; + case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break; + case 'b': mask |= _RT_BOOL; break; + case 'g': mask |= _RT_GENERATOR; break; + case 'p': mask |= _RT_USERPOINTER; break; + case 'v': mask |= _RT_THREAD; break; + case 'x': mask |= _RT_INSTANCE; break; + case 'y': mask |= _RT_CLASS; break; + case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue; + case ' ': i++; continue; //ignores spaces + default: + return false; + } + i++; + if(typemask[i] == '|') { + i++; + if(typemask[i] == 0) + return false; + continue; + } + res.push_back(mask); + mask = 0; + + } + return true; +} + +SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz) +{ + int i=0; + SQTable *t=SQTable::Create(ss,0); + while(funcz[i].name!=0){ + SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f); + nc->_nparamscheck = funcz[i].nparamscheck; + nc->_name = SQString::Create(ss,funcz[i].name); + if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask)) + return NULL; + t->NewSlot(SQString::Create(ss,funcz[i].name),nc); + i++; + } + return t; +} + +void SQSharedState::Init() +{ + _scratchpad=NULL; + _scratchpadsize=0; +#ifndef NO_GARBAGE_COLLECTOR + _gc_chain=NULL; +#endif + sq_new(_stringtable,StringTable); + sq_new(_metamethods,SQObjectPtrVec); + sq_new(_systemstrings,SQObjectPtrVec); + sq_new(_types,SQObjectPtrVec); + _metamethodsmap = SQTable::Create(this,MT_LAST-1); + //adding type strings to avoid memory trashing + //types names + newsysstring(_SC("null")); + newsysstring(_SC("table")); + newsysstring(_SC("array")); + newsysstring(_SC("closure")); + newsysstring(_SC("string")); + newsysstring(_SC("userdata")); + newsysstring(_SC("integer")); + newsysstring(_SC("float")); + newsysstring(_SC("userpointer")); + newsysstring(_SC("function")); + newsysstring(_SC("generator")); + newsysstring(_SC("thread")); + newsysstring(_SC("class")); + newsysstring(_SC("instance")); + newsysstring(_SC("bool")); + //meta methods + newmetamethod(MM_ADD); + newmetamethod(MM_SUB); + newmetamethod(MM_MUL); + newmetamethod(MM_DIV); + newmetamethod(MM_UNM); + newmetamethod(MM_MODULO); + newmetamethod(MM_SET); + newmetamethod(MM_GET); + newmetamethod(MM_TYPEOF); + newmetamethod(MM_NEXTI); + newmetamethod(MM_CMP); + newmetamethod(MM_CALL); + newmetamethod(MM_CLONED); + newmetamethod(MM_NEWSLOT); + newmetamethod(MM_DELSLOT); + + _constructoridx = SQString::Create(this,_SC("constructor")); + _refs_table = SQTable::Create(this,0); + _registry = SQTable::Create(this,0); + _table_default_delegate=CreateDefaultDelegate(this,_table_default_delegate_funcz); + _array_default_delegate=CreateDefaultDelegate(this,_array_default_delegate_funcz); + _string_default_delegate=CreateDefaultDelegate(this,_string_default_delegate_funcz); + _number_default_delegate=CreateDefaultDelegate(this,_number_default_delegate_funcz); + _closure_default_delegate=CreateDefaultDelegate(this,_closure_default_delegate_funcz); + _generator_default_delegate=CreateDefaultDelegate(this,_generator_default_delegate_funcz); + _thread_default_delegate=CreateDefaultDelegate(this,_thread_default_delegate_funcz); + _class_default_delegate=CreateDefaultDelegate(this,_class_default_delegate_funcz); + _instance_default_delegate=CreateDefaultDelegate(this,_instance_default_delegate_funcz); + +} + +SQSharedState::~SQSharedState() +{ + _constructoridx = _null_; + _table(_refs_table)->Finalize(); + _table(_registry)->Finalize(); + _table(_metamethodsmap)->Finalize(); + _refs_table = _null_; + _registry = _null_; + _metamethodsmap = _null_; + while(!_systemstrings->empty()){ + _systemstrings->back()=_null_; + _systemstrings->pop_back(); + } + _thread(_root_vm)->Finalize(); + _root_vm = _null_; + _table_default_delegate=_null_; + _array_default_delegate=_null_; + _string_default_delegate=_null_; + _number_default_delegate=_null_; + _closure_default_delegate=_null_; + _generator_default_delegate=_null_; + _thread_default_delegate=_null_; + _class_default_delegate=_null_; + _instance_default_delegate=_null_; + +#ifndef NO_GARBAGE_COLLECTOR + + + SQCollectable *t=_gc_chain; + SQCollectable *nx=NULL; + while(t){ + t->_uiRef++; + t->Finalize(); + nx=t->_next; + if(--t->_uiRef==0) + t->Release(); + t=nx; + } + assert(_gc_chain==NULL); //just to proove a theory + while(_gc_chain){ + _gc_chain->_uiRef++; + _gc_chain->Release(); + } +#endif + sq_delete(_types,SQObjectPtrVec); + sq_delete(_systemstrings,SQObjectPtrVec); + sq_delete(_metamethods,SQObjectPtrVec); + sq_delete(_stringtable,StringTable); + if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize); +} + + +SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) +{ + if(type(name) != OT_STRING) + return -1; + SQObjectPtr ret; + if(_table(_metamethodsmap)->Get(name,ret)) { + return _integer(ret); + } + return -1; +} + +#ifndef NO_GARBAGE_COLLECTOR + +void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) +{ + switch(type(o)){ + case OT_TABLE:_table(o)->Mark(chain);break; + case OT_ARRAY:_array(o)->Mark(chain);break; + case OT_USERDATA:_userdata(o)->Mark(chain);break; + case OT_CLOSURE:_closure(o)->Mark(chain);break; + case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; + case OT_GENERATOR:_generator(o)->Mark(chain);break; + case OT_THREAD:_thread(o)->Mark(chain);break; + case OT_CLASS:_class(o)->Mark(chain);break; + case OT_INSTANCE:_instance(o)->Mark(chain);break; + } +} + + +int SQSharedState::CollectGarbage(SQVM *vm) +{ + int n=0; + SQCollectable *tchain=NULL; + SQVM *vms=_thread(_root_vm); + + vms->Mark(&tchain); + int x = _table(_thread(_root_vm)->_roottable)->CountUsed(); + MarkObject(_refs_table,&tchain); + MarkObject(_registry,&tchain); + MarkObject(_metamethodsmap,&tchain); + MarkObject(_table_default_delegate,&tchain); + MarkObject(_array_default_delegate,&tchain); + MarkObject(_string_default_delegate,&tchain); + MarkObject(_number_default_delegate,&tchain); + MarkObject(_generator_default_delegate,&tchain); + MarkObject(_thread_default_delegate,&tchain); + MarkObject(_closure_default_delegate,&tchain); + MarkObject(_class_default_delegate,&tchain); + MarkObject(_instance_default_delegate,&tchain); + + SQCollectable *t=_gc_chain; + SQCollectable *nx=NULL; + while(t){ + t->_uiRef++; + t->Finalize(); + nx=t->_next; + if(--t->_uiRef==0) + t->Release(); + t=nx; + n++; + } + + t=tchain; + while(t){ + t->UnMark(); + t=t->_next; + } + _gc_chain=tchain; + int z = _table(_thread(_root_vm)->_roottable)->CountUsed(); + assert(z == x); + return n; +} +#endif + +#ifndef NO_GARBAGE_COLLECTOR +void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c) +{ + c->_prev=NULL; + c->_next=*chain; + if(*chain) (*chain)->_prev=c; + *chain=c; +} + +void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c) +{ + if(c->_prev) c->_prev->_next=c->_next; + else *chain=c->_next; + if(c->_next) + c->_next->_prev=c->_prev; + c->_next=NULL; + c->_prev=NULL; +} +#endif + +SQChar* SQSharedState::GetScratchPad(int size) +{ + int newsize; + if(size>0){ + if(_scratchpadsize>1); + _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize=newsize; + + }else if(_scratchpadsize>=(size<<5)){ + newsize=_scratchpadsize>>1; + _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize=newsize; + } + } + return _scratchpad; +} + +////////////////////////////////////////////////////////////////////////// +//StringTable +/* +* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) +* http://www.lua.org/copyright.html#4 +* http://www.lua.org/source/4.0.1/src_lstring.c.html +*/ + +int SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + int idx = (int)TranslateIndex(refpos); + while(idx < _len){ + outkey = (SQInteger)idx; + outval = SQInteger(_val[idx]); + //return idx for the next iteration + return ++idx; + } + //nothing to iterate anymore + return -1; +} + +StringTable::StringTable() +{ + AllocNodes(4); + _slotused = 0; +} + +StringTable::~StringTable() +{ + SQ_FREE(_strings,sizeof(SQString*)*_numofslots); + _strings=NULL; +} + +void StringTable::AllocNodes(int size) +{ + _numofslots=size; + //_slotused=0; + _strings=(SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots); + memset(_strings,0,sizeof(SQString*)*_numofslots); +} + +SQString *StringTable::Add(const SQChar *news,int len) +{ + if(len<0) + len=scstrlen(news); + unsigned int h=::_hashstr(news,len)&(_numofslots-1); + SQString *s; + for (s = _strings[h]; s; s = s->_next){ + if(s->_len == len && (!memcmp(news,s->_val,rsl(len)))) + return s; //found + } + + SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString)); + new (t) SQString; + memcpy(t->_val,news,rsl(len)); + t->_val[len]=_SC('\0'); + t->_len=len; + t->_hash=::_hashstr(news,len); + t->_next=_strings[h]; + t->_uiRef=0; + _strings[h]=t; + _slotused++; + if (_slotused > _numofslots) /* too crowded? */ + Resize(_numofslots*2); + return t; +} + +void StringTable::Resize(int size) +{ + int oldsize=_numofslots; + SQString **oldtable=_strings; + AllocNodes(size); + for (int i=0; i_next; + unsigned int h=p->_hash&(_numofslots-1); + p->_next=_strings[h]; + _strings[h] = p; + p=next; + } + } + SQ_FREE(oldtable,oldsize*sizeof(SQString*)); +} + +void StringTable::Remove(SQString *bs) +{ + SQString *s; + SQString *prev=NULL; + unsigned int h=bs->_hash&(_numofslots-1); + + for (s = _strings[h]; s; ){ + if(s == bs){ + if(prev) + prev->_next = s->_next; + else + _strings[h] = s->_next; + _slotused--; + int slen=s->_len; + s->~SQString(); + SQ_FREE(s,sizeof(SQString)+rsl(slen)); + return; + } + prev = s; + s = s->_next; + } + assert(0);//if this fail something is wrong +} diff --git a/src/squirrel/squirrel/sqstate.h b/src/squirrel/squirrel/sqstate.h new file mode 100644 index 000000000..96acca8af --- /dev/null +++ b/src/squirrel/squirrel/sqstate.h @@ -0,0 +1,116 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTATE_H_ +#define _SQSTATE_H_ + +#include "squtils.h" +#include "sqobject.h" +struct SQString; +struct SQTable; +//max number of character for a printed number +#define NUMBER_MAX_CHAR 50 + +struct StringTable +{ + StringTable(); + ~StringTable(); + //return a string obj if exists + //so when there is a table query, if the string doesn't exists in the global state + //it cannot be in a table so the result will be always null + //SQString *get(const SQChar *news); + SQString *Add(const SQChar *,int len); + void Remove(SQString *); +private: + void Resize(int size); + void AllocNodes(int size); + SQString **_strings; + unsigned int _numofslots; + unsigned int _slotused; +}; + +#define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len) +#define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr) + +struct SQObjectPtr; + +struct SQSharedState +{ + SQSharedState(); + ~SQSharedState(); + void Init(); +public: + SQChar* GetScratchPad(int size); + SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name); +#ifndef NO_GARBAGE_COLLECTOR + int CollectGarbage(SQVM *vm); + static void MarkObject(SQObjectPtr &o,SQCollectable **chain); +#endif + SQObjectPtrVec *_metamethods; + SQObjectPtr _metamethodsmap; + SQObjectPtrVec *_systemstrings; + SQObjectPtrVec *_types; + StringTable *_stringtable; + SQObjectPtr _refs_table; + SQObjectPtr _registry; + SQObjectPtr _constructoridx; +#ifndef NO_GARBAGE_COLLECTOR + SQCollectable *_gc_chain; +#endif + SQObjectPtr _root_vm; + SQObjectPtr _table_default_delegate; + static SQRegFunction _table_default_delegate_funcz[]; + SQObjectPtr _array_default_delegate; + static SQRegFunction _array_default_delegate_funcz[]; + SQObjectPtr _string_default_delegate; + static SQRegFunction _string_default_delegate_funcz[]; + SQObjectPtr _number_default_delegate; + static SQRegFunction _number_default_delegate_funcz[]; + SQObjectPtr _generator_default_delegate; + static SQRegFunction _generator_default_delegate_funcz[]; + SQObjectPtr _closure_default_delegate; + static SQRegFunction _closure_default_delegate_funcz[]; + SQObjectPtr _thread_default_delegate; + static SQRegFunction _thread_default_delegate_funcz[]; + SQObjectPtr _class_default_delegate; + static SQRegFunction _class_default_delegate_funcz[]; + SQObjectPtr _instance_default_delegate; + static SQRegFunction _instance_default_delegate_funcz[]; + + SQCOMPILERERROR _compilererrorhandler; + SQPRINTFUNCTION _printfunc; + bool _debuginfo; +private: + SQChar *_scratchpad; + int _scratchpadsize; +}; + +#define _sp(s) (_sharedstate->GetScratchPad(s)) +#define _spval (_sharedstate->GetScratchPad(-1)) + +#define _table_ddel _table(_sharedstate->_table_default_delegate) +#define _array_ddel _table(_sharedstate->_array_default_delegate) +#define _string_ddel _table(_sharedstate->_string_default_delegate) +#define _number_ddel _table(_sharedstate->_number_default_delegate) +#define _generator_ddel _table(_sharedstate->_generator_default_delegate) +#define _closure_ddel _table(_sharedstate->_closure_default_delegate) +#define _thread_ddel _table(_sharedstate->_thread_default_delegate) +#define _class_ddel _table(_sharedstate->_class_default_delegate) +#define _instance_ddel _table(_sharedstate->_instance_default_delegate) + +#ifdef SQUNICODE //rsl REAL STRING LEN +#define rsl(l) ((l)<<1) +#else +#define rsl(l) (l) +#endif + +extern SQObjectPtr _null_; +extern SQObjectPtr _true_; +extern SQObjectPtr _false_; +extern SQObjectPtr _one_; +extern SQObjectPtr _minusone_; + +bool CompileTypemask(SQIntVec &res,const SQChar *typemask); + +void *sq_vm_malloc(unsigned int size); +void *sq_vm_realloc(void *p,unsigned int oldsize,unsigned int size); +void sq_vm_free(void *p,unsigned int size); +#endif //_SQSTATE_H_ diff --git a/src/squirrel/squirrel/sqstring.h b/src/squirrel/squirrel/sqstring.h new file mode 100644 index 000000000..dfb401712 --- /dev/null +++ b/src/squirrel/squirrel/sqstring.h @@ -0,0 +1,31 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTRING_H_ +#define _SQSTRING_H_ + +inline unsigned int _hashstr (const SQChar *s, size_t l) +{ + unsigned int h = l; /* seed */ + size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */ + for (; l>=step; l-=step) + h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++)); + return h; +} + +struct SQString : public SQRefCounted +{ + SQString(){} + ~SQString(){} +public: + static SQString *Create(SQSharedState *ss, const SQChar *, int len = -1 ); + int Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + void Release(); + SQSharedState *_sharedstate; + SQString *_next; //chain for the string table + int _len; + int _hash; + SQChar _val[1]; +}; + + + +#endif //_SQSTRING_H_ diff --git a/src/squirrel/squirrel/sqtable.cpp b/src/squirrel/squirrel/sqtable.cpp new file mode 100644 index 000000000..04509ec70 --- /dev/null +++ b/src/squirrel/squirrel/sqtable.cpp @@ -0,0 +1,193 @@ +/* +see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqtable.h" +#include "sqfuncproto.h" +#include "sqclosure.h" + +SQTable::SQTable(SQSharedState *ss,int nInitialSize) +{ + int pow2size=MINPOWER2; + while(nInitialSize>pow2size)pow2size=pow2size<<1; + AllocNodes(pow2size); + _uiRef = 0; + _usednodes = 0; + _delegate = NULL; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain,this); +} + +void SQTable::Remove(const SQObjectPtr &key) +{ + _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); + if (n) { + n->val = n->key = _null_; + _usednodes--; + Rehash(false); + } +} + +void SQTable::AllocNodes(int nSize) +{ + _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize); + for(int i=0;i= oldsize-oldsize/4) /* using more than 3/4? */ + AllocNodes(oldsize*2); + else if (nelems <= oldsize/4 && /* less than 1/4? */ + oldsize > MINPOWER2) + AllocNodes(oldsize/2); + else if(force) + AllocNodes(oldsize); + else + return; + _usednodes = 0; + for (int i=0; ikey) != OT_NULL) + NewSlot(old->key,old->val); + } + for(int k=0;kNewSlot(key,val); + } + nt->SetDelegate(_delegate); + return nt; +} + +bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) +{ + _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); + if (n) { + val = n->val; + return true; + } + return false; +} +bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) +{ + unsigned long h = HashKey(key) & (_numofnodes - 1); + _HashNode *n = _Get(key, h); + if (n) { + n->val = val; + return false; + } + _HashNode *mp = &_nodes[h]; + n = mp; + + //key not found I'll insert it + //main pos is not free + + if(type(mp->key)!=OT_NULL) { + + _HashNode *othern; /* main position of colliding node */ + n = _firstfree; /* get a free place */ + if (mp > n && (othern = &_nodes[h]) != mp){ + /* yes; move colliding node into free position */ + while (othern->next != mp) + othern = othern->next; /* find previous */ + othern->next = n; /* redo the chain with `n' in place of `mp' */ + *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + mp->next = NULL; /* now `mp' is free */ + } + else{ + /* new node will go into free position */ + n->next = mp->next; /* chain new position */ + mp->next = n; + mp = n; + } + } + mp->key = key; + + for (;;) { /* correct `firstfree' */ + if (type(_firstfree->key) == OT_NULL) { + mp->val = val; + _usednodes++; + return true; /* OK; table still has a free place */ + } + else if (_firstfree == _nodes) break; /* cannot decrement from here */ + else (_firstfree)--; + } + Rehash(true); + return NewSlot(key, val); +} + +int SQTable::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + int idx = (int)TranslateIndex(refpos); + while (idx < _numofnodes) { + if(type(_nodes[idx].key) != OT_NULL) { + //first found + outkey = _nodes[idx].key; + outval = _nodes[idx].val; + //return idx for the next iteration + return ++idx; + } + ++idx; + } + //nothing to iterate anymore + return -1; +} + +bool SQTable::SetDelegate(SQTable *mt) +{ + SQTable *temp = mt; + while (temp) { + if (temp->_delegate == this) return false; //cycle detected + temp = temp->_delegate; + } + if (mt) __ObjAddRef(mt); + __ObjRelease(_delegate); + _delegate = mt; + return true; +} + +bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val) +{ + _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1)); + if (n) { + n->val = val; + return true; + } + return false; +} + +void SQTable::Finalize() +{ + for(int i = 0;i < _numofnodes; i++) { _nodes[i].key = _null_; _nodes[i].val = _null_; } + SetDelegate(NULL); +} diff --git a/src/squirrel/squirrel/sqtable.h b/src/squirrel/squirrel/sqtable.h new file mode 100644 index 000000000..b27b7d37c --- /dev/null +++ b/src/squirrel/squirrel/sqtable.h @@ -0,0 +1,88 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQTABLE_H_ +#define _SQTABLE_H_ +/* +* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) +* http://www.lua.org/copyright.html#4 +* http://www.lua.org/source/4.0.1/src_ltable.c.html +*/ + +#include "sqstring.h" + +#define hashptr(p) (((unsigned long)(p)) >> 3) + +struct SQTable : public SQDelegable +{ +private: + struct _HashNode + { + SQObjectPtr val; + SQObjectPtr key; + _HashNode *next; + }; + _HashNode *_firstfree; + _HashNode *_nodes; + int _numofnodes; + int _usednodes; + +/////////////////////////// + void AllocNodes(int nSize); + void Rehash(bool force); + SQTable(SQSharedState *ss, int nInitialSize); +public: + static SQTable* Create(SQSharedState *ss,int nInitialSize) + { + SQTable *newtable = (SQTable*)SQ_MALLOC(sizeof(SQTable)); + new (newtable) SQTable(ss, nInitialSize); + newtable->_delegate = NULL; + return newtable; + } + void Finalize(); + SQTable *Clone(); + ~SQTable() + { + SetDelegate(NULL); + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + for (int i = 0; i < _numofnodes; i++) _nodes[i].~_HashNode(); + SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode)); + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + inline unsigned long HashKey(const SQObjectPtr &key) + { + switch(type(key)){ + case OT_STRING: return _string(key)->_hash; + case OT_FLOAT: return (unsigned long)((long)_float(key)); + case OT_INTEGER: return (unsigned long)((long)_integer(key)); + default: return hashptr(key._unVal.pRefCounted); + } + } + _HashNode *_Get(const SQObjectPtr &key,unsigned long hash) + { + _HashNode *n = &_nodes[hash]; + do{ + if(_rawval(n->key) == _rawval(key) && type(n->key) == type(key)){ + return n; + } + }while(n = n->next); + return NULL; + } + bool Get(const SQObjectPtr &key,SQObjectPtr &val); + void Remove(const SQObjectPtr &key); + bool Set(const SQObjectPtr &key, const SQObjectPtr &val); + //returns true if a new slot has been created false if it was already present + bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val); + int Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + + int CountUsed(); + void Release() + { + sq_delete(this, SQTable); + } + bool SetDelegate(SQTable *mt); + + +}; + +#endif //_SQTABLE_H_ diff --git a/src/squirrel/squirrel/squirrel.dsp b/src/squirrel/squirrel/squirrel.dsp new file mode 100644 index 000000000..1b8cd40c3 --- /dev/null +++ b/src/squirrel/squirrel/squirrel.dsp @@ -0,0 +1,302 @@ +# Microsoft Developer Studio Project File - Name="squirrel" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=squirrel - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "squirrel.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "squirrel.mak" CFG="squirrel - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "squirrel - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "squirrel - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "squirrel - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "GARBAGE_COLLECTOR" /YX /FD /c +# ADD BASE RSC /l 0x410 /d "NDEBUG" +# ADD RSC /l 0x410 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\squirrel.lib" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "GARBAGE_COLLECTOR" /YX /FD /GZ /c +# ADD BASE RSC /l 0x410 /d "_DEBUG" +# ADD RSC /l 0x410 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\squirrel.lib" + +!ENDIF + +# Begin Target + +# Name "squirrel - Win32 Release" +# Name "squirrel - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\sqapi.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqbaselib.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqcompiler.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqdebug.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqfuncstate.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqlexer.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqmem.cpp +# End Source File +# Begin Source File + +SOURCE=.\sqobject.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqstate.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqtable.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqclass.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\sqvm.cpp + +!IF "$(CFG)" == "squirrel - Win32 Release" + +!ELSEIF "$(CFG)" == "squirrel - Win32 Debug" + +# ADD CPP /YX"stdafx.h" + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\sqarray.h +# End Source File +# Begin Source File + +SOURCE=.\sqclosure.h +# End Source File +# Begin Source File + +SOURCE=.\sqcompiler.h +# End Source File +# Begin Source File + +SOURCE=.\sqfuncproto.h +# End Source File +# Begin Source File + +SOURCE=.\sqfuncstate.h +# End Source File +# Begin Source File + +SOURCE=.\sqlexer.h +# End Source File +# Begin Source File + +SOURCE=.\sqobject.h +# End Source File +# Begin Source File + +SOURCE=.\sqopcodes.h +# End Source File +# Begin Source File + +SOURCE=.\sqpcheader.h +# End Source File +# Begin Source File + +SOURCE=.\sqstate.h +# End Source File +# Begin Source File + +SOURCE=.\sqstring.h +# End Source File +# Begin Source File + +SOURCE=.\sqtable.h +# End Source File +# Begin Source File + +SOURCE=.\squserdata.h +# End Source File +# Begin Source File + +SOURCE=.\squtils.h +# End Source File +# Begin Source File + +SOURCE=.\sqclass.h +# End Source File +# Begin Source File + +SOURCE=.\sqvm.h +# End Source File +# End Group +# End Target +# End Project diff --git a/src/squirrel/squirrel/squserdata.h b/src/squirrel/squirrel/squserdata.h new file mode 100644 index 000000000..7b85913e7 --- /dev/null +++ b/src/squirrel/squirrel/squserdata.h @@ -0,0 +1,45 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQUSERDATA_H_ +#define _SQUSERDATA_H_ + +struct SQUserData : SQDelegable +{ + SQUserData(SQSharedState *ss){ _uiRef = 0; _delegate = 0; _hook = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain, this); } + ~SQUserData() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this); + SetDelegate(NULL); + } + static SQUserData* Create(SQSharedState *ss, int size) + { + SQUserData* ud = (SQUserData*)SQ_MALLOC(sizeof(SQUserData)+(size-1)); + new (ud) SQUserData(ss); + ud->_size = size; + ud->_typetag = 0; + return ud; + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){SetDelegate(NULL);} +#endif + void Release() { + if (_hook) _hook(_val,_size); + int tsize = _size - 1; + this->~SQUserData(); + SQ_FREE(this, sizeof(SQUserData) + tsize); + } + void SetDelegate(SQTable *mt) + { + if (mt) __ObjAddRef(mt); + __ObjRelease(_delegate); + _delegate = mt; + } + + + int _size; + SQRELEASEHOOK _hook; + unsigned int _typetag; + SQChar _val[1]; +}; + +#endif //_SQUSERDATA_H_ diff --git a/src/squirrel/squirrel/squtils.h b/src/squirrel/squirrel/squtils.h new file mode 100644 index 000000000..d1abd54ef --- /dev/null +++ b/src/squirrel/squirrel/squtils.h @@ -0,0 +1,104 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQUTILS_H_ +#define _SQUTILS_H_ + +#define sq_new(__ptr,__type) {__ptr=(__type *)sq_vm_malloc(sizeof(__type));new (__ptr) __type;} +#define sq_delete(__ptr,__type) {__ptr->~__type();sq_vm_free(__ptr,sizeof(__type));} +#define SQ_MALLOC(__size) sq_vm_malloc(__size); +#define SQ_FREE(__ptr,__size) sq_vm_free(__ptr,__size); +#define SQ_REALLOC(__ptr,__oldsize,__size) sq_vm_realloc(__ptr,__oldsize,__size); + +//sqvector mini vector class, supports objects by value +template class sqvector +{ +public: + sqvector() + { + _vals = NULL; + _size = 0; + _allocated = 0; + } + sqvector(const sqvector& v) + { + copy(v); + } + void copy(const sqvector& v) + { + resize(v._size); + for(unsigned int i = 0; i < v._size; i++) { + new ((void *)&_vals[i]) T(v._vals[i]); + } + _size = v._size; + } + ~sqvector() + { + if(_allocated) { + for(unsigned int i = 0; i < _size; i++) + _vals[i].~T(); + SQ_FREE(_vals, (_allocated * sizeof(T))); + } + } + void reserve(unsigned int newsize) { _realloc(newsize); } + void resize(unsigned int newsize, const T& fill = T()) + { + if(newsize > _allocated) + _realloc(newsize); + if(newsize > _size) { + while(_size < newsize) { + new ((void *)&_vals[_size]) T(fill); + _size++; + } + } + else{ + for(unsigned int i = newsize; i < _size; i++) { + _vals[i].~T(); + } + _size = newsize; + } + } + void shrinktofit() { if(_size > 4) { _realloc(_size); } } + T& top() const { return _vals[_size - 1]; } + inline unsigned int size() const { return _size; } + bool empty() const { return (_size <= 0); } + inline void push_back(const T& val = T()) + { + if(_allocated <= _size) + _realloc(_size * 2); + new ((void *)&_vals[_size++]) T(val); + } + inline void pop_back() + { + _size--; _vals[_size].~T(); + } + void insert(unsigned int idx, const T& val) + { + resize(_size + 1); + for(unsigned int i = _size - 1; i > idx; i--) { + _vals[i] = _vals[i - 1]; + } + _vals[idx] = val; + } + void remove(unsigned int idx) + { + _vals[idx].~T(); + if(idx < (_size - 1)) { + memcpy(&_vals[idx], &_vals[idx+1], sizeof(T) * (_size - idx - 1)); + } + _size--; + } + unsigned int capacity() { return _allocated; } + inline T &back() const { return _vals[_size - 1]; } + T& operator[](unsigned int pos) const{ return _vals[pos]; } + T* _vals; +private: + void _realloc(unsigned int newsize) + { + newsize = (newsize > 0)?newsize:4; + _vals = (T*)SQ_REALLOC(_vals, _allocated * sizeof(T), newsize * sizeof(T)); + _allocated = newsize; + } + unsigned int _size; + unsigned int _allocated; +}; + +#endif //_SQUTILS_H_ diff --git a/src/squirrel/squirrel/sqvm.cpp b/src/squirrel/squirrel/sqvm.cpp new file mode 100644 index 000000000..3244c65b1 --- /dev/null +++ b/src/squirrel/squirrel/sqvm.cpp @@ -0,0 +1,1391 @@ +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include +#include +#include "sqopcodes.h" +#include "sqfuncproto.h" +#include "sqvm.h" +#include "sqclosure.h" +#include "sqstring.h" +#include "sqtable.h" +#include "squserdata.h" +#include "sqarray.h" +#include "sqclass.h" + +#define TOP() (_stack[_top-1]) + +bool SQVM::BW_OP(unsigned int op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) +{ + SQInteger res; + SQInteger i1 = _integer(o1), i2 = _integer(o2); + if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) + { + switch(op) { + case BW_AND: res = i1 & i2; break; + case BW_OR: res = i1 | i2; break; + case BW_XOR: res = i1 ^ i2; break; + case BW_SHIFTL: res = i1 << i2; break; + case BW_SHIFTR: res = i1 >> i2; break; + case BW_USHIFTR:res = (SQInteger)(*((unsigned int*)&i1) >> i2); break; + default: { Raise_Error(_SC("internal vm error bitwise op failed")); return false; } + } + } + else { Raise_Error(_SC("bitwise op between '%s' and '%s'"),GetTypeName(o1),GetTypeName(o2)); return false;} + trg = res; + return true; +} + +bool SQVM::ARITH_OP(unsigned int op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) +{ + if(sq_isnumeric(o1) && sq_isnumeric(o2)) { + if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) { + switch(op) { + case '+': trg = _integer(o1) + _integer(o2); break; + case '-': trg = _integer(o1) - _integer(o2); break; + case '/': if(_integer(o2) == 0) { Raise_Error(_SC("division by zero")); return false; } + trg = _integer(o1) / _integer(o2); + break; + case '*': trg = _integer(o1) * _integer(o2); break; + case '%': trg = _integer(o1) % _integer(o2); break; + } + }else{ + switch(op) { + case '+': trg = tofloat(o1) + tofloat(o2); break; + case '-': trg = tofloat(o1) - tofloat(o2); break; + case '/': trg = tofloat(o1) / tofloat(o2); break; + case '*': trg = tofloat(o1) * tofloat(o2); break; + case '%': trg = SQFloat(fmod((double)tofloat(o1),(double)tofloat(o2))); break; + } + } + } else { + if(op == '+' && (type(o1) == OT_STRING || type(o2) == OT_STRING)){ + if(!StringCat(o1, o2, trg)) return false; + } + else if(!ArithMetaMethod(op,o1,o2,trg)) { + Raise_Error(_SC("arith op %c on between '%s' and '%s'"),op,GetTypeName(o1),GetTypeName(o2)); return false; + } + } + return true; +} + +SQObjectPtr &stack_get(HSQUIRRELVM v,int idx){return ((idx>=0)?(v->GetAt(idx+v->_stackbase-1)):(v->GetUp(idx)));} + +SQVM::SQVM(SQSharedState *ss) +{ + _sharedstate=ss; + _suspended=false; + _suspended_target=-1; + _suspended_root=false; + _suspended_traps=-1; + _foreignptr=NULL; + _nnativecalls=0; + _uiRef=0; + _lasterror = _null_; + _errorhandler = _null_; + _debughook = _null_; + INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); +} + +void SQVM::Finalize() +{ + _roottable = _null_; + _lasterror = _null_; + _errorhandler = _null_; + _debughook = _null_; + temp_reg = _null_; + int size=_stack.size(); + for(int i=0;i_gc_chain,this); +} + +bool SQVM::ArithMetaMethod(int op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest) +{ + SQMetaMethod mm; + switch(op){ + case _SC('+'): mm=MT_ADD; break; + case _SC('-'): mm=MT_SUB; break; + case _SC('/'): mm=MT_DIV; break; + case _SC('*'): mm=MT_MUL; break; + case _SC('%'): mm=MT_MODULO; break; + } + if(is_delegable(o1) && _delegable(o1)->_delegate) { + Push(o1);Push(o2); + return CallMetaMethod(_delegable(o1),mm,2,dest); + } + return false; +} + +bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o) +{ + + switch(type(o)) { + case OT_INTEGER: + trg = -_integer(o); + return true; + case OT_FLOAT: + trg = -_float(o); + return true; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o)->_delegate) { + Push(o); + if(CallMetaMethod(_delegable(o), MT_UNM, 1, temp_reg)) { + trg = temp_reg; + return true; + } + } + return true; + + } + Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o)); + return false; +} + +#define _RET_SUCCEED(exp) { result = (exp); return true; } +bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,int &result) +{ + if(type(o1)==type(o2)){ + if(_userpointer(o1)==_userpointer(o2))_RET_SUCCEED(0); + SQObjectPtr res; + switch(type(o1)){ + case OT_STRING: + _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2))); + case OT_INTEGER: + _RET_SUCCEED(_integer(o1)-_integer(o2)); + case OT_FLOAT: + _RET_SUCCEED((_float(o1)<_float(o2))?-1:1); + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + Push(o1);Push(o2); + if(_delegable(o1)->_delegate)CallMetaMethod(_delegable(o1),MT_CMP,2,res); + break; + } + if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; } + _RET_SUCCEED(_integer(res)); + } + else{ + if(sq_isnumeric(o1) && sq_isnumeric(o2)){ + if((type(o1)==OT_INTEGER) && (type(o2)==OT_FLOAT)) { + if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); } + else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); } + _RET_SUCCEED(1); + } + else{ + if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); } + else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); } + _RET_SUCCEED(1); + } + } + else if(type(o1)==OT_NULL) {_RET_SUCCEED(-1);} + else if(type(o2)==OT_NULL) {_RET_SUCCEED(1);} + else { Raise_CompareError(o1,o2); return false; } + + } + assert(0); + _RET_SUCCEED(0); //cannot happen +} + +bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res) +{ + int r; + if(ObjCmp(o1,o2,r)) { + switch(op) { + case CMP_G: res = (r > 0)?_true_:_false_; return true; + case CMP_GE: res = (r >= 0)?_true_:_false_; return true; + case CMP_L: res = (r < 0)?_true_:_false_; return true; + case CMP_LE: res = (r <= 0)?_true_:_false_; return true; + + } + assert(0); + } + return false; +} + +bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest) +{ + switch(type(obj)) + { + case OT_STRING: + switch(type(str)){ + case OT_STRING: { + int l=_string(str)->_len,ol=_string(obj)->_len; + SQChar *s=_sp(rsl(l+ol+1)); + memcpy(s,_stringval(str),rsl(l));memcpy(s+l,_stringval(obj),rsl(ol));s[l+ol]=_SC('\0'); + break; + } + case OT_FLOAT: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%g%s"),_float(str),_stringval(obj)); + break; + case OT_INTEGER: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(obj)->_len+1)),_SC("%d%s"),_integer(str),_stringval(obj)); + break; + default: + Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj)); + return false; + } + dest=SQString::Create(_ss(this),_spval); + break; + case OT_FLOAT: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%g"),_stringval(str),_float(obj)); + dest=SQString::Create(_ss(this),_spval); + break; + case OT_INTEGER: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+_string(str)->_len+1)),_SC("%s%d"),_stringval(str),_integer(obj)); + dest=SQString::Create(_ss(this),_spval); + break; + default: + Raise_Error(_SC("string concatenation between '%s' and '%s'"),GetTypeName(str),GetTypeName(obj)); + return false; + } + return true; +} + +const SQChar *IdType2Name(SQObjectType type) +{ + switch(_RAW_TYPE(type)) + { + case _RT_NULL:return _SC("null"); + case _RT_INTEGER:return _SC("integer"); + case _RT_FLOAT:return _SC("float"); + case _RT_BOOL:return _SC("bool"); + case _RT_STRING:return _SC("string"); + case _RT_TABLE:return _SC("table"); + case _RT_ARRAY:return _SC("array"); + case _RT_GENERATOR:return _SC("generator"); + case _RT_CLOSURE: + case _RT_NATIVECLOSURE: + return _SC("function"); + case _RT_USERDATA: + case _RT_USERPOINTER: + return _SC("userdata"); + case _RT_THREAD: return _SC("thread"); + case _RT_FUNCPROTO: return _SC("function"); + case _RT_CLASS: return _SC("class"); + case _RT_INSTANCE: return _SC("instance"); + default: + return NULL; + } +} + +const SQChar *GetTypeName(const SQObjectPtr &obj1) +{ + return IdType2Name(type(obj1)); +} + +void SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest) +{ + if(is_delegable(obj1) && _delegable(obj1)->_delegate) { + Push(obj1); + if(CallMetaMethod(_delegable(obj1),MT_TYPEOF,1,dest)) + return; + } + dest = SQString::Create(_ss(this),GetTypeName(obj1)); +} + +bool SQVM::Init(SQVM *friendvm, int stacksize) +{ + _stack.resize(stacksize); + _callsstack.reserve(4); + _stackbase = 0; + _top = 0; + if(!friendvm) + _roottable = SQTable::Create(_ss(this), 0); + else { + _roottable = friendvm->_roottable; + _errorhandler = friendvm->_errorhandler; + _debughook = friendvm->_debughook; + } + + sq_base_register(this); + return true; +} + +extern SQInstructionDesc g_InstrDesc[]; + +bool SQVM::StartCall(SQClosure *closure,int target,int nargs,int stackbase,bool tailcall) +{ + SQFunctionProto *func = _funcproto(closure->_function); + //const int outerssize = func->_outervalues.size(); + + const int paramssize = func->_parameters.size(); + const int oldtop = _top; + const int newtop = stackbase + func->_stacksize; + + + if(func->_varparams) + { + if (nargs < paramssize) { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + for(int n = 0; n < nargs - paramssize; n++) { + _vargsstack.push_back(_stack[stackbase+paramssize+n]); + _stack[stackbase+paramssize+n] = _null_; + } + } + else { + if (paramssize != nargs) { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + + } + + if (!tailcall) { + PUSH_CALLINFO(this, CallInfo()); + ci->_etraps = 0; + ci->_prevstkbase = stackbase - _stackbase; + ci->_target = target; + ci->_prevtop = _top - _stackbase; + ci->_ncalls = 1; + ci->_root = false; + } + else { + ci->_ncalls++; + } + ci->_vargs.size = (nargs - paramssize); + ci->_vargs.base = _vargsstack.size()-(nargs - paramssize); + ci->_closure._unVal.pClosure = closure; + ci->_closure._type = OT_CLOSURE; + ci->_iv = &func->_instructions; + ci->_literals = &func->_literals; + //grows the stack if needed + if (((unsigned int)newtop + (func->_stacksize<<1)) > _stack.size()) { + _stack.resize(_stack.size() + (func->_stacksize<<1)); + } + + _top = newtop; + _stackbase = stackbase; + ci->_ip = ci->_iv->_vals; + return true; +} + +bool SQVM::Return(int _arg0, int _arg1, SQObjectPtr &retval) +{ + if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) + for(int i=0;i_ncalls;i++) + CallDebugHook(_SC('r')); + + bool broot = ci->_root; + int last_top = _top; + int target = ci->_target; + int oldstackbase = _stackbase; + _stackbase -= ci->_prevstkbase; + _top = _stackbase + ci->_prevtop; + PopVarArgs(ci->_vargs); + POP_CALLINFO(this); + if (broot) { + if (_arg0 != MAX_FUNC_STACKSIZE) retval = _stack[oldstackbase+_arg1]; + else retval = _null_; + } + else { + if (_arg0 != MAX_FUNC_STACKSIZE) + STK(target) = _stack[oldstackbase+_arg1]; + else + STK(target) = _null_; + } + + while (last_top >= _top) _stack[last_top--].Null(); + assert(oldstackbase >= _stackbase); + return broot; +} + +#define _RET_ON_FAIL(exp) { if(!exp) return false; } + +bool SQVM::LOCAL_INC(int op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) +{ + _RET_ON_FAIL(ARITH_OP( op , target, a, incr)); + a = target; + return true; +} + +bool SQVM::PLOCAL_INC(int op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) +{ + SQObjectPtr trg; + _RET_ON_FAIL(ARITH_OP( op , trg, a, incr)); + target = a; + a = trg; + return true; +} + +bool SQVM::DerefInc(int op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix) +{ + SQObjectPtr tmp, tself = self, tkey = key; + if (!Get(tself, tkey, tmp, false, true)) { Raise_IdxError(tkey); return false; } + _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr)) + Set(tself, tkey, target,true); + if (postfix) target = tmp; + return true; +} + +#define arg0 (_i_._arg0) +#define arg1 (_i_._arg1) +#define sarg1 (*((int *)&_i_._arg1)) +#define arg2 (_i_._arg2) +#define arg3 (_i_._arg3) +#define sarg3 (*((char *)&_i_._arg3)) + +SQRESULT SQVM::Suspend() +{ + if (_suspended) + return sq_throwerror(this, _SC("cannot suspend an already suspended vm")); + if (_nnativecalls!=2) + return sq_throwerror(this, _SC("cannot suspend through native calls/metamethods")); + return SQ_SUSPEND_FLAG; +} + +void SQVM::PopVarArgs(VarArgs &vargs) +{ + for(int n = 0; n< vargs.size; n++) + _vargsstack.pop_back(); +} + +#define _FINISH(stoploop) {finished = stoploop; return true; } +bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr +&o3,SQObjectPtr &o4,int arg_2,bool &finished) +{ + int nrefidx; + switch(type(o1)) { + case OT_TABLE: + if((nrefidx = _table(o1)->Next(o4, o2, o3)) == -1) _FINISH(true); + o4 = (SQInteger)nrefidx; _FINISH(false); + case OT_ARRAY: + if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(true); + o4 = (SQInteger) nrefidx; _FINISH(false); + case OT_STRING: + if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(true); + o4 = (SQInteger)nrefidx; _FINISH(false); + case OT_CLASS: + if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(true); + o4 = (SQInteger)nrefidx; _FINISH(false); + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o1)->_delegate) { + SQObjectPtr itr; + Push(o1); + Push(o4); + if(CallMetaMethod(_delegable(o1), MT_NEXTI, 2, itr)){ + o4 = o2 = itr; + if(type(itr) == OT_NULL) _FINISH(true); + if(!Get(o1, itr, o3, false,false)) { + Raise_Error(_SC("_nexti returned an invalid idx")); + return false; + } + _FINISH(false); + } + Raise_Error(_SC("_nexti failed")); + return false; + } + break; + case OT_GENERATOR: + if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(true); + if(_generator(o1)->_state == SQGenerator::eSuspended) { + SQInteger idx = 0; + if(type(o4) == OT_INTEGER) { + idx = _integer(o4) + 1; + } + o2 = idx; + o4 = idx; + _generator(o1)->Resume(this, arg_2+1); + _FINISH(false); + } + } + Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1)); + return false; //cannot be hit(just to avoid warnings) +} + +bool SQVM::DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2) +{ + if(type(o1) != OT_TABLE) { Raise_Error(_SC("delegating a '%s'"), GetTypeName(o1)); return false; } + switch(type(o2)) { + case OT_TABLE: + if(!_table(o1)->SetDelegate(_table(o2))){ + Raise_Error(_SC("delegate cycle detected")); + return false; + } + break; + case OT_NULL: + _table(o1)->SetDelegate(NULL); + break; + default: + Raise_Error(_SC("using '%s' as delegate"), GetTypeName(o2)); + return false; + break; + } + trg = o1; + return true; +} +#define COND_LITERAL (arg3!=0?(*ci->_literals)[arg1]:STK(arg1)) + +#define _GUARD(exp) { if(!exp) { Raise_Error(_lasterror); SQ_THROW();} } + +#define SQ_THROW() { goto exception_trap; } + +bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func) +{ + int nouters; + SQClosure *closure = SQClosure::Create(_ss(this), func); + if(nouters = func->_outervalues.size()) { + closure->_outervalues.reserve(nouters); + for(int i = 0; i_outervalues[i]; + switch(v._type){ + case otSYMBOL: + closure->_outervalues.push_back(_null_); + if(!Get(_stack._vals[_stackbase]/*STK(0)*/, v._src, closure->_outervalues.top(), false,true)) + {Raise_IdxError(v._src); return false; } + break; + case otLOCAL: + closure->_outervalues.push_back(_stack._vals[_stackbase+_integer(v._src)]); + break; + case otOUTER: + closure->_outervalues.push_back(_closure(ci->_closure)->_outervalues[_integer(v._src)]); + break; + } + } + } + target = closure; + return true; + +} + +bool SQVM::GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &index,CallInfo *ci) +{ + if(ci->_vargs.size == 0) { + Raise_Error(_SC("the function doesn't have var args")); + return false; + } + if(!sq_isnumeric(index)){ + Raise_Error(_SC("indexing 'vargv' with %s"),GetTypeName(index)); + return false; + } + int idx = tointeger(index); + if(idx < 0 || idx >= ci->_vargs.size){ Raise_Error(_SC("vargv index out of range")); return false; } + target = _vargsstack[ci->_vargs.base+idx]; + return true; +} + +bool SQVM::CLASS_OP(SQObjectPtr &target,int baseclass,int attributes) +{ + SQClass *base = NULL; + SQObjectPtr attrs; + if(baseclass != MAX_LITERALS) { + if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; } + base = _class(_stack._vals[_stackbase + baseclass]); + } + if(attributes != MAX_FUNC_STACKSIZE) { + attrs = _stack._vals[_stackbase+attributes]; + } + target = SQClass::Create(_ss(this),base); + _class(target)->_attributes = attrs; + return true; +} + +bool SQVM::IsFalse(SQObjectPtr &o) +{ + SQObjectType t = type(o); + if((t & SQOBJECT_CANBEFALSE) + && ((t == OT_NULL) || ((t == OT_INTEGER || t == OT_BOOL) && _integer(o) == 0) + || (t == OT_FLOAT && _float(o) == SQFloat(0.0)))) { + return true; + } + return false; +} + +bool SQVM::IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res) +{ + if(type(o1) == type(o2)) { + res = ((_userpointer(o1) == _userpointer(o2)?true:false)); + } + else { + if(sq_isnumeric(o1) && sq_isnumeric(o2)) { + int cmpres; + if(!ObjCmp(o1, o2,cmpres)) return false; + res = (cmpres == 0); + } + else { + res = false; + } + } + return true; +} + +bool SQVM::Execute(SQObjectPtr &closure, int target, int nargs, int stackbase,SQObjectPtr &outres, ExecutionType et) +{ + if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } + _nnativecalls++; + AutoDec ad(&_nnativecalls); + int traps = 0; + //temp_reg vars for OP_CALL + int ct_target; + bool ct_tailcall; + + switch(et) { + case ET_CALL: + if(!StartCall(_closure(closure), _top - nargs, nargs, stackbase, false)) { + //call the handler if there are no calls in the stack, if not relies on the previous node + if(ci == NULL) CallErrorHandler(_lasterror); + return false; + } + ci->_root = true; + break; + case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, target); ci->_root = true; traps += ci->_etraps; break; + case ET_RESUME_VM: + traps = _suspended_traps; + ci->_root = _suspended_root; + _suspended = false; + break; + } + +exception_restore: + //SQ_TRY + { + for(;;) + { + const SQInstruction &_i_ = *ci->_ip++; + //dumpstack(_stackbase); + //scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-ci->_iv->_vals,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3); + switch(_i_.op) + { + case _OP_LINE: + if(type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) + CallDebugHook(_SC('l'),arg1); + continue; + case _OP_LOAD: TARGET = (*ci->_literals)[arg1]; continue; + case _OP_TAILCALL: + temp_reg = STK(arg1); + if (type(temp_reg) == OT_CLOSURE){ + ct_tailcall = true; + PopVarArgs(ci->_vargs); + for (int i = 0; i < arg3; i++) STK(i) = STK(arg2 + i); + ct_target = ci->_target; + goto common_call; + } + case _OP_CALL: { + ct_tailcall = false; + ct_target = arg0; + temp_reg = STK(arg1); +common_call: + int last_top = _top; + switch (type(temp_reg)) { + case OT_CLOSURE:{ + StartCall(_closure(temp_reg), ct_target, arg3, ct_tailcall?_stackbase:_stackbase+arg2, ct_tailcall); + if (_funcproto(_closure(temp_reg)->_function)->_bgenerator) { + SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(temp_reg)); + _GUARD(gen->Yield(this)); + Return(1, ct_target, temp_reg); + STK(ct_target) = gen; + while (last_top >= _top) _stack[last_top--].Null(); + continue; + } + if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) + CallDebugHook(_SC('c')); + } + break; + case OT_NATIVECLOSURE: { + bool suspend; + _GUARD(CallNative(_nativeclosure(temp_reg), arg3, _stackbase+arg2, ct_tailcall, temp_reg,suspend)); + if(suspend){ + _suspended = true; + _suspended_target = ct_target; + _suspended_root = ci->_root; + _suspended_traps = traps; + outres = temp_reg; + return true; + } + STK(ct_target) = temp_reg; + } + break; + case OT_CLASS:{ + _GUARD(CreateClassInstance(_class(temp_reg),arg3,_stackbase+arg2,STK(ct_target))); + } + break; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + { + Push(temp_reg); + for (int i = 0; i < arg3; i++) Push(STK(arg2 + i)); + if (_delegable(temp_reg) && CallMetaMethod(_delegable(temp_reg), MT_CALL, arg3+1, temp_reg)){ + STK(ct_target) = temp_reg; + break; + } + Raise_Error(_SC("attempt to call '%s'"), GetTypeName(temp_reg)); + SQ_THROW(); + } + default: + Raise_Error(_SC("attempt to call '%s'"), GetTypeName(temp_reg)); + SQ_THROW(); + } + } + continue; + case _OP_PREPCALL: + if (!Get(STK(arg2), STK(arg1), temp_reg, false,true)) + { Raise_IdxError(STK(arg1)); SQ_THROW(); } + goto common_prepcall; + case _OP_PREPCALLK: + if (!Get(STK(arg2), (*ci->_literals)[arg1], temp_reg,false,true)) { + if(type(STK(arg2)) == OT_CLASS) { //hack? + if(_class_ddel->Get((*ci->_literals)[arg1],temp_reg)) { + STK(arg3) = STK(arg2); + TARGET = temp_reg; + continue; + } + } + { Raise_IdxError((*ci->_literals)[arg1]); SQ_THROW();} + } +common_prepcall: + if(type(STK(arg2)) == OT_CLASS) { + STK(arg3) = STK(0); // this + } + else { + STK(arg3) = STK(arg2); + } + TARGET = temp_reg; + continue; + case _OP_GETK: + if (!Get(STK(arg2), (*ci->_literals)[arg1], temp_reg, false,true)) { Raise_IdxError((*ci->_literals)[arg1]); SQ_THROW();} + TARGET = temp_reg; + continue; + case _OP_MOVE: TARGET = STK(arg1); continue; + case _OP_NEWSLOT: + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3))); + if(arg0 != arg3) TARGET = STK(arg3); + continue; + case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue; + case _OP_SET: + if (!Set(STK(arg1), STK(arg2), STK(arg3),true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); } + if (arg0 != arg3) TARGET = STK(arg3); + continue; + case _OP_GET: + if (!Get(STK(arg1), STK(arg2), temp_reg, false,true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); } + TARGET = temp_reg; + continue; + case _OP_EQ:{ + bool res; + if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } + TARGET = res?_true_:_false_; + }continue; + case _OP_NE:{ + bool res; + if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } + TARGET = (!res)?_true_:_false_; + } continue; + case _OP_ARITH: _GUARD(ARITH_OP( arg3 , temp_reg, STK(arg2), STK(arg1))); TARGET = temp_reg; continue; + case _OP_BITW: _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue; + case _OP_RETURN: + if(type((ci)->_generator) == OT_GENERATOR) { + _generator((ci)->_generator)->Kill(); + } + if(Return(arg0, arg1, temp_reg)){ + assert(traps==0); + outres = temp_reg; + return true; + } + continue; + case _OP_LOADNULLS:{ for(unsigned int n=0;n_ip += (sarg1); continue; + case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; + case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; + case _OP_LOADFREEVAR: TARGET = _closure(ci->_closure)->_outervalues[arg1]; continue; + case _OP_VARGC: TARGET = SQInteger(ci->_vargs.size); continue; + case _OP_GETVARGV: + if(!GETVARGV_OP(TARGET,STK(arg1),ci)) { SQ_THROW(); } + continue; + case _OP_NEWTABLE: TARGET = SQTable::Create(_ss(this), arg1); continue; + case _OP_NEWARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue; + case _OP_APPENDARRAY: _array(STK(arg0))->Append(COND_LITERAL); continue; + case _OP_GETPARENT: + switch(type(STK(arg1))) { + case OT_TABLE: + TARGET = _table(STK(arg1))->_delegate?SQObjectPtr(_table(STK(arg1))->_delegate):_null_; + continue; + case OT_CLASS: TARGET = _class(STK(arg1))->_base?_class(STK(arg1))->_base:_null_; + continue; + } + Raise_Error(_SC("the %s type doesn't have a parent slot"), GetTypeName(STK(arg1))); + SQ_THROW(); + continue; + case _OP_COMPARITH: _GUARD(DerefInc(arg3, TARGET, STK((((unsigned int)arg1&0xFFFF0000)>>16)), STK(arg2), STK(arg1&0x0000FFFF), false)); continue; + case _OP_COMPARITHL: _GUARD(LOCAL_INC(arg3, TARGET, STK(arg1), STK(arg2))); continue; + case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false));} continue; + case _OP_INCL: {SQObjectPtr o(sarg3); _GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));} continue; + case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true));} continue; + case _OP_PINCL: {SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));} continue; + case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue; + case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,false)?_true_:_false_;continue; + case _OP_INSTANCEOF: + if(type(STK(arg1)) != OT_CLASS || type(STK(arg2)) != OT_INSTANCE) + {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();} + TARGET = _instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?_true_:_false_; + continue; + case _OP_AND: + if(IsFalse(STK(arg2))) { + TARGET = STK(arg2); + ci->_ip += (sarg1); + } + continue; + case _OP_OR: + if(!IsFalse(STK(arg2))) { + TARGET = STK(arg2); + ci->_ip += (sarg1); + } + continue; + case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue; + case _OP_NOT: TARGET = (IsFalse(STK(arg1))?_true_:_false_); continue; + case _OP_BWNOT: + if(type(STK(arg1)) == OT_INTEGER) { + TARGET = SQInteger(~_integer(STK(arg1))); + continue; + } + Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1))); + SQ_THROW(); + case _OP_CLOSURE: { + SQClosure *c = ci->_closure._unVal.pClosure; + SQFunctionProto *fp = c->_function._unVal.pFunctionProto; + if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); } + continue; + } + case _OP_YIELD:{ + if(type(ci->_generator) == OT_GENERATOR) { + if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1); + _GUARD(_generator(ci->_generator)->Yield(this)); + traps -= ci->_etraps; + if(sarg1 != MAX_FUNC_STACKSIZE) STK(arg1) = temp_reg; + } + else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();} + if(Return(arg0, arg1, temp_reg)){ + assert(traps==0); + outres = temp_reg; + return true; + } + + } + continue; + case _OP_RESUME: + if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error(_SC("trying to resume a '%s',only genenerator can be resumed"), GetTypeName(STK(arg1))); SQ_THROW();} + _GUARD(_generator(STK(arg1))->Resume(this, arg0)); + traps += ci->_etraps; + continue; + case _OP_FOREACH:{ bool finished; + _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,finished)); + if(finished) ci->_ip += sarg1; } + continue; + case _OP_DELEGATE: _GUARD(DELEGATE_OP(TARGET,STK(arg1),STK(arg2))); continue; + case _OP_CLONE: + if(!Clone(STK(arg1), TARGET)) + { Raise_Error(_SC("cloning a %s"), GetTypeName(STK(arg1))); SQ_THROW();} + continue; + case _OP_TYPEOF: TypeOf(STK(arg1), TARGET); continue; + case _OP_PUSHTRAP: + _etraps.push_back(SQExceptionTrap(_top,_stackbase, &ci->_iv->_vals[(ci->_ip-ci->_iv->_vals)+arg1], arg0)); traps++; + ci->_etraps++; + continue; + case _OP_POPTRAP:{ + for(int i=0; i_etraps--; + }} + continue; + case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue; + case _OP_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue; + case _OP_NEWSLOTA: + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3))); + _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1)); + if(arg0 != arg3) TARGET = STK(arg3); + continue; + } + + } + } +exception_trap: + { + SQObjectPtr currerror = _lasterror; +// dumpstack(_stackbase); + int n = 0; + int last_top = _top; + if(ci) { + if(traps) { + do { + if(ci->_etraps > 0) { + SQExceptionTrap &et = _etraps.top(); + ci->_ip = et._ip; + _top = et._stacksize; + _stackbase = et._stackbase; + _stack[_stackbase+et._extarget] = currerror; + _etraps.pop_back(); traps--; ci->_etraps--; + while(last_top >= _top) _stack[last_top--].Null(); + goto exception_restore; + } + //if is a native closure + if(type(ci->_closure) != OT_CLOSURE && n) + break; + if(type(ci->_generator) == OT_GENERATOR) _generator(ci->_generator)->Kill(); + PopVarArgs(ci->_vargs); + POP_CALLINFO(this); + n++; + }while(_callsstack.size()); + } + //call the hook + CallErrorHandler(currerror); + //remove call stack until a C function is found or the cstack is empty + if(ci) do{ + bool exitafterthisone = ci->_root; + if(type(ci->_generator) == OT_GENERATOR) _generator(ci->_generator)->Kill(); + _stackbase -= ci->_prevstkbase; + _top = _stackbase + ci->_prevtop; + PopVarArgs(ci->_vargs); + POP_CALLINFO(this); + if( (ci && type(ci->_closure) != OT_CLOSURE) || exitafterthisone) break; + }while(_callsstack.size()); + + while(last_top >= _top) _stack[last_top--].Null(); + } + _lasterror = currerror; + return false; + } + assert(0); +} + +bool SQVM::CreateClassInstance(SQClass *theclass, int nargs, int stackbase, SQObjectPtr &retval) +{ + SQObjectPtr constr; + SQObjectPtr inst = theclass->CreateInstance(); + _stack[stackbase] = inst; + if(theclass->Get(_ss(this)->_constructoridx,constr)) { + if(!Call(constr,nargs,stackbase,constr)) + return false; + } + retval = inst; + return true; +} + +void SQVM::CallErrorHandler(SQObjectPtr &error) +{ + if(type(_errorhandler) != OT_NULL) { + SQObjectPtr out; + Push(_roottable); Push(error); + Call(_errorhandler, 2, _top-2, out); + Pop(2); + } +} + +void SQVM::CallDebugHook(int type,int forcedline) +{ + SQObjectPtr temp_reg; + int nparams=5; + SQFunctionProto *func=_funcproto(_closure(ci->_closure)->_function); + Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name); + Call(_debughook,nparams,_top-nparams,temp_reg); + Pop(nparams); +} + +bool SQVM::CallNative(SQNativeClosure *nclosure,int nargs,int stackbase,bool tailcall,SQObjectPtr &retval,bool &suspend) +{ + if (_nnativecalls + 1 > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } + int nparamscheck = nclosure->_nparamscheck; + if(((nparamscheck > 0) && (nparamscheck != nargs)) + || ((nparamscheck < 0) && (nargs < (-nparamscheck)))) { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + + int tcs; + if(tcs = nclosure->_typecheck.size()) { + for(int i = 0; i < nargs && i < tcs; i++) + if((nclosure->_typecheck[i] != -1) && !(type(_stack[stackbase+i]) & nclosure->_typecheck[i])) { + Raise_ParamTypeError(i,nclosure->_typecheck[i],type(_stack[stackbase+i])); + return false; + } + } + _nnativecalls++; + if ((_top + MIN_STACK_OVERHEAD) > (int)_stack.size()) { + _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD<<1)); + } + int oldtop = _top; + int oldstackbase = _stackbase; + _top = stackbase + nargs; + PUSH_CALLINFO(this, CallInfo()); + ci->_etraps = 0; + ci->_closure._unVal.pNativeClosure = nclosure; + ci->_closure._type = OT_NATIVECLOSURE; + ci->_prevstkbase = stackbase - _stackbase; + ci->_ncalls = 1; + _stackbase = stackbase; + //push free variables + int outers = nclosure->_outervalues.size(); + for (int i = 0; i < outers; i++) { + Push(nclosure->_outervalues[i]); + } + ci->_prevtop = (oldtop - oldstackbase); + int ret = (nclosure->_function)(this); + _nnativecalls--; + suspend = false; + if( ret == SQ_SUSPEND_FLAG) suspend = true; + else if (ret < 0) { + _stackbase = oldstackbase; + _top = oldtop; + POP_CALLINFO(this); + Raise_Error(_lasterror); + return false; + } + + if (ret != 0){ retval = TOP(); } + else { retval = _null_; } + _stackbase = oldstackbase; + _top = oldtop; + POP_CALLINFO(this); + return true; +} + +bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, bool fetchroot) +{ + switch(type(self)){ + case OT_TABLE: + if(_table(self)->Get(key,dest))return true; + break; + case OT_ARRAY: + if(sq_isnumeric(key)){ + return _array(self)->Get(tointeger(key),dest); + } + break; + case OT_INSTANCE: + if(_instance(self)->Get(key,dest)) return true; + break; + } + if(FallBackGet(self,key,dest,raw)) return true; + + if(fetchroot) { + if(_rawval(STK(0)) == _rawval(self) && + type(STK(0)) == type(self)) { + return _table(_roottable)->Get(key,dest); + } + } + return false; +} + +bool SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw) +{ + switch(type(self)){ + case OT_CLASS: + return _class(self)->Get(key,dest); + break; + case OT_TABLE: + case OT_USERDATA: + //delegation + if(_delegable(self)->_delegate) { + if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,raw,false)) + return true; + if(raw)return false; + Push(self);Push(key); + if(CallMetaMethod(_delegable(self),MT_GET,2,dest)) + return true; + } + if(type(self) == OT_TABLE) { + if(raw) return false; + return _table_ddel->Get(key,dest); + } + return false; + break; + case OT_ARRAY: + if(raw)return false; + return _array_ddel->Get(key,dest); + case OT_STRING: + if(sq_isnumeric(key)){ + SQInteger n=tointeger(key); + if(abs(n)<_string(self)->_len){ + if(n<0)n=_string(self)->_len-n; + dest=SQInteger(_stringval(self)[n]); + return true; + } + return false; + } + else { + if(raw)return false; + return _string_ddel->Get(key,dest); + } + break; + case OT_INSTANCE: + if(raw)return false; + Push(self);Push(key); + if(!CallMetaMethod(_delegable(self),MT_GET,2,dest)) { + return _instance_ddel->Get(key,dest); + } + return true; + case OT_INTEGER:case OT_FLOAT:case OT_BOOL: + if(raw)return false; + return _number_ddel->Get(key,dest); + case OT_GENERATOR: + if(raw)return false; + return _generator_ddel->Get(key,dest); + case OT_CLOSURE: case OT_NATIVECLOSURE: + if(raw)return false; + return _closure_ddel->Get(key,dest); + case OT_THREAD: + if(raw)return false; + return _thread_ddel->Get(key,dest); + default:return false; + } + return false; +} + +bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool fetchroot) +{ + switch(type(self)){ + case OT_TABLE: + if(_table(self)->Set(key,val)) + return true; + if(_table(self)->_delegate) { + if(Set(_table(self)->_delegate,key,val,false)) { + return true; + } + } + //keeps going + case OT_USERDATA: + if(_delegable(self)->_delegate) { + SQObjectPtr t; + Push(self);Push(key);Push(val); + if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true; + } + break; + case OT_INSTANCE:{ + if(_instance(self)->Set(key,val)) + return true; + SQObjectPtr t; + Push(self);Push(key);Push(val); + if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true; + } + break; + case OT_ARRAY: + if(!sq_isnumeric(key)) {Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; } + return _array(self)->Set(tointeger(key),val); + default: + Raise_Error(_SC("trying to set '%s'"),GetTypeName(self)); + return false; + } + if(fetchroot) { + if(_rawval(STK(0)) == _rawval(self) && + type(STK(0)) == type(self)) { + return _table(_roottable)->Set(key,val); + } + } + return false; +} + +bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target) +{ + SQObjectPtr temp_reg; + switch(type(self)){ + case OT_TABLE: + target = _table(self)->Clone(); + goto cloned_mt; + case OT_INSTANCE: + target = _instance(self)->Clone(_ss(this)); +cloned_mt: + if(_delegable(target)->_delegate){ + Push(target); + Push(self); + CallMetaMethod(_delegable(target),MT_CLONED,2,temp_reg); + } + return true; + case OT_ARRAY: + target=_array(self)->Clone(); + return true; + default: return false; + } +} + +bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val) +{ + if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; } + switch(type(self)) { + case OT_TABLE: { + bool rawcall = true; + if(_table(self)->_delegate) { + SQObjectPtr res; + if(!_table(self)->Get(key,res)) { + Push(self);Push(key);Push(val); + rawcall = !CallMetaMethod(_table(self),MT_NEWSLOT,3,res); + } + } + if(rawcall) _table(self)->NewSlot(key,val); //cannot fail + + break;} + case OT_CLASS: + if(!_class(self)->NewSlot(key,val)) { + if(_class(self)->_locked) { + Raise_Error(_SC("trying to modify a class that has already been instantiated")); + return false; + } + else { + SQObjectPtr oval = PrintObjVal(key); + Raise_Error(_SC("the property '%s' already exists"),_stringval(oval)); + return false; + } + } + break; + default: + Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); + return false; + break; + } + return true; +} + +bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res) +{ + switch(type(self)) { + case OT_TABLE: + case OT_INSTANCE: + case OT_USERDATA: { + SQObjectPtr t; + bool handled = false; + if(_delegable(self)->_delegate) { + Push(self);Push(key); + handled = CallMetaMethod(_delegable(self),MT_DELSLOT,2,t); + } + + if(!handled) { + if(type(self) == OT_TABLE) { + if(_table(self)->Get(key,t)) { + _table(self)->Remove(key); + } + else { + Raise_IdxError((SQObject &)key); + return false; + } + } + else { + Raise_Error(_SC("cannot delete a slot from %s"),GetTypeName(self)); + return false; + } + } + res = t; + } + break; + default: + Raise_Error(_SC("attempt to delete a slot from a %s"),GetTypeName(self)); + return false; + } + return true; +} + +bool SQVM::Call(SQObjectPtr &closure,int nparams,int stackbase,SQObjectPtr &outres) +{ +#ifdef _DEBUG +int prevstackbase = _stackbase; +#endif + switch(type(closure)) { + case OT_CLOSURE: + return Execute(closure, _top - nparams, nparams, stackbase,outres); + break; + case OT_NATIVECLOSURE:{ + bool suspend; + return CallNative(_nativeclosure(closure), nparams, stackbase, false, outres,suspend); + + } + break; + case OT_CLASS: + return CreateClassInstance(_class(closure),nparams,stackbase,outres); + break; + default: + return false; + } +#ifdef _DEBUG + if(!_suspended) { + assert(_stackbase == prevstackbase); + } +#endif + return true; +} + +bool SQVM::CallMetaMethod(SQDelegable *del,SQMetaMethod mm,int nparams,SQObjectPtr &outres) +{ + SQObjectPtr closure; + if(del->GetMetaMethod(mm, closure)) { + if(Call(closure, nparams, _top - nparams, outres)) { + Pop(nparams); + return true; + } + } + Pop(nparams); + return false; +} + +void SQVM::Pop() { + _stack[--_top] = _null_; +} +void SQVM::Pop(int n) { + for(int i = 0; i < n; i++){ + _stack[--_top] = _null_; + } +} + +void SQVM::Remove(int n) { + n = (n >= 0)?n + _stackbase - 1:_top + n; + for(int i = n; i < _top; i++){ + _stack[i] = _stack[i+1]; + } + _stack[_top] = _null_; + _top--; +} + +void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; } +SQObjectPtr &SQVM::Top() { return _stack[_top-1]; } +SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; } +SQObjectPtr &SQVM::GetUp(int n) { return _stack[_top+n]; } +SQObjectPtr &SQVM::GetAt(int n) { return _stack[n]; } + +#ifdef _DEBUG_DUMP +void SQVM::dumpstack(int stackbase,bool dumpall) +{ + int size=dumpall?_stack.size():_top; + int n=0; + scprintf(_SC("\n>>>>stack dump<<<<\n")); + CallInfo &ci=_callsstack.back(); + scprintf(_SC("IP: %d\n"),ci._ip); + scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase); + scprintf(_SC("prev top: %d\n"),ci._prevtop); + for(int i=0;i"));else scprintf(_SC(" ")); + scprintf(_SC("[%d]:"),n); + switch(type(obj)){ + case OT_FLOAT: scprintf(_SC("FLOAT %.3f"),_float(obj));break; + case OT_INTEGER: scprintf(_SC("INTEGER %d"),_integer(obj));break; + case OT_BOOL: scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break; + case OT_STRING: scprintf(_SC("STRING %s"),_stringval(obj));break; + case OT_NULL: scprintf(_SC("NULL")); break; + case OT_TABLE: scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break; + case OT_ARRAY: scprintf(_SC("ARRAY %p"),_array(obj));break; + case OT_CLOSURE: scprintf(_SC("CLOSURE [%p]"),_closure(obj));break; + case OT_NATIVECLOSURE: scprintf(_SC("NATIVECLOSURE"));break; + case OT_USERDATA: scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break; + case OT_GENERATOR: scprintf(_SC("GENERATOR"));break; + case OT_THREAD: scprintf(_SC("THREAD [%p]"),_thread(obj));break; + case OT_USERPOINTER: scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break; + case OT_CLASS: scprintf(_SC("CLASS %p"),_class(obj));break; + case OT_INSTANCE: scprintf(_SC("INSTANCE %p"),_instance(obj));break; + default: + assert(0); + break; + }; + scprintf(_SC("\n")); + ++n; + } +} + +#endif diff --git a/src/squirrel/squirrel/sqvm.h b/src/squirrel/squirrel/sqvm.h new file mode 100644 index 000000000..7ba178ce1 --- /dev/null +++ b/src/squirrel/squirrel/sqvm.h @@ -0,0 +1,189 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQVM_H_ +#define _SQVM_H_ + +#include "sqopcodes.h" +#include "sqobject.h" +#define MAX_NATIVE_CALLS 100 +#define MIN_STACK_OVERHEAD 10 + +#define SQ_SUSPEND_FLAG -666 +//base lib +void sq_base_register(HSQUIRRELVM v); + +struct SQExceptionTrap{ + SQExceptionTrap() {} + SQExceptionTrap(int ss, int stackbase,SQInstruction *ip, int ex_target){ _stacksize = ss; _stackbase = stackbase; _ip = ip; _extarget = ex_target;} + SQExceptionTrap(const SQExceptionTrap &et) { (*this) = et; } + int _stackbase; + int _stacksize; + SQInstruction *_ip; + int _extarget; +}; + + +#define STK(a) _stack._vals[_stackbase+(a)] +#define TARGET _stack._vals[_stackbase+arg0] + +typedef sqvector ExceptionsTraps; + +struct SQVM : public CHAINABLE_OBJ +{ + struct VarArgs { + VarArgs() { size = 0; base = 0; } + int size; + int base; + }; + + struct CallInfo{ + //CallInfo() {} + //CallInfo(const CallInfo& ci) { } + SQInstructionVec *_iv; + SQObjectPtrVec *_literals; + SQObject _closure; + SQObject _generator; + int _etraps; + int _prevstkbase; + int _prevtop; + int _target; + SQInstruction *_ip; + int _ncalls; + bool _root; + VarArgs _vargs; + }; + +typedef sqvector CallInfoVec; +public: + enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM }; + SQVM(SQSharedState *ss); + ~SQVM(); + bool Init(SQVM *friendvm, int stacksize); + bool Execute(SQObjectPtr &func, int target, int nargs, int stackbase, SQObjectPtr &outres, ExecutionType et = ET_CALL); + //start a native call return when the NATIVE closure returns(returns true if the vm has been suspended) + bool CallNative(SQNativeClosure *nclosure, int nargs, int stackbase, bool tailcall, SQObjectPtr &retval,bool &suspend); + //start a SQUIRREL call in the same "Execution loop" + bool StartCall(SQClosure *closure, int target, int nargs, int stackbase, bool tailcall); + bool CreateClassInstance(SQClass *theclass, int nargs, int stackbase, SQObjectPtr &retval); + //call a generic closure pure SQUIRREL or NATIVE + bool Call(SQObjectPtr &closure, int nparams, int stackbase, SQObjectPtr &outres); + SQRESULT Suspend(); + + void CallDebugHook(int type,int forcedline=0); + void CallErrorHandler(SQObjectPtr &e); + bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, bool fetchroot); + bool FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw); + bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, bool fetchroot); + bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val); + bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res); + bool Clone(const SQObjectPtr &self, SQObjectPtr &target); + bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,int &res); + bool StringCat(const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest); + bool IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res); + bool IsFalse(SQObjectPtr &o); + SQString *PrintObjVal(const SQObject &o); + + + void Raise_Error(const SQChar *s, ...); + void Raise_Error(SQObjectPtr &desc); + void Raise_IdxError(SQObject &o); + void Raise_CompareError(const SQObject &o1, const SQObject &o2); + void Raise_ParamTypeError(int nparam,int typemask,int type); + + void TypeOf(const SQObjectPtr &obj1, SQObjectPtr &dest); + bool CallMetaMethod(SQDelegable *del, SQMetaMethod mm, int nparams, SQObjectPtr &outres); + bool ArithMetaMethod(int op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest); + //void Modulo(const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest); + bool Return(int _arg0, int _arg1, SQObjectPtr &retval); + //new stuff + bool ARITH_OP(unsigned int op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); + bool BW_OP(unsigned int op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); + bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1); + bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res); + bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func); + bool GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &idx,CallInfo *ci); + bool CLASS_OP(SQObjectPtr &target,int base,int attrs); + //return true if the loop is finished + bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,int arg_2,bool &finished); + bool DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2); + bool LOCAL_INC(int op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); + bool PLOCAL_INC(int op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); + bool DerefInc(int op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix); + void PopVarArgs(VarArgs &vargs); +#ifdef _DEBUG_DUMP + void dumpstack(int stackbase=-1, bool dumpall = false); +#endif + +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + void Finalize(); + + void Release(){ sq_delete(this,SQVM); } //does nothing +//////////////////////////////////////////////////////////////////////////// + //stack functions for the api + void Pop(); + void Pop(int n); + void Remove(int n); + + void Push(const SQObjectPtr &o); + SQObjectPtr &Top(); + SQObjectPtr &PopGet(); + SQObjectPtr &GetUp(int n); + SQObjectPtr &GetAt(int n); + + SQObjectPtrVec _stack; + SQObjectPtrVec _vargsstack; + int _top; + int _stackbase; + SQObjectPtr _roottable; + //SQObjectPtr _thrownerror; + SQObjectPtr _lasterror; + SQObjectPtr _errorhandler; + SQObjectPtr _debughook; + + SQObjectPtr temp_reg; + CallInfoVec _callsstack; + ExceptionsTraps _etraps; + CallInfo *ci; + void *_foreignptr; + //VMs sharing the same state + SQSharedState *_sharedstate; + int _nnativecalls; + //suspend infos + bool _suspended; + bool _suspended_root; + int _suspended_target; + int _suspended_traps; +}; + +struct AutoDec{ + AutoDec(int *n) { _n = n; } + ~AutoDec() { (*_n)--; } + int *_n; +}; + +SQObjectPtr &stack_get(HSQUIRRELVM v, int idx); +const SQChar *GetTypeName(const SQObjectPtr &obj1); +const SQChar *IdType2Name(SQObjectType type); + +#define _ss(_vm_) (_vm_)->_sharedstate + +#ifndef NO_GARBAGE_COLLECTOR +#define _opt_ss(_vm_) (_vm_)->_sharedstate +#else +#define _opt_ss(_vm_) NULL +#endif + +#define PUSH_CALLINFO(v,nci){ \ + v->_callsstack.push_back(nci); \ + v->ci = &v->_callsstack.back(); \ +} + +#define POP_CALLINFO(v){ \ + v->_callsstack.pop_back(); \ + if(v->_callsstack.size()) \ + v->ci = &v->_callsstack.back() ; \ + else \ + v->ci = NULL; \ +} +#endif //_SQVM_H_ diff --git a/src/statistics.cpp b/src/statistics.cpp index 2ea2e49c3..beff2c2d1 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -20,10 +20,10 @@ #include #include "video/drawing_context.h" -#include "app/gettext.h" -#include "app/globals.h" +#include "gettext.h" #include "lisp/lisp.h" #include "resources.h" +#include "main.h" #include "statistics.h" Statistics global_stats; diff --git a/src/statistics.h b/src/statistics.h index 218c02751..2030b281e 100644 --- a/src/statistics.h +++ b/src/statistics.h @@ -24,8 +24,6 @@ #include "lisp/lisp.h" #include "lisp/writer.h" -using namespace SuperTux; - class DrawingContext; #define SPLAYER 0 diff --git a/src/textscroller.cpp b/src/textscroller.cpp index 9f7a5dd56..859ca3092 100644 --- a/src/textscroller.cpp +++ b/src/textscroller.cpp @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #include #include "textscroller.h" @@ -26,7 +25,6 @@ #include "resources.h" #include "video/font.h" #include "video/drawing_context.h" -#include "app/globals.h" #include "lisp/parser.h" #include "lisp/lisp.h" #include "main.h" diff --git a/src/tile.cpp b/src/tile.cpp index 901dfcd2c..20835fbd9 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -24,7 +24,6 @@ #include #include -#include "app/globals.h" #include "lisp/lisp.h" #include "tile.h" #include "resources.h" diff --git a/src/tile.h b/src/tile.h index a5f5856fc..a9ea335a7 100644 --- a/src/tile.h +++ b/src/tile.h @@ -25,8 +25,6 @@ #include "math/rectangle.h" #include "lisp/lisp.h" -using namespace SuperTux; - /** Tile Class */ diff --git a/src/tile_manager.cpp b/src/tile_manager.cpp index e3a5b59a6..37cf79a9d 100644 --- a/src/tile_manager.cpp +++ b/src/tile_manager.cpp @@ -23,8 +23,6 @@ #include #include #include "video/drawing_context.h" -#include "app/setup.h" -#include "app/globals.h" #include "lisp/lisp.h" #include "lisp/parser.h" #include "lisp/list_iterator.h" diff --git a/src/timer.cpp b/src/timer.cpp index 7b2854cab..8166e85e5 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #include #include diff --git a/src/timer.h b/src/timer.h index 88441839f..d7f037362 100644 --- a/src/timer.h +++ b/src/timer.h @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __SUPERTUX_TIMER_H__ #define __SUPERTUX_TIMER_H__ diff --git a/src/tinygettext/tinygettext.cpp b/src/tinygettext/tinygettext.cpp new file mode 100644 index 000000000..dd73e8028 --- /dev/null +++ b/src/tinygettext/tinygettext.cpp @@ -0,0 +1,701 @@ +// $Id$ +// +// TinyGetText - A small flexible gettext() replacement +// Copyright (C) 2004 Ingo Ruhnke +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include + +#include +#include +#include +#include +#include +#include +#include +#include "tinygettext.h" + +//#define TRANSLATION_DEBUG + +namespace TinyGetText { + +/** Convert \a which is in \a from_charset to \a to_charset and return it */ +std::string convert(const std::string& text, + const std::string& from_charset, + const std::string& to_charset) +{ + if (from_charset == to_charset) + return text; + + iconv_t cd = iconv_open(to_charset.c_str(), from_charset.c_str()); + + size_t in_len = text.length(); + size_t out_len = text.length()*3; // FIXME: cross fingers that this is enough + + char* out_orig = new char[out_len]; + char* in_orig = new char[in_len+1]; + strcpy(in_orig, text.c_str()); + + char* out = out_orig; + char* in = in_orig; + size_t out_len_temp = out_len; // iconv is counting down the bytes it has + // written from this... + + size_t retval = iconv(cd, &in, &in_len, &out, &out_len_temp); + out_len -= out_len_temp; // see above + if (retval == (size_t) -1) + { + std::cerr << strerror(errno) << std::endl; + std::cerr << "Error: conversion from " << from_charset + << " to " << to_charset << " went wrong: " << retval << std::endl; + return ""; + } + iconv_close(cd); + + std::string ret(out_orig, out_len); + delete[] out_orig; + delete[] in_orig; + return ret; +} + +bool has_suffix(const std::string& lhs, const std::string rhs) +{ + if (lhs.length() < rhs.length()) + return false; + else + return lhs.compare(lhs.length() - rhs.length(), rhs.length(), rhs) == 0; +} + +bool has_prefix(const std::string& lhs, const std::string rhs) +{ + if (lhs.length() < rhs.length()) + return false; + else + return lhs.compare(0, rhs.length(), rhs) == 0; +} + +int plural1(int ) { return 0; } +int plural2_1(int n) { return (n != 1); } +int plural2_2(int n) { return (n > 1); } +int plural3_lv(int n) { return (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); } +int plural3_ga(int n) { return n==1 ? 0 : n==2 ? 1 : 2; } +int plural3_lt(int n) { return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); } +int plural3_1(int n) { return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } +int plural3_sk(int n) { return (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; } +int plural3_pl(int n) { return (n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } +int plural3_sl(int n) { return (n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3); } + +/** Language Definitions */ +//*{ +LanguageDef lang_hu("hu", "Hungarian", 1, plural1); // "nplurals=1; plural=0;" +LanguageDef lang_ja("ja", "Japanese", 1, plural1); // "nplurals=1; plural=0;" +LanguageDef lang_ko("ko", "Korean", 1, plural1); // "nplurals=1; plural=0;" +LanguageDef lang_tr("tr", "Turkish", 1, plural1); // "nplurals=1; plural=0;" +LanguageDef lang_da("da", "Danish", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_nl("nl", "Dutch", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_en("en", "English", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_fo("fo", "Faroese", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_de("de", "German", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_nb("nb", "Norwegian Bokmal", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_no("no", "Norwegian", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_nn("nn", "Norwegian Nynorsk", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_sv("sv", "Swedish", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_et("et", "Estonian", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_fi("fi", "Finnish", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_el("el", "Greek", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_he("he", "Hebrew", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_it("it", "Italian", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_pt("pt", "Portuguese", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_es("es", "Spanish", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_eo("eo", "Esperanto", 2, plural2_1); // "nplurals=2; plural=(n != 1);" +LanguageDef lang_fr("fr", "French", 2, plural2_2); // "nplurals=2; plural=(n > 1);" +LanguageDef lang_pt_BR("pt_BR", "Brazilian", 2, plural2_2); // "nplurals=2; plural=(n > 1);" +LanguageDef lang_lv("lv", "Latvian", 3, plural3_lv); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);" +LanguageDef lang_ga("ga", "Irish", 3, plural3_ga); // "nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;" +LanguageDef lang_lt("lt", "Lithuanian", 3, plural3_lt); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);" +LanguageDef lang_hr("hr", "Croatian", 3, plural3_1); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" +LanguageDef lang_cs("cs", "Czech", 3, plural3_1); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" +LanguageDef lang_ru("ru", "Russian", 3, plural3_1); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" +LanguageDef lang_uk("uk", "Ukrainian", 3, plural3_1); // "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" +LanguageDef lang_sk("sk", "Slovak", 3, plural3_sk); // "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" +LanguageDef lang_pl("pl", "Polish", 3, plural3_pl); // "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); +LanguageDef lang_sl("sl", "Slovenian", 3, plural3_sl); // "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);" +//*} + +LanguageDef& +get_language_def(const std::string& name) +{ + if (name == "hu") return lang_hu; + else if (name == "ja") return lang_ja; + else if (name == "ko") return lang_ko; + else if (name == "tr") return lang_tr; + else if (name == "da") return lang_da; + else if (name == "nl") return lang_nl; + else if (name == "en") return lang_en; + else if (name == "fo") return lang_fo; + else if (name == "de") return lang_de; + else if (name == "nb") return lang_nb; + else if (name == "no") return lang_no; + else if (name == "nn") return lang_nn; + else if (name == "sv") return lang_sv; + else if (name == "et") return lang_et; + else if (name == "fi") return lang_fi; + else if (name == "el") return lang_el; + else if (name == "he") return lang_he; + else if (name == "it") return lang_it; + else if (name == "pt") return lang_pt; + else if (name == "es") return lang_es; + else if (name == "eo") return lang_eo; + else if (name == "fr") return lang_fr; + else if (name == "pt_BR") return lang_pt_BR; + else if (name == "lv") return lang_lv; + else if (name == "ga") return lang_ga; + else if (name == "lt") return lang_lt; + else if (name == "hr") return lang_hr; + else if (name == "cs") return lang_cs; + else if (name == "ru") return lang_ru; + else if (name == "uk") return lang_uk; + else if (name == "sk") return lang_sk; + else if (name == "pl") return lang_pl; + else if (name == "sl") return lang_sl; + else return lang_en; +} + +DictionaryManager::DictionaryManager() + : current_dict(&empty_dict) +{ + parseLocaleAliases(); + // setup language from environment vars + const char* lang = getenv("LC_ALL"); + if(!lang) + lang = getenv("LC_MESSAGES"); + if(!lang) + lang = getenv("LANG"); + + if(lang) + set_language(lang); +} + +void +DictionaryManager::parseLocaleAliases() +{ + // try to parse language alias list + std::ifstream in("/usr/share/locale/locale.alias"); + + char c = ' '; + while(in.good() && !in.eof()) { + while(isspace(c) && !in.eof()) + in.get(c); + + if(c == '#') { // skip comments + while(c != '\n' && !in.eof()) + in.get(c); + continue; + } + + std::string alias; + while(!isspace(c) && !in.eof()) { + alias += c; + in.get(c); + } + while(isspace(c) && !in.eof()) + in.get(c); + std::string language; + while(!isspace(c) && !in.eof()) { + language += c; + in.get(c); + } + + if(in.eof()) + break; + set_language_alias(alias, language); + } +} + +Dictionary& +DictionaryManager::get_dictionary(const std::string& spec) +{ + std::string lang = get_language_from_spec(spec); + Dictionaries::iterator i = dictionaries.find(get_language_from_spec(lang)); + if (i != dictionaries.end()) + { + return i->second; + } + else // Dictionary for languages lang isn't loaded, so we load it + { + //std::cout << "get_dictionary: " << lang << std::endl; + Dictionary& dict = dictionaries[lang]; + + dict.set_language(get_language_def(lang)); + if(charset != "") + dict.set_charset(charset); + + for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p) + { + DIR* dir = opendir(p->c_str()); + if (!dir) + { + std::cerr << "Error: opendir() failed on " << *p << std::endl; + } + else + { + struct dirent* ent; + while((ent = readdir(dir))) + { + if (std::string(ent->d_name) == lang + ".po") + { + std::string pofile = *p + "/" + ent->d_name; + std::ifstream in(pofile.c_str()); + if (!in) + { + std::cerr << "Error: Failure file opening: " << pofile << std::endl; + } + else + { + read_po_file(dict, in); + } + } + } + closedir(dir); + } + } + + return dict; + } +} + +std::set +DictionaryManager::get_languages() +{ + std::set languages; + + for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p) + { + DIR* dir = opendir(p->c_str()); + if (!dir) + { + std::cerr << "Error: opendir() failed on " << *p << std::endl; + } + else + { + struct dirent* ent; + while((ent = readdir(dir))) + { + if (has_suffix(ent->d_name, ".po")) + { + std::string filename = ent->d_name; + languages.insert(filename.substr(0, filename.length()-3)); + } + } + closedir(dir); + } + } + return languages; +} + +void +DictionaryManager::set_language(const std::string& lang) +{ + language = get_language_from_spec(lang); + current_dict = & (get_dictionary(language)); +} + +void +DictionaryManager::set_charset(const std::string& charset) +{ + dictionaries.clear(); // changing charset invalidates cache + this->charset = charset; + set_language(language); +} + +void +DictionaryManager::set_language_alias(const std::string& alias, + const std::string& language) +{ + language_aliases.insert(std::make_pair(alias, language)); +} + +std::string +DictionaryManager::get_language_from_spec(const std::string& spec) +{ + std::string lang = spec; + Aliases::iterator i = language_aliases.find(lang); + if(i != language_aliases.end()) { + lang = i->second; + } + + std::string::size_type s = lang.find_first_of("_."); + if(s == std::string::npos) + return lang; + + return std::string(lang, 0, s); +} + +void +DictionaryManager::add_directory(const std::string& pathname) +{ + dictionaries.clear(); // adding directories invalidates cache + search_path.push_back(pathname); + set_language(language); +} + +//--------------------------------------------------------------------------- + +Dictionary::Dictionary(const LanguageDef& language_, const std::string& charset_) + : language(language_), charset(charset_) +{ +} + +Dictionary::Dictionary() + : language(lang_en) +{ +} + +std::string +Dictionary::get_charset() const +{ + return charset; +} + +void +Dictionary::set_charset(const std::string& charset_) +{ + charset = charset_; +} + +void +Dictionary::set_language(const LanguageDef& lang) +{ + language = lang; +} + +std::string +Dictionary::translate(const std::string& msgid, const std::string& msgid2, int num) +{ + PluralEntries::iterator i = plural_entries.find(msgid); + std::map& msgstrs = i->second; + + if (i != plural_entries.end() && !msgstrs.empty()) + { + int g = language.plural(num); + std::map::iterator j = msgstrs.find(g); + if (j != msgstrs.end()) + { + return j->second; + } + else + { + // Return the first translation, in case we can't translate the specific number + return msgstrs.begin()->second; + } + } + else + { +#ifdef TRANSLATION_DEBUG + std::cerr << "Warning: Couldn't translate: " << msgid << std::endl; + std::cerr << "Candidates: " << std::endl; + for (PluralEntries::iterator i = plural_entries.begin(); i != plural_entries.end(); ++i) + std::cout << "'" << i->first << "'" << std::endl; +#endif + + if (plural2_1(num)) // default to english rules + return msgid2; + else + return msgid; + } +} + +std::string +Dictionary::translate(const std::string& msgid) +{ + Entries::iterator i = entries.find(msgid); + if (i != entries.end() && !i->second.empty()) + { + return i->second; + } + else + { +#ifdef TRANSLATION_DBEUG + std::cout << "Error: Couldn't translate: " << msgid << std::endl; +#endif + return msgid; + } +} + +void +Dictionary::add_translation(const std::string& msgid, const std::string& , + const std::map& msgstrs) +{ + // Do we need msgid2 for anything? its after all supplied to the + // translate call, so we just throw it away + plural_entries[msgid] = msgstrs; +} + +void +Dictionary::add_translation(const std::string& msgid, const std::string& msgstr) +{ + entries[msgid] = msgstr; +} + +class POFileReader +{ +private: + struct Token + { + std::string keyword; + std::string content; + }; + + Dictionary& dict; + + std::string from_charset; + std::string to_charset; + + std::string current_msgid; + std::string current_msgid_plural; + std::map msgstr_plural; + + int line_num; + + enum { WANT_MSGID, WANT_MSGSTR, WANT_MSGSTR_PLURAL, WANT_MSGID_PLURAL } state; + +public: + POFileReader(std::istream& in, Dictionary& dict_) + : dict(dict_) + { + state = WANT_MSGID; + line_num = 0; + tokenize_po(in); + } + + void parse_header(const std::string& header) + { + // Seperate the header in lines + typedef std::vector Lines; + Lines lines; + + std::string::size_type start = 0; + for(std::string::size_type i = 0; i < header.length(); ++i) + { + if (header[i] == '\n') + { + lines.push_back(header.substr(start, i - start)); + start = i+1; + } + } + + for(Lines::iterator i = lines.begin(); i != lines.end(); ++i) + { + if (has_prefix(*i, "Content-Type: text/plain; charset=")) { + from_charset = i->substr(strlen("Content-Type: text/plain; charset=")); + } + } + + if (from_charset.empty() || from_charset == "CHARSET") + { + std::cerr << "Error: Charset not specified for .po, fallback to ISO-8859-1" << std::endl; + from_charset = "ISO-8859-1"; + } + + to_charset = dict.get_charset(); + if (to_charset.empty()) + { // No charset requested from the dict, so we use the one from the .po + to_charset = from_charset; + dict.set_charset(from_charset); + } + } + + void add_token(const Token& token) + { + switch(state) + { + case WANT_MSGID: + if (token.keyword == "msgid") + { + current_msgid = token.content; + state = WANT_MSGID_PLURAL; + } + else if (token.keyword.empty()) + { + //std::cerr << "Got EOF, everything looks ok." << std::endl; + } + else + { + std::cerr << "tinygettext: expected 'msgid' keyword, got " << token.keyword + << " at line " << line_num << std::endl; + } + break; + + case WANT_MSGID_PLURAL: + if (token.keyword == "msgid_plural") + { + current_msgid_plural = token.content; + state = WANT_MSGSTR_PLURAL; + } + else + { + state = WANT_MSGSTR; + add_token(token); + } + break; + + case WANT_MSGSTR: + if (token.keyword == "msgstr") + { + if (current_msgid == "") + { // .po Header is hidden in the msgid with the empty string + parse_header(token.content); + } + else + { + dict.add_translation(current_msgid, convert(token.content, from_charset, to_charset)); + } + state = WANT_MSGID; + } + else + { + std::cerr << "tinygettext: expected 'msgstr' keyword, got " << token.keyword + << " at line " << line_num << std::endl; + } + break; + + case WANT_MSGSTR_PLURAL: + if (has_prefix(token.keyword, "msgstr[")) + { + int num; + if (sscanf(token.keyword.c_str(), "msgstr[%d]", &num) != 1) + { + std::cerr << "Error: Couldn't parse: " << token.keyword << std::endl; + } + else + { + msgstr_plural[num] = convert(token.content, from_charset, to_charset); + } + } + else + { + dict.add_translation(current_msgid, current_msgid_plural, msgstr_plural); + + state = WANT_MSGID; + add_token(token); + } + break; + } + } + + inline int getchar(std::istream& in) + { + int c = in.get(); + if (c == '\n') + line_num += 1; + return c; + } + + void tokenize_po(std::istream& in) + { + enum State { READ_KEYWORD, + READ_CONTENT, + READ_CONTENT_IN_STRING, + SKIP_COMMENT }; + + State state = READ_KEYWORD; + int c; + Token token; + + while((c = getchar(in)) != EOF) + { + //std::cout << "Lexing char: " << char(c) << " " << state << std::endl; + switch(state) + { + case READ_KEYWORD: + if (c == '#') + { + state = SKIP_COMMENT; + } + else + { + // Read a new token + token = Token(); + + do { // Read keyword + token.keyword += c; + } while((c = getchar(in)) != EOF && !isspace(c)); + in.unget(); + + state = READ_CONTENT; + } + break; + + case READ_CONTENT: + while((c = getchar(in)) != EOF) + { + if (c == '"') { + // Found start of content + state = READ_CONTENT_IN_STRING; + break; + } else if (isspace(c)) { + // skip + } else { // Read something that may be a keyword + in.unget(); + state = READ_KEYWORD; + add_token(token); + break; + } + } + break; + + case READ_CONTENT_IN_STRING: + if (c == '\\') { + c = getchar(in); + if (c != EOF) + { + if (c == 'n') token.content += '\n'; + else if (c == 't') token.content += '\t'; + else if (c == 'r') token.content += '\r'; + else if (c == '"') token.content += '"'; + else + { + std::cout << "Unhandled escape character: " << char(c) << std::endl; + } + } + else + { + std::cout << "Unterminated string" << std::endl; + } + } else if (c == '"') { // Content string is terminated + state = READ_CONTENT; + } else { + token.content += c; + } + break; + + case SKIP_COMMENT: + if (c == '\n') + state = READ_KEYWORD; + break; + } + } + add_token(token); + } +}; + +void read_po_file(Dictionary& dict_, std::istream& in) +{ + POFileReader reader(in, dict_); +} + +} // namespace TinyGetText + +/* EOF */ diff --git a/src/tinygettext/tinygettext.h b/src/tinygettext/tinygettext.h new file mode 100644 index 000000000..207ce28a6 --- /dev/null +++ b/src/tinygettext/tinygettext.h @@ -0,0 +1,153 @@ +// $Id$ +// +// TinyGetText - A small flexible gettext() replacement +// Copyright (C) 2004 Ingo Ruhnke +// +// 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 HEADER_TINYGETTEXT_H +#define HEADER_TINYGETTEXT_H + +#include +#include +#include +#include + +namespace TinyGetText { + +typedef int (*PluralFunc)(int n); + +struct LanguageDef { + const char* code; + const char* name; + int nplural; + PluralFunc plural; + + LanguageDef(const char* code_, const char* name_, int nplural_, PluralFunc plural_) + : code(code_), name(name_), nplural(nplural_), plural(plural_) + {} +}; + +/** A simple dictionary class that mimics gettext() behaviour. Each + Dictionary only works for a single language, for managing multiple + languages and .po files at once use the DictionaryManager. */ +class Dictionary +{ +private: + typedef std::map Entries; + Entries entries; + + typedef std::map > PluralEntries; + PluralEntries plural_entries; + + LanguageDef language; + std::string charset; +public: + /** */ + Dictionary(const LanguageDef& language_, const std::string& charset = ""); + + Dictionary(); + + /** Return the charset used for this dictionary */ + std::string get_charset() const; + + /** Set a charset for this dictionary, this will NOT convert stuff, + it is for information only, you have to convert stuff yourself + when you add it with \a add_translation() */ + void set_charset(const std::string& charset); + + /** Set the language that is used for this dictionary, this is + mainly needed to evaluate plural forms */ + void set_language(const LanguageDef& lang); + + /** Translate the string \a msgid to its correct plural form, based + on the number of items given by \a num. \a msgid2 is \a msgid in + plural form. */ + std::string translate(const std::string& msgid, const std::string& msgid2, int num); + + /** Translate the string \a msgid. */ + std::string translate(const std::string& msgid); + + /** Add a translation from \a msgid to \a msgstr to the dictionary, + where \a msgid is the singular form of the message, msgid2 the + plural form and msgstrs a table of translations. The right + translation will be calculated based on the \a num argument to + translate(). */ + void add_translation(const std::string& msgid, const std::string& msgid2, + const std::map& msgstrs); + + /** Add a translation from \a msgid to \a msgstr to the + dictionary */ + void add_translation(const std::string& msgid, const std::string& msgstr); +}; + +/** Manager class for dictionaries, you give it a bunch of directories + with .po files and it will then automatically load the right file + on demand depending on which language was set. */ +class DictionaryManager +{ +private: + typedef std::map Dictionaries; + Dictionaries dictionaries; + typedef std::vector SearchPath; + SearchPath search_path; + typedef std::map Aliases; + Aliases language_aliases; + std::string charset; + std::string language; + Dictionary* current_dict; + Dictionary empty_dict; + +public: + DictionaryManager(); + + /** Return the currently active dictionary, if none is set, an empty + dictionary is returned. */ + Dictionary& get_dictionary() + { return *current_dict; } + + /** Get dictionary for lang */ + Dictionary& get_dictionary(const std::string& langspec); + + /** Set a language based on a four? letter country code */ + void set_language(const std::string& langspec); + + /** Set a charset that will be set on the returned dictionaries */ + void set_charset(const std::string& charset); + + /** Define an alias for a language */ + void set_language_alias(const std::string& alias, const std::string& lang); + + /** Add a directory to the search path for dictionaries */ + void add_directory(const std::string& pathname); + + /** Return a set of the available languages in their country code */ + std::set get_languages(); + +private: + void parseLocaleAliases(); + /// returns the language part in a language spec (like de_DE.UTF-8 -> de) + std::string get_language_from_spec(const std::string& spec); +}; + +/** Read the content of the .po file given as \a in into the + dictionary given as \a dict */ +void read_po_file(Dictionary& dict, std::istream& in); +LanguageDef& get_language_def(const std::string& name); + +} // namespace TinyGetText + +#endif + +/* EOF */ diff --git a/src/title.cpp b/src/title.cpp index 7b3b89d41..3ae54f67e 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -37,14 +37,11 @@ #include #endif -#include "app/globals.h" #include "title.h" #include "video/screen.h" #include "video/surface.h" #include "gui/menu.h" #include "timer.h" -#include "special/frame_rate.h" -#include "app/setup.h" #include "lisp/lisp.h" #include "lisp/parser.h" #include "level.h" @@ -59,9 +56,10 @@ #include "object/camera.h" #include "object/player.h" #include "resources.h" -#include "app/gettext.h" +#include "gettext.h" #include "misc.h" #include "textscroller.h" +#include "file_system.h" #include "control/joystickkeyboardcontroller.h" #include "control/codecontroller.h" #include "main.h" @@ -81,8 +79,6 @@ static CodeController* controller; static std::vector contrib_subsets; static LevelSubset* current_contrib_subset = 0; -static FrameRate frame_rate(100); - /* If the demo was stopped - because game started, level editor was excuted, etc - call this when you get back to the title code. @@ -93,7 +89,7 @@ void resume_demo() titlesession->get_current_sector()->activate("main"); titlesession->set_current(); - frame_rate.update(); + //frame_rate.update(); } void update_load_save_game_menu(Menu* menu) @@ -225,20 +221,16 @@ void check_levels_contrib_menu() void check_contrib_subset_menu() { int index = contrib_subset_menu->check(); - if (index != -1) - { - if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION) - { - std::cout << "Starting level: " << index << std::endl; - - GameSession session( - current_contrib_subset->get_level_filename(index), ST_GL_PLAY); - session.run(); - player_status.reset(); - Menu::set_current(main_menu); - resume_demo(); - } - } + if (index != -1) { + if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION) { + GameSession session( + current_contrib_subset->get_level_filename(index), ST_GL_PLAY); + session.run(); + player_status.reset(); + Menu::set_current(main_menu); + resume_demo(); + } + } } void draw_demo(float elapsed_time) @@ -256,12 +248,10 @@ void draw_demo(float elapsed_time) if(random_timer.check() || (walking && (int) last_tux_x_pos == (int) tux->get_pos().x)) { walking = false; - printf("Walking: %d.\n", walking); } else { if(!walking && (int) tux->get_pos().y == (int) last_tux_y_pos) { random_timer.start(float(rand() % 3000 + 3000) / 1000.); walking = true; - printf("Walking: %d.\n", walking); } } if(!walking) @@ -287,8 +277,6 @@ void title() MusicRef credits_music; controller = new CodeController(); - Ticks::pause_init(); - titlesession = new GameSession(get_resource_filename("levels/misc/menu.stl"), ST_GL_DEMO_GAME); @@ -374,7 +362,6 @@ void title() break; case MNID_LEVELS_CONTRIB: // Contrib Menu - puts("Entering contrib menu"); generate_contrib_menu(); break; #if 0 @@ -450,7 +437,7 @@ void title() context.do_drawing(); - frame_rate.update(); + //frame_rate.update(); /* Pause: */ frame++; diff --git a/src/trigger/door.cpp b/src/trigger/door.cpp index efe800444..760d3d08a 100644 --- a/src/trigger/door.cpp +++ b/src/trigger/door.cpp @@ -25,12 +25,9 @@ #include "sprite/sprite.h" #include "sprite/sprite_manager.h" #include "video/drawing_context.h" -#include "app/globals.h" #include "lisp/lisp.h" #include "lisp/writer.h" -using namespace SuperTux; - Door::Door(const lisp::Lisp& reader) { reader.get("x", bbox.p1.x); diff --git a/src/trigger/hatch.cpp b/src/trigger/hatch.cpp index a599c3306..8e264dfb4 100644 --- a/src/trigger/hatch.cpp +++ b/src/trigger/hatch.cpp @@ -25,12 +25,9 @@ #include "sprite/sprite.h" #include "sprite/sprite_manager.h" #include "video/drawing_context.h" -#include "app/globals.h" #include "lisp/lisp.h" #include "lisp/writer.h" -using namespace SuperTux; - Hatch::Hatch(const lisp::Lisp& reader) { reader.get("x", bbox.p1.x); diff --git a/src/trigger/secretarea_trigger.cpp b/src/trigger/secretarea_trigger.cpp index 66a7f2e59..72c88f867 100644 --- a/src/trigger/secretarea_trigger.cpp +++ b/src/trigger/secretarea_trigger.cpp @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #include #include "secretarea_trigger.h" @@ -25,8 +24,9 @@ #include "lisp/lisp.h" #include "lisp/writer.h" #include "object_factory.h" +#include "main.h" -#define MESSAGE_TIME 3.5 +static const float MESSAGE_TIME=3.5; //TODO: Count numbers of triggered/total secret areas SecretAreaTrigger::SecretAreaTrigger(const lisp::Lisp& reader) diff --git a/src/trigger/secretarea_trigger.h b/src/trigger/secretarea_trigger.h index 60318bf68..bbc3641af 100644 --- a/src/trigger/secretarea_trigger.h +++ b/src/trigger/secretarea_trigger.h @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef __SECRETAREA_TRIGGER_H__ #define __SECRETAREA_TRIGGER_H__ @@ -25,7 +24,6 @@ #include "serializable.h" #include "resources.h" #include "video/drawing_context.h" -#include "app/globals.h" #include "timer.h" class SecretAreaTrigger : public TriggerBase, public Serializable diff --git a/src/trigger/trigger_base.h b/src/trigger/trigger_base.h index 5ccc9ea0b..3f8fdc476 100644 --- a/src/trigger/trigger_base.h +++ b/src/trigger/trigger_base.h @@ -24,7 +24,6 @@ #include "sprite/sprite.h" class Player; -using namespace SuperTux; /** This class is the base class for all objects you can interact with in some * way. There are several interaction types defined like touch and activate diff --git a/src/video/drawing_context.cpp b/src/video/drawing_context.cpp index 66c1fa153..15e886393 100644 --- a/src/video/drawing_context.cpp +++ b/src/video/drawing_context.cpp @@ -24,12 +24,10 @@ #include "drawing_context.h" #include "surface.h" -#include "app/globals.h" #include "font.h" +#include "main.h" #include "gameconfig.h" -using namespace SuperTux; - DrawingContext::DrawingContext(SDL_Surface* targetsurface) { if(targetsurface) { diff --git a/src/video/drawing_context.h b/src/video/drawing_context.h index 0aa7cec2c..e396659fa 100644 --- a/src/video/drawing_context.h +++ b/src/video/drawing_context.h @@ -30,8 +30,6 @@ #include "video/surface.h" #include "video/font.h" -using namespace SuperTux; - class Surface; // some constants for predefined layer values diff --git a/src/video/font.cpp b/src/video/font.cpp index 3d2c8ca09..bdcd54102 100644 --- a/src/video/font.cpp +++ b/src/video/font.cpp @@ -23,15 +23,12 @@ #include #include -#include "app/globals.h" #include "lisp/parser.h" #include "lisp/lisp.h" #include "screen.h" #include "font.h" #include "drawing_context.h" -using namespace SuperTux; - Font::Font(const std::string& file, FontType ntype, int nw, int nh, int nshadowsize) : chars(0), shadow_chars(0), type(ntype), w(nw), h(nh), diff --git a/src/video/screen.cpp b/src/video/screen.cpp index 8bc28c8a7..7ceb28ee7 100644 --- a/src/video/screen.cpp +++ b/src/video/screen.cpp @@ -37,15 +37,13 @@ #include "gameconfig.h" #include "screen.h" -#include "app/globals.h" +#include "main.h" #include "video/drawing_context.h" #include "math/vector.h" static const float LOOP_DELAY = 20.0; extern SDL_Surface* screen; -using namespace SuperTux; - /* 'Stolen' from the SDL documentation. * Return the pixel value at (x, y) * NOTE: The surface must be locked before calling this! diff --git a/src/video/screen.h b/src/video/screen.h index 1da243291..48c5180dd 100644 --- a/src/video/screen.h +++ b/src/video/screen.h @@ -26,8 +26,6 @@ #include #include "math/vector.h" -using namespace SuperTux; - /** Stores 8bit RGBA values. */ class Color { diff --git a/src/video/surface.cpp b/src/video/surface.cpp index fb3e8a038..998748232 100644 --- a/src/video/surface.cpp +++ b/src/video/surface.cpp @@ -31,10 +31,6 @@ #include "gameconfig.h" #include "video/surface.h" #include "video/screen.h" -#include "app/globals.h" -#include "app/setup.h" - -using namespace SuperTux; Surface::Surfaces Surface::surfaces; diff --git a/src/worldmap.cpp b/src/worldmap.cpp index a2f8d3b9d..173e9363f 100644 --- a/src/worldmap.cpp +++ b/src/worldmap.cpp @@ -26,13 +26,10 @@ #include #include -#include "app/globals.h" -#include "app/gettext.h" -#include "app/setup.h" +#include "gettext.h" #include "video/surface.h" #include "video/screen.h" #include "video/drawing_context.h" -#include "special/frame_rate.h" #include "sprite/sprite_manager.h" #include "audio/sound_manager.h" #include "lisp/parser.h" @@ -47,6 +44,9 @@ #include "player_status.h" #include "textscroller.h" #include "main.h" +#include "file_system.h" +#include "gui/menu.h" +#include "gui/mousecursor.h" #include "control/joystickkeyboardcontroller.h" Menu* worldmap_menu = 0; @@ -688,7 +688,6 @@ WorldMap::update(float delta) { PlayerStatus old_player_status = player_status; - std::cout << "Enter the current level: " << level->name << std::endl; // do a shriking fade to the level shrink_fade(Vector((level->pos.x*32 + 16 + offset.x), (level->pos.y*32 + 16 + offset.y)), 500); @@ -732,8 +731,6 @@ WorldMap::update(float delta) tux->set_direction(dir); //tux->update(delta); } - - std::cout << "Walk to dir: " << dir << std::endl; } } @@ -772,8 +769,7 @@ WorldMap::update(float delta) context.do_drawing(); - SDL_Event event; - wait_for_event(event,2000,6000,true); + wait_for_event(2.0, 6.0); quit = true; player_status.reset(); diff --git a/tools/Jamfile b/tools/Jamfile new file mode 100644 index 000000000..92739149c --- /dev/null +++ b/tools/Jamfile @@ -0,0 +1,3 @@ +SubDir TOP tools ; + +SubInclude TOP tools miniswig ; diff --git a/tools/miniswig/create_wrapper.cpp b/tools/miniswig/create_wrapper.cpp index a806de411..fc83acd10 100644 --- a/tools/miniswig/create_wrapper.cpp +++ b/tools/miniswig/create_wrapper.cpp @@ -6,7 +6,7 @@ #include "globals.h" void -WrapperCreator::create_wrapper(CompilationUnit* unit) +WrapperCreator::create_wrapper(Namespace* ns) { // hpp file hppout @@ -14,10 +14,10 @@ WrapperCreator::create_wrapper(CompilationUnit* unit) << " * WARNING: This file is automatically generated from '" << inputfile << "' - do not change\n" << " */\n" - << "#ifndef __" << modulename << "_WRAPPER_HPP__\n" - << "#define __" << modulename << "_WRAPPER_HPP__\n" + << "#ifndef __" << modulename << "_WRAPPER_H__\n" + << "#define __" << modulename << "_WRAPPER_H__\n" << "\n" - << "#include \"WrapperUtil.hpp\"\n" + << "#include \"wrapper_util.h\"\n" << "\n" << "extern WrappedFunction " << modulename << "_global_functions[];\n" << "extern WrappedClass " << modulename << "_classes[];\n" @@ -34,26 +34,30 @@ WrapperCreator::create_wrapper(CompilationUnit* unit) << "#include \n" << "#include \n" << "#include \n" - << "#include \"WrapperUtil.hpp\"\n" - << "#include \"" << inputfile << "\"\n" + << "#include \"wrapper_util.h\"\n" + << "#include \"wrapper.interface.h\"\n" << "\n"; + if(selected_namespace != "") { + out << "using namespace " << selected_namespace << ";\n"; + out << "\n"; + } - for(std::vector::iterator i = unit->types.begin(); - i != unit->types.end(); ++i) { + for(std::vector::iterator i = ns->types.begin(); + i != ns->types.end(); ++i) { AtomicType* type = *i; Class* _class = dynamic_cast (type); if(_class != 0) create_class_wrapper(_class); } - for(std::vector::iterator i = unit->functions.begin(); - i != unit->functions.end(); ++i) { + for(std::vector::iterator i = ns->functions.begin(); + i != ns->functions.end(); ++i) { create_function_wrapper(0, *i); } // create function list... out << "WrappedFunction " << modulename << "_global_functions[] = {\n"; - for(std::vector::iterator i = unit->functions.begin(); - i != unit->functions.end(); ++i) { + for(std::vector::iterator i = ns->functions.begin(); + i != ns->functions.end(); ++i) { Function* function = *i; out << ind << "{ \"" << function->name << "\", &" << function->name << "_wrapper },\n"; @@ -66,8 +70,8 @@ WrapperCreator::create_wrapper(CompilationUnit* unit) std::ostringstream classlist; classlist << "WrappedClass " << modulename << "_classes[] = {\n"; - for(std::vector::iterator i = unit->types.begin(); - i != unit->types.end(); ++i) { + for(std::vector::iterator i = ns->types.begin(); + i != ns->types.end(); ++i) { AtomicType* type = *i; Class* _class = dynamic_cast (type); if(_class == 0) @@ -93,10 +97,10 @@ WrapperCreator::create_wrapper(CompilationUnit* unit) out << ind << "{ \"" << function->name << "\", &" << _class->name << "_" << function->name << "_wrapper },\n"; } - classlist << ind << "{ 0, 0 }\n"; out << "};\n" << "\n"; } + classlist << ind << "{ 0, 0 }\n"; classlist << "};\n"; out << classlist.str(); out << "\n"; @@ -148,6 +152,8 @@ WrapperCreator::create_function_wrapper(Class* _class, Function* function) } if(_class != 0) { out << "_this->"; + } else if(selected_namespace != "") { + out << selected_namespace << "::"; } out << function->name << "("; for(size_t i = 0; i < function->parameters.size(); ++i) { @@ -262,7 +268,7 @@ WrapperCreator::create_class_destruct_function(Class* _class) << "{\n" << ind << _class->name << "* _this = reinterpret_cast<" << _class->name << "*> (ptr);\n" - << ind << "_this->~" << _class->name << "();\n" + << ind << "delete _this;\n" << ind << "return 0;\n" << "}\n" << "\n"; diff --git a/tools/miniswig/create_wrapper.h b/tools/miniswig/create_wrapper.h index 7b51a18ec..0b546eb94 100644 --- a/tools/miniswig/create_wrapper.h +++ b/tools/miniswig/create_wrapper.h @@ -18,7 +18,7 @@ public: ind = " "; } - void create_wrapper(CompilationUnit* unit); + void create_wrapper(Namespace* ns); void create_class_wrapper(Class* _class); void create_class_construct_function(Class* _class); void create_class_destruct_function(Class* _class); diff --git a/tools/miniswig/globals.h b/tools/miniswig/globals.h index 652f68892..362559b20 100644 --- a/tools/miniswig/globals.h +++ b/tools/miniswig/globals.h @@ -4,10 +4,17 @@ #include "tree.h" #include +// parsing extern CompilationUnit* unit; +extern bool search_down; +extern Namespace* search_namespace; +extern Namespace* current_namespace; + +// config/output extern std::istream* input; extern std::string inputfile; extern std::string modulename; +extern std::string selected_namespace; #endif diff --git a/tools/miniswig/lexer.ll b/tools/miniswig/lexer.ll index dc019e813..3285ec4c4 100644 --- a/tools/miniswig/lexer.ll +++ b/tools/miniswig/lexer.ll @@ -21,6 +21,7 @@ %% +#.* /* ignore preprocessor directives */ [[:space:]]+ /* eat spaces */ \/\*.*\*\/ /* eat comment */ \/\/[^\n]*\n /* eat comment */ @@ -41,10 +42,14 @@ double { return T_DOUBLE; } public { return T_PUBLIC; } protected { return T_PROTECTED; } private { return T_PRIVATE; } +namespace { return T_NAMESPACE; } [a-zA-Z_][a-zA-Z_0-9]* { + Namespace* ns = search_namespace; + if(ns == 0) + ns = current_namespace; // is it a type? - for(std::vector::iterator i = unit->types.begin(); - i != unit->types.end(); ++i) { + for(std::vector::iterator i = ns->types.begin(); + i != ns->types.end(); ++i) { AtomicType* type = *i; if(type->name == yytext) { yylval->atomic_type = type; @@ -52,10 +57,11 @@ private { return T_PRIVATE; } } } // or a namespace? (hack for now...) - if(strcmp(yytext, "std") == 0) { - yylval->_namespace = unit->namespaces[0]; - return T_NAMESPACE; + yylval->_namespace = ns->_findNamespace(yytext, search_down); + if(yylval->_namespace) { + return T_NAMESPACEREF; } + // a new ID yylval->str = strdup(yytext); return T_ID; } diff --git a/tools/miniswig/main.cpp b/tools/miniswig/main.cpp index 94393df1f..24171985d 100644 --- a/tools/miniswig/main.cpp +++ b/tools/miniswig/main.cpp @@ -12,11 +12,12 @@ extern int yylex(); CompilationUnit* unit = 0; std::istream* input = 0; std::string inputfile; +std::string selected_namespace; std::string modulename = "wrapper"; void usage() { - std::cout << "Usage: miniswig --input FILE --output-cpp FILE --output-hpp FILE [--module NAME]\n"; + std::cout << "Usage: miniswig --input FILE --output-cpp FILE --output-hpp FILE [--module NAME] [--select-namespace NAME]\n"; std::cout << "\n"; } @@ -53,6 +54,13 @@ int main(int argc, char** argv) return 1; } outputhpp = argv[++i]; + } else if(strcmp(argv[i], "--select-namespace") == 0) { + if(i+1 >= argc) { + std::cerr << "Need to specify a namespace.\n"; + usage(); + return 1; + } + selected_namespace = argv[++i]; } else if(argv[i][0] == '-') { std::cerr << "Unknown option '" << argv[i] << "'.\n"; usage(); @@ -73,11 +81,13 @@ int main(int argc, char** argv) return 1; } unit = new CompilationUnit(); - unit->types.push_back(new StringType()); Namespace* std_namespace = new Namespace(); std_namespace->name = "std"; + std_namespace->types.push_back(new StringType()); unit->namespaces.push_back(std_namespace); + yyparse(); + std::ofstream cppout(outputcpp.c_str()); if(!cppout.good()) { std::cerr << "Couldn't open file '" << outputcpp << "' for writing.\n"; @@ -88,8 +98,14 @@ int main(int argc, char** argv) std::cerr << "Couldn't open file '" << outputhpp << "' for writing.\n"; return 1; } + + Namespace* ns = unit; + if(selected_namespace != "") { + ns = ns->findNamespace(selected_namespace); + } + WrapperCreator creator(cppout, hppout); - creator.create_wrapper(unit); + creator.create_wrapper(ns); } catch(std::exception& e) { std::cerr << e.what() << "\n"; return 1; diff --git a/tools/miniswig/parser.yy b/tools/miniswig/parser.yy index f7865cc2c..e66b58ce3 100644 --- a/tools/miniswig/parser.yy +++ b/tools/miniswig/parser.yy @@ -26,10 +26,13 @@ extern int yylex(YYSTYPE* yylval); void yyerror(const char* s); extern int yylineno; -static Class* currentClass = 0; +bool search_down = true; +Namespace* search_namespace = 0; +Namespace* current_namespace = 0; +static Class* current_class = 0; static Function* currentFunction = 0; -static Type* currentType = 0; -static ClassMember::Visbility currentVisibility; +static Type* current_type = 0; +static ClassMember::Visbility current_visibility; class ParseError : public std::exception { @@ -59,7 +62,7 @@ private: %token T_STRING %token T_ID %token T_ATOMIC_TYPE -%token <_namespace> T_NAMESPACE; +%token <_namespace> T_NAMESPACEREF; %token T_CLASS %token T_STRUCT %token T_STATIC @@ -77,6 +80,7 @@ private: %token T_PUBLIC %token T_PROTECTED %token T_PRIVATE +%token T_NAMESPACE %token T_DDCOL "::" %type <_class> class_declaration @@ -88,77 +92,110 @@ private: %% -input: /* empty */ - | compilation_unit +input: + { + current_namespace = unit; + } + namespace_members +; + +namespace_members: /* empty */ + | namespace_members namespace_member ; -compilation_unit: compilation_unit_part - | compilation_unit compilation_unit_part +namespace_declaration: + T_NAMESPACE T_ID '{' + { + Namespace* newNamespace = new Namespace(); + newNamespace->name = $2; + free($2); + current_namespace->add_namespace(newNamespace); + current_namespace = newNamespace; + } + namespace_members '}' + { + current_namespace = current_namespace->parent; + } + | T_NAMESPACE T_NAMESPACEREF '{' + { + current_namespace = $2; + } + namespace_members '}' + { + current_namespace = current_namespace->parent; + } ; -compilation_unit_part: class_declaration - { unit->types.push_back($1); } +namespace_member: + class_declaration + { current_namespace->add_type($1); } | function_declaration - { unit->functions.push_back($1); } + { current_namespace->functions.push_back($1); } + | namespace_declaration ; -class_declaration: T_CLASS T_ID '{' - { - currentClass = new Class(); - currentClass->name = $2; - free($2); - currentVisibility = ClassMember::PROTECTED; - } - class_body '}' ';' - { - $$ = currentClass; - } +class_declaration: + T_CLASS T_ID '{' + { + current_class = new Class(); + current_class->name = $2; + free($2); + current_visibility = ClassMember::PROTECTED; + } + class_body '}' ';' + { + $$ = current_class; + } ; class_body: /* empty */ - | visibility_change class_body + | class_body class_body_element +; + +class_body_element: + visibility_change | constructor_declaration { - $1->visibility = currentVisibility; - currentClass->members.push_back($1); + $1->visibility = current_visibility; + current_class->members.push_back($1); } - class_body | destructor_declaration { - $1->visibility = currentVisibility; - currentClass->members.push_back($1); + $1->visibility = current_visibility; + current_class->members.push_back($1); } - class_body | function_declaration { - $1->visibility = currentVisibility; - currentClass->members.push_back($1); + $1->visibility = current_visibility; + current_class->members.push_back($1); } - class_body - | variable_declaration class_body + | variable_declaration ; -visibility_change: T_PUBLIC ':' - { currentVisibility = ClassMember::PUBLIC; } - | T_PROTECTED ':' - { currentVisibility = ClassMember::PROTECTED; } - | T_PRIVATE ':' - { currentVisibility = ClassMember::PRIVATE; } +visibility_change: + T_PUBLIC ':' + { current_visibility = ClassMember::PUBLIC; } + | T_PROTECTED ':' + { current_visibility = ClassMember::PROTECTED; } + | T_PRIVATE ':' + { current_visibility = ClassMember::PRIVATE; } ; -constructor_declaration: T_ID '(' +constructor_declaration: + T_ID '(' { currentFunction = new Function(); currentFunction->type = Function::CONSTRUCTOR; free($1); } - param_list ')' ';' + parameter_list ')' ';' { $$ = currentFunction; } ; -destructor_declaration: '~' T_ID '(' ')' ';' +destructor_declaration: + '~' T_ID '(' ')' ';' { currentFunction = new Function(); currentFunction->type = Function::DESTRUCTOR; @@ -167,9 +204,12 @@ destructor_declaration: '~' T_ID '(' ')' ';' } ; -variable_declaration: type T_ID ';' +variable_declaration: + type T_ID ';' +; -function_declaration: type T_ID '(' +function_declaration: + type T_ID '(' { currentFunction = new Function(); currentFunction->type = Function::FUNCTION; @@ -178,83 +218,121 @@ function_declaration: type T_ID '(' currentFunction->name = $2; free($2); } - param_list ')' ';' + parameter_list ')' ';' { $$ = currentFunction; } ; -param_list: /* empty */ - | param_list2 +parameter_list: + /* empty */ + | parameters ; -param_list2: parameter - | parameter ',' param_list2 +parameters: + parameter + | parameters ',' parameter ; -parameter: type - { - Parameter parameter; - parameter.type = *($1); - delete $1; - currentFunction->parameters.push_back(parameter); - } - | type T_ID - { - Parameter parameter; - parameter.type = *($1); - delete $1; - parameter.name = *($2); - free($2); - currentFunction->parameters.push_back(parameter); - } +parameter: + type + { + Parameter parameter; + parameter.type = *($1); + delete $1; + currentFunction->parameters.push_back(parameter); + } + | type T_ID + { + Parameter parameter; + parameter.type = *($1); + delete $1; + parameter.name = *($2); + free($2); + currentFunction->parameters.push_back(parameter); + } ; -type: { - currentType = new Type(); - } - prefix_type_modifiers atomic_type postfix_type_modifiers - { - $$ = currentType; - } +type: + { + current_type = new Type(); + } + prefix_type_modifiers atomic_type postfix_type_modifiers + { + $$ = current_type; + } +; + +prefix_type_modifiers: + /* empty */ + | prefix_type_modifiers prefix_type_modifier +; + +prefix_type_modifier: + T_UNSIGNED + | T_SIGNED + | T_STATIC + | T_CONST ; -prefix_type_modifiers: /* empty */ - | T_UNSIGNED prefix_type_modifiers - | T_SIGNED prefix_type_modifiers - | T_STATIC prefix_type_modifiers - | T_CONST prefix_type_modifiers +postfix_type_modifiers: + /* empty */ + | postfix_type_modifiers postfix_type_modifier ; -postfix_type_modifiers: /* empty */ - | T_CONST postfix_type_modifiers - { currentType->_const = true; } - | '*' postfix_type_modifiers - { currentType->pointer++; } - | '&' postfix_type_modifiers - { currentType->ref++; } +postfix_type_modifier: + T_CONST + { current_type->_const = true; } + | '*' + { current_type->pointer++; } + | '&' + { current_type->ref++; } ; -atomic_type: T_VOID { currentType->atomic_type = &BasicType::VOID; } - | T_BOOL { currentType->atomic_type = &BasicType::BOOL; } - | T_CHAR { currentType->atomic_type = &BasicType::CHAR; } - | T_SHORT { currentType->atomic_type = &BasicType::SHORT; } - | T_INT { currentType->atomic_type = &BasicType::INT; } - | T_LONG { currentType->atomic_type = &BasicType::LONG; } - | T_FLOAT { currentType->atomic_type = &BasicType::FLOAT; } - | T_DOUBLE { currentType->atomic_type = &BasicType::DOUBLE; } - | type_identifier { currentType->atomic_type = $1; } +atomic_type: + T_VOID + { current_type->atomic_type = &BasicType::VOID; } + | T_BOOL + { current_type->atomic_type = &BasicType::BOOL; } + | T_CHAR + { current_type->atomic_type = &BasicType::CHAR; } + | T_SHORT + { current_type->atomic_type = &BasicType::SHORT; } + | T_INT + { current_type->atomic_type = &BasicType::INT; } + | T_LONG + { current_type->atomic_type = &BasicType::LONG; } + | T_FLOAT + { current_type->atomic_type = &BasicType::FLOAT; } + | T_DOUBLE + { current_type->atomic_type = &BasicType::DOUBLE; } + | type_identifier + { current_type->atomic_type = $1; } ; -type_identifier: T_ATOMIC_TYPE +type_identifier: + T_ATOMIC_TYPE { // search for type in current compilation unit... $$ = $1; } - | T_NAMESPACE "::" type_identifier + | namespace_refs "::" T_ATOMIC_TYPE { - // hack... $$ = $3; + search_namespace = 0; + search_down = true; + } +; + +namespace_refs: + T_NAMESPACEREF + { + search_namespace = $1; + search_down = false; + } + | namespace_refs "::" T_NAMESPACEREF + { + search_namespace = $3; } ; diff --git a/tools/miniswig/tree.h b/tools/miniswig/tree.h index 4b9485c1a..f1149afb8 100644 --- a/tools/miniswig/tree.h +++ b/tools/miniswig/tree.h @@ -4,10 +4,16 @@ #include #include #include +#include +#include + +class Namespace; class AtomicType { public: - std::string name; + AtomicType() + : parent(0) + { } virtual ~AtomicType() { } @@ -15,6 +21,9 @@ public: { out << name; } + + std::string name; + Namespace* parent; }; class BasicType : public AtomicType { @@ -143,12 +152,10 @@ public: class Namespace { public: - std::string name; -}; - -class CompilationUnit { -public: - ~CompilationUnit() { + Namespace() { + parent = 0; + } + virtual ~Namespace() { for(std::vector::iterator i = functions.begin(); i != functions.end(); ++i) delete *i; @@ -159,10 +166,50 @@ public: i != namespaces.end(); ++i) delete *i; } - + void add_type(AtomicType* type) + { + types.push_back(type); + type->parent = this; + } + void add_namespace(Namespace* ns) + { + namespaces.push_back(ns); + ns->parent = this; + } + Namespace* _findNamespace(const std::string& name, bool godown = false) { + for(std::vector::iterator i = namespaces.begin(); + i != namespaces.end(); ++i) { + Namespace* ns = *i; + if(ns->name == name) + return ns; + } + if(godown && parent) + return parent->_findNamespace(name, true); + + return 0; + } + + Namespace* findNamespace(const std::string& name, bool godown = false) { + Namespace* ret = _findNamespace(name, godown); + if(!ret) { + std::ostringstream msg; + msg << "Couldn't find namespace '" << name << "'."; + throw std::runtime_error(msg.str()); + } + + return ret; + } + std::vector functions; std::vector types; std::vector namespaces; + + Namespace* parent; + std::string name; +}; + +class CompilationUnit : public Namespace { +public: }; #endif