diff --git a/Box2D/Android.mk b/Box2D/Android.mk index 2c0fcfd3b9..31d1a52a15 100644 --- a/Box2D/Android.mk +++ b/Box2D/Android.mk @@ -43,4 +43,4 @@ Dynamics/b2WorldCallbacks.cpp LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. -include $(BUILD_SHARED_LIBRARY) +include $(BUILD_STATIC_LIBRARY) diff --git a/CocosDenshion/android/Android.mk b/CocosDenshion/android/Android.mk index 93ef096973..5e0348e7d5 100644 --- a/CocosDenshion/android/Android.mk +++ b/CocosDenshion/android/Android.mk @@ -5,9 +5,7 @@ LOCAL_MODULE := cocosdenshion LOCAL_SRC_FILES := SimpleAudioEngine.cpp \ jni/SimpleAudioEngineJni.cpp -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include - -LOCAL_LDLIBS := -llog - +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../cocos2dx -include $(BUILD_SHARED_LIBRARY) \ No newline at end of file +include $(BUILD_STATIC_LIBRARY) \ No newline at end of file diff --git a/CocosDenshion/android/jni/SimpleAudioEngineJni.cpp b/CocosDenshion/android/jni/SimpleAudioEngineJni.cpp index 2bb2f8d4a7..3bed9b355a 100644 --- a/CocosDenshion/android/jni/SimpleAudioEngineJni.cpp +++ b/CocosDenshion/android/jni/SimpleAudioEngineJni.cpp @@ -1,4 +1,5 @@ #include "SimpleAudioEngineJni.h" +#include "platform/android/Cocos2dJni.h" #include #define LOG_TAG "libSimpleAudioEngine" @@ -7,17 +8,9 @@ extern "C" { - static JavaVM *gJavaVM = 0; static jclass classOfCocos2dxActivity = 0; JNIEnv *env = 0; - jint JNI_OnLoad(JavaVM *vm, void *reserved) - { - gJavaVM = vm; - - return JNI_VERSION_1_4; - } - static jmethodID getMethodID(const char *methodName, const char *paramCode) { jmethodID ret = 0; diff --git a/CocosDenshion/proj.win32/CocosDenshion.win32.vcproj.user b/CocosDenshion/proj.win32/CocosDenshion.win32.vcproj.user index 0ce2ced646..8261052312 100644 --- a/CocosDenshion/proj.win32/CocosDenshion.win32.vcproj.user +++ b/CocosDenshion/proj.win32/CocosDenshion.win32.vcproj.user @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/HelloLua/Classes/AppDelegate.cpp b/HelloLua/Classes/AppDelegate.cpp new file mode 100644 index 0000000000..7160507a5d --- /dev/null +++ b/HelloLua/Classes/AppDelegate.cpp @@ -0,0 +1,154 @@ +#include "AppDelegate.h" + +#include "cocos2d.h" + +USING_NS_CC; + +AppDelegate::AppDelegate() +{ + +} + +AppDelegate::~AppDelegate() +{ +} + +bool AppDelegate::initInstance() +{ + bool bRet = false; + do + { +#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) + + // Initialize OpenGLView instance, that release by CCDirector when application terminate. + // The HelloWorld is designed as HVGA. + CCEGLView * pMainWnd = new CCEGLView(); + CC_BREAK_IF(! pMainWnd + || ! pMainWnd->Create(TEXT("cocos2d: Hello World"), 480, 320)); + +#endif // CC_PLATFORM_WIN32 + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) + + // OpenGLView initialized in testsAppDelegate.mm on ios platform, nothing need to do here. + +#endif // CC_PLATFORM_IOS + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) + + // OpenGLView initialized in HelloWorld/android/jni/helloworld/main.cpp + // the default setting is to create a fullscreen view + // if you want to use auto-scale, please enable view->create(320,480) in main.cpp + +#endif // CC_PLATFORM_ANDROID + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_WOPHONE) + + // Initialize OpenGLView instance, that release by CCDirector when application terminate. + // The HelloWorld is designed as HVGA. + CCEGLView* pMainWnd = new CCEGLView(this); + CC_BREAK_IF(! pMainWnd || ! pMainWnd->Create(320,480, WM_WINDOW_ROTATE_MODE_CW)); + +#ifndef _TRANZDA_VM_ + // on wophone emulator, we copy resources files to Work7/NEWPLUS/TDA_DATA/Data/ folder instead of zip file + cocos2d::CCFileUtils::setResource("HelloWorld.zip"); +#endif + +#endif // CC_PLATFORM_WOPHONE + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_AIRPLAY) + // MaxAksenov said it's NOT a very elegant solution. I agree, haha + CCDirector::sharedDirector()->setDeviceOrientation(kCCDeviceOrientationLandscapeLeft); +#endif + bRet = true; + } while (0); + return bRet; +} + +bool AppDelegate::applicationDidFinishLaunching() +{ + // initialize director + CCDirector *pDirector = CCDirector::sharedDirector(); + pDirector->setOpenGLView(&CCEGLView::sharedOpenGLView()); + + // enable High Resource Mode(2x, such as iphone4) and maintains low resource on other devices. +// pDirector->enableRetinaDisplay(true); + + // turn on display FPS + pDirector->setDisplayFPS(true); + + // pDirector->setDeviceOrientation(kCCDeviceOrientationLandscapeLeft); + + // set FPS. the default value is 1.0/60 if you don't call this + pDirector->setAnimationInterval(1.0 / 60); + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) + CCLog("1"); + unsigned long size; + char *pFileContent = (char*)CCFileUtils::getFileData("hello.lua", "r", &size); + + if (pFileContent) + { + // copy the file contents and add '\0' at the end, or the lua parser can not parse it + char *pTmp = new char[size + 1]; + pTmp[size] = '\0'; + memcpy(pTmp, pFileContent, size); + delete[] pFileContent; + + string code(pTmp); + CCLuaScriptModule::sharedLuaScriptModule()->executeString(code); + delete []pTmp; + } +#endif + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) + CCLuaScriptModule::sharedLuaScriptModule()->executeScriptFile("./../../HelloLua/Resource/hello.lua"); + + /* + * Another way to run lua script. + * Load the file into memory and run it. + * + unsigned long size; + char *pFileContent = (char*)CCFileUtils::getFileData("./../../HelloLua/Resource/hello.lua", "r", &size); + if (pFileContent) + { + // copy the file contents and add '\0' at the end, or the lua parser can not parse it + char *pTmp = new char[size + 1]; + pTmp[size] = '\0'; + memcpy(pTmp, pFileContent, size); + delete[] pFileContent; + + string code(pTmp); + CCLuaScriptModule::sharedLuaScriptModule()->executeString(code); + delete []pTmp; + } + */ + +#endif + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) + pDirector->setDeviceOrientation(kCCDeviceOrientationLandscapeLeft); + string path = CCFileUtils::fullPathFromRelativePath("hello.lua"); + CCLuaScriptModule::sharedLuaScriptModule()->executeScriptFile(path.c_str()); +#endif + + return true; +} + +// This function will be called when the app is inactive. When comes a phone call,it's be invoked too +void AppDelegate::applicationDidEnterBackground() +{ + CCDirector::sharedDirector()->pause(); + + // if you use SimpleAudioEngine, it must be pause + // SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic(); +} + +// this function will be called when the app is active again +void AppDelegate::applicationWillEnterForeground() +{ + CCDirector::sharedDirector()->resume(); + + // if you use SimpleAudioEngine, it must resume here + // SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic(); +} diff --git a/HelloLua/Classes/AppDelegate.h b/HelloLua/Classes/AppDelegate.h new file mode 100644 index 0000000000..6a7b537389 --- /dev/null +++ b/HelloLua/Classes/AppDelegate.h @@ -0,0 +1,43 @@ +#ifndef _APP_DELEGATE_H_ +#define _APP_DELEGATE_H_ + +#include "CCApplication.h" + +/** +@brief The cocos2d Application. + +The reason for implement as private inheritance is to hide some interface call by CCDirector. +*/ +class AppDelegate : private cocos2d::CCApplication +{ +public: + AppDelegate(); + virtual ~AppDelegate(); + + /** + @brief Implement for initialize OpenGL instance, set source path, etc... + */ + virtual bool initInstance(); + + /** + @brief Implement CCDirector and CCScene init code here. + @return true Initialize success, app continue. + @return false Initialize failed, app terminate. + */ + virtual bool applicationDidFinishLaunching(); + + /** + @brief The function be called when the application enter background + @param the pointer of the application + */ + virtual void applicationDidEnterBackground(); + + /** + @brief The function be called when the application enter foreground + @param the pointer of the application + */ + virtual void applicationWillEnterForeground(); +}; + +#endif // _APP_DELEGATE_H_ + diff --git a/HelloLua/Resource/90001.jpg.REMOVED.git-id b/HelloLua/Resource/90001.jpg.REMOVED.git-id new file mode 100644 index 0000000000..4609f3cf02 --- /dev/null +++ b/HelloLua/Resource/90001.jpg.REMOVED.git-id @@ -0,0 +1 @@ +d7290c34702d1c6bdb368acb060d93b42d5deff8 \ No newline at end of file diff --git a/HelloLua/Resource/hello.lua b/HelloLua/Resource/hello.lua new file mode 100644 index 0000000000..8236ef2ca6 --- /dev/null +++ b/HelloLua/Resource/hello.lua @@ -0,0 +1,197 @@ +lastMouseX = 0; +lastMouseY = 0; + + + +g_Scene = cocos2d.CCScene:node(); +pSprite = cocos2d.CCSprite:spriteWithFile("90001.jpg");pSprite:setPosition(cocos2d.CCPoint(300, 400)); + + +pLayer = cocos2d.CCLayer:node(); +pLayer:setIsTouchEnabled(true); +pLayer:setAnchorPoint(cocos2d.CCPoint(0,0)); +pLayer:setPosition( cocos2d.CCPoint(0, -300) ); +g_Scene:addChild(pLayer); + + + +function btnTouchMove(e) + + cocos2d.CCLuaLog("mousemove"); + touch = e:anyObject() + debug.setmetatable(touch, cocos2d.CCTouch) + cocos2d.CCLuaLog("btnTouchBegin") + X = touch:locationInView(touch:view()).x + Y = touch:locationInView(touch:view()).y + + OffX = lastMouseX - X; + OffY = lastMouseY - Y; + lastMouseX = X; + lastMouseY = Y; + + point = pLayer:getPosition(); + + point.x = point.x + OffX; + + if point.x >100 then + point.x = 100 + elseif point.x < 0 then + point.x = 0 + end + + pLayer:setPosition(point) + +end --fuction + + +function btnTouchBegin(e) + + count = e:count(); + if count > 1 then + cocos2d.CCLuaLog("2 click"); + end + + touch = e:anyObject() + debug.setmetatable(touch, cocos2d.CCTouch) + cocos2d.CCLuaLog("btnTouchBegin") + lastMouseX = touch:locationInView(touch:view()).x + lastMouseY = touch:locationInView(touch:view()).y + + cocos2d.CCLuaLog("btnTouchBegin") +end + + + + +function btnTouchEnd(e) + cocos2d.CCLuaLog("btnTouchEnd") +end + +-- register touch handler +pLayer.__CCTouchDelegate__:registerLuaTouchEvent("ccTouchBegan", "btnTouchBegin") +pLayer.__CCTouchDelegate__:registerLuaTouchEvent("ccTouchMoved", "btnTouchMove") +pLayer.__CCTouchDelegate__:registerLuaTouchEvent("ccTouchEnded", "btnTouchEnd") +pLayer:addChild(pSprite) + + + +-- add pop menu +menuItem = cocos2d.CCMenuItemImage:itemFromNormalImage("menu2.png","menu2.png"); +menuItem:setAnchorPoint(cocos2d.CCPoint(0,0)); +menuItem:setPosition( cocos2d.CCPoint(100, 200) ); +menuItem:registerMenuHandler("CloseMenu"); +pMenu = cocos2d.CCMenu:menuWithItem(menuItem); +pMenu:setPosition( cocos2d.CCPoint(1000, 200) ); +g_Scene:addChild(pMenu); + + + +function CloseMenu() + pMenu:setPosition(cocos2d.CCPoint(1000, 200) ); + +end + + + +function PopMenu() + + pMenu:setPosition( cocos2d.CCPoint(0, -50) ); + cocos2d.CCLuaLog("pop click"); + +end + + + + +pCloseItem = cocos2d.CCMenuItemImage:itemFromNormalImage("menu1.png","menu1.png"); +pCloseItem:setPosition( cocos2d.CCPoint(30, 40) ); +pCloseItem:registerMenuHandler("PopMenu"); +pcloseMenu = cocos2d.CCMenu:menuWithItem(pCloseItem); +pcloseMenu:setPosition( cocos2d.CCPoint(30, 40) ); +g_Scene:addChild(pcloseMenu); + + + +for i=0,3,1 do + for j=0,1,1 do + + landSprite = cocos2d.CCSprite:spriteWithFile("land1.png"); + pLayer:addChild(landSprite); + + landSprite:setAnchorPoint(cocos2d.CCPoint(0,0)); + landSprite:setPosition(cocos2d.CCPoint(90+j*180 - i%2*90, 200+i*95/2)); + + end +end + + + +--crop + +for i=0,3,1 do + for j=0,1,1 do + + texturecrop = cocos2d.CCTextureCache:sharedTextureCache():addImage("crop1.png"); + framecrop = cocos2d.CCSpriteFrame:frameWithTexture(texturecrop, cocos2d.CCRectMake(0, 0, 105, 95)); + spritecrop = cocos2d.CCSprite:spriteWithSpriteFrame(framecrop); + + pLayer:addChild(spritecrop); + + spritecrop:setAnchorPoint(cocos2d.CCPoint(0,0)); + spritecrop:setPosition(cocos2d.CCPoint(45+90+j*180 - i%2*90, 25+200+i*95/2)); + + end +end + + + + +nFrameWidth = 105; +nFrameHeight = 95; + +texture = cocos2d.CCTextureCache:sharedTextureCache():addImage("dog1.png"); +frame0 = cocos2d.CCSpriteFrame:frameWithTexture(texture, cocos2d.CCRectMake(0, 0, nFrameWidth, nFrameHeight)); +frame1 = cocos2d.CCSpriteFrame:frameWithTexture(texture, cocos2d.CCRectMake(nFrameWidth*1, 0, nFrameWidth, nFrameHeight)); + + +spritedog = cocos2d.CCSprite:spriteWithSpriteFrame(frame0); +spritedog:setPosition(cocos2d.CCPoint(300, 500)); +pLayer:addChild(spritedog); + + + +animFrames = cocos2d.CCMutableArray_CCSpriteFrame__:new(2); + +animFrames:addObject(frame0); +animFrames:addObject(frame1); + + +animation = cocos2d.CCAnimation:animationWithName("wait", 0.5, animFrames) + +animate = cocos2d.CCAnimate:actionWithAnimation(animation, false); +spritedog:runAction(cocos2d.CCRepeatForever:actionWithAction(animate)) + + +cocos2d.CCDirector:sharedDirector():runWithScene(g_Scene); + + + +function tick(cc) + + point = cocos2d.CCPoint(300, 500); + point = spritedog:getPosition(); + + + if point.x > 600 then + point.x = 0 + spritedog:setPosition(point) + else + point.x = point.x + 1 + spritedog:setPosition(point) + end + +end + +cocos2d.CCDirector:sharedDirector():registerTick("tick") + + diff --git a/HelloLua/android/AndroidManifest.xml b/HelloLua/android/AndroidManifest.xml new file mode 100644 index 0000000000..899435c3e2 --- /dev/null +++ b/HelloLua/android/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/HelloLua/android/build_native.sh b/HelloLua/android/build_native.sh new file mode 100644 index 0000000000..412dffc1df --- /dev/null +++ b/HelloLua/android/build_native.sh @@ -0,0 +1,33 @@ +# set params +ANDROID_NDK_ROOT=/cygdrive/e/android-ndk-r5 +COCOS2DX_ROOT=/cygdrive/d/Work7/cocos2d-x +GAME_ROOT=$COCOS2DX_ROOT/HelloLua +GAME_ANDROID_ROOT=$GAME_ROOT/android +RESOURCE_ROOT=$GAME_ROOT/Resource + +# make sure assets is exist +if [ -d $GAME_ANDROID_ROOT/assets ]; then + rm -rf $GAME_ANDROID_ROOT/assets +fi + +mkdir $GAME_ANDROID_ROOT/assets + +# copy resources +for file in $RESOURCE_ROOT/* +do + if [ -d $file ]; then + cp -rf $file $GAME_ANDROID_ROOT/assets + fi + + if [ -f $file ]; then + cp $file $GAME_ANDROID_ROOT/assets + fi +done + +# to enable lua +ENABLE_LUA=true +export ENABLE_LUA + +# build +$ANDROID_NDK_ROOT/ndk-build -C $GAME_ANDROID_ROOT $* + diff --git a/HelloLua/android/default.properties b/HelloLua/android/default.properties new file mode 100644 index 0000000000..46769a7204 --- /dev/null +++ b/HelloLua/android/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-7 diff --git a/HelloLua/android/jni/Android.mk b/HelloLua/android/jni/Android.mk new file mode 100644 index 0000000000..44da642f22 --- /dev/null +++ b/HelloLua/android/jni/Android.mk @@ -0,0 +1,11 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +subdirs := $(addprefix $(LOCAL_PATH)/../../../,$(addsuffix /Android.mk, \ + cocos2dx \ + CocosDenshion/android \ + lua/jni \ + )) +subdirs += $(LOCAL_PATH)/helloworld/Android.mk + +include $(subdirs) diff --git a/HelloLua/android/jni/Application.mk b/HelloLua/android/jni/Application.mk new file mode 100644 index 0000000000..f240662d57 --- /dev/null +++ b/HelloLua/android/jni/Application.mk @@ -0,0 +1,3 @@ +# it is needed for ndk-r5 +APP_STL := stlport_static +APP_MODULES := game \ No newline at end of file diff --git a/HelloLua/android/jni/helloworld/Android.mk b/HelloLua/android/jni/helloworld/Android.mk new file mode 100644 index 0000000000..3a9bc7af7c --- /dev/null +++ b/HelloLua/android/jni/helloworld/Android.mk @@ -0,0 +1,41 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := game + +LOCAL_SRC_FILES := main.cpp \ +../../../Classes/AppDelegate.cpp + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../cocos2dx \ + $(LOCAL_PATH)/../../../../cocos2dx/platform \ + $(LOCAL_PATH)/../../../../cocos2dx/include \ + $(LOCAL_PATH)/../../../../cocos2dx/lua_support \ + $(LOCAL_PATH)/../../../../CocosDenshion/include \ + $(LOCAL_PATH)/../../../Classes \ + $(LOCAL_PATH)/../../../../lua/src \ + $(LOCAL_PATH)/../../../../lua/tolua + +# it is used for ndk-r4 +# if you build with nkd-r4, uncomment it +# LOCAL_LDLIBS := -llog -lGLESv1_CM -llog -lz \ +# -L$(LOCAL_PATH)/../../../../cocos2dx/platform/third_party/android/libraries -lcurl \ +# -lpng \ +# -lxml2 \ +# -ljpeg \ +# -lskia + +# it is used for ndk-r5 +# if you build with ndk-r4, comment it +# because the new Windows toolchain doesn't support Cygwin's drive +# mapping (i.e /cygdrive/c/ instead of C:/) +LOCAL_LDLIBS := -llog -lGLESv1_CM -llog -lz \ + -L$(call host-path, $(LOCAL_PATH)/../../../../cocos2dx/platform/third_party/android/libraries) -lcurl \ + -lpng \ + -lxml2 \ + -ljpeg \ + -lskia + +LOCAL_STATIC_LIBRARIES := libcocos2d libcocosdenshion liblua + +LOCAL_CFLAGS := -DENABLE_LUA + +include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/HelloLua/android/jni/helloworld/main.cpp b/HelloLua/android/jni/helloworld/main.cpp new file mode 100644 index 0000000000..d268ee37f2 --- /dev/null +++ b/HelloLua/android/jni/helloworld/main.cpp @@ -0,0 +1,38 @@ +#include "AppDelegate.h" +#include "cocos2d.h" +#include +#include + +#define LOG_TAG "main" +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) + +using namespace cocos2d; + +#define IMG_PATH "assets" + +extern "C" +{ + +void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thiz, jint w, jint h) +{ + if (!cocos2d::CCDirector::sharedDirector()->getOpenGLView()) + { + cocos2d::CCEGLView *view = &cocos2d::CCEGLView::sharedOpenGLView(); + view->setFrameWidthAndHeight(w, h); + // if you want to run in WVGA with HVGA resource, set it + // view->create(320, 480); + cocos2d::CCDirector::sharedDirector()->setOpenGLView(view); + + CCFileUtils::setRelativePath(IMG_PATH); + + AppDelegate *pAppDelegate = new AppDelegate(); + cocos2d::CCApplication::sharedApplication().run(); + } + else + { + cocos2d::CCTextureCache::reloadAllTextures(); + cocos2d::CCDirector::sharedDirector()->setGLDefaultValues(); + } +} + +} diff --git a/HelloLua/android/res/layout/game_demo.xml b/HelloLua/android/res/layout/game_demo.xml new file mode 100644 index 0000000000..09a239fbdc --- /dev/null +++ b/HelloLua/android/res/layout/game_demo.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/HelloLua/android/res/values/strings.xml b/HelloLua/android/res/values/strings.xml new file mode 100644 index 0000000000..8736404c10 --- /dev/null +++ b/HelloLua/android/res/values/strings.xml @@ -0,0 +1,4 @@ + + + HelloLua + diff --git a/HelloLua/android/src/org/cocos2dx/hellolua/HelloLua.java b/HelloLua/android/src/org/cocos2dx/hellolua/HelloLua.java new file mode 100644 index 0000000000..2211591244 --- /dev/null +++ b/HelloLua/android/src/org/cocos2dx/hellolua/HelloLua.java @@ -0,0 +1,49 @@ +package org.cocos2dx.hellolua; +import org.cocos2dx.lib.Cocos2dxActivity; +import org.cocos2dx.lib.Cocos2dxGLSurfaceView; +import org.cocos2dx.hellolua.R; + + +import android.opengl.GLSurfaceView; +import android.os.Bundle; + +public class HelloLua extends Cocos2dxActivity{ + protected void onCreate(Bundle savedInstanceState){ + super.onCreate(savedInstanceState); + + // get the packageName,it's used to set the resource path + String packageName = getApplication().getPackageName(); + super.setPackageName(packageName); + + setContentView(R.layout.game_demo); + mGLView = (Cocos2dxGLSurfaceView) findViewById(R.id.game_gl_surfaceview); + + // Get the size of the mGLView after the layout happens + mGLView.post(new Runnable() { + + @Override + public void run() { + Cocos2dxActivity.screenHeight = mGLView.getHeight(); + Cocos2dxActivity.screenWidth = mGLView.getWidth(); + } + }); + } + + @Override + protected void onPause() { + super.onPause(); + mGLView.onPause(); + } + + @Override + protected void onResume() { + super.onResume(); + mGLView.onResume(); + } + + private GLSurfaceView mGLView; + + static { + System.loadLibrary("game"); + } +} diff --git a/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxAccelerometer.java b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxAccelerometer.java new file mode 100644 index 0000000000..2978066f0e --- /dev/null +++ b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxAccelerometer.java @@ -0,0 +1,52 @@ +package org.cocos2dx.lib; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; + +/** + * + * This class is used for controlling the Accelerometer + * + */ +public class Cocos2dxAccelerometer implements SensorEventListener { + + private static final String TAG = "Cocos2dxAccelerometer"; + private Context mContext; + private SensorManager mSensorManager; + private Sensor mAccelerometer; + + public Cocos2dxAccelerometer(Context context){ + mContext = context; + + //Get an instance of the SensorManager + mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); + mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + } + + public void enable() { + mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); + } + + public void disable () { + mSensorManager.unregisterListener(this); + } + + @Override + public void onSensorChanged(SensorEvent event) { + + if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) + return; + + onSensorChanged(event.values[0], event.values[1], event.values[2], event.timestamp); + + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + + private static native void onSensorChanged(float x, float y, float z, long timeStamp); +} diff --git a/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxActivity.java b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxActivity.java new file mode 100644 index 0000000000..b27ac6f24f --- /dev/null +++ b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxActivity.java @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This is a small port of the "San Angeles Observation" demo + * program for OpenGL ES 1.x. For more details, see: + * + * http://jet.ro/visuals/san-angeles-observation/ + * + * This program demonstrates how to use a GLSurfaceView from Java + * along with native OpenGL calls to perform frame rendering. + * + * Touching the screen will start/stop the animation. + * + * Note that the demo runs much faster on the emulator than on + * real devices, this is mainly due to the following facts: + * + * - the demo sends bazillions of polygons to OpenGL without + * even trying to do culling. Most of them are clearly out + * of view. + * + * - on a real device, the GPU bus is the real bottleneck + * that prevent the demo from getting acceptable performance. + * + * - the software OpenGL engine used in the emulator uses + * the system bus instead, and its code rocks :-) + * + * Fixing the program to send less polygons to the GPU is left + * as an exercise to the reader. As always, patches welcomed :-) + */ + +package org.cocos2dx.lib; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.DisplayMetrics; +import android.util.Log; + +public class Cocos2dxActivity extends Activity{ + public static int screenWidth; + public static int screenHeight; + private static Cocos2dxMusic backgroundMusicPlayer; + private static Cocos2dxSound soundPlayer; + private static Cocos2dxAccelerometer accelerometer; + private static boolean accelerometerEnabled = false; + private static Handler handler; + private final static int HANDLER_SHOW_DIALOG = 1; + private static String packageName; + + private static native void nativeSetPaths(String apkPath); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // get frame size + DisplayMetrics dm = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(dm); + screenWidth = dm.widthPixels; + screenHeight = dm.heightPixels; + accelerometer = new Cocos2dxAccelerometer(this); + + // init media player and sound player + backgroundMusicPlayer = new Cocos2dxMusic(this); + soundPlayer = new Cocos2dxSound(this); + + handler = new Handler(){ + public void handleMessage(Message msg){ + switch(msg.what){ + case HANDLER_SHOW_DIALOG: + showDialog(((DialogMessage)msg.obj).title, ((DialogMessage)msg.obj).message); + break; + } + } + }; + } + + public static void showMessageBox(String title, String message){ + Message msg = new Message(); + msg.what = HANDLER_SHOW_DIALOG; + msg.obj = new DialogMessage(title, message); + + handler.sendMessage(msg); + } + + public static void enableAccelerometer() { + accelerometerEnabled = true; + accelerometer.enable(); + } + + public static void disableAccelerometer() { + accelerometerEnabled = false; + accelerometer.disable(); + } + + public static void playBackgroundMusic(String path, boolean isLoop){ + backgroundMusicPlayer.playBackgroundMusic(path, isLoop); + } + + public static void stopBackgroundMusic(){ + backgroundMusicPlayer.stopBackgroundMusic(); + } + + public static void pauseBackgroundMusic(){ + backgroundMusicPlayer.pauseBackgroundMusic(); + } + + public static void resumeBackgroundMusic(){ + backgroundMusicPlayer.resumeBackgroundMusic(); + } + + public static void rewindBackgroundMusic(){ + backgroundMusicPlayer.rewindBackgroundMusic(); + } + + public static boolean isBackgroundMusicPlaying(){ + return backgroundMusicPlayer.isBackgroundMusicPlaying(); + } + + public static float getBackgroundMusicVolume(){ + return backgroundMusicPlayer.getBackgroundVolume(); + } + + public static void setBackgroundMusicVolume(float volume){ + backgroundMusicPlayer.setBackgroundVolume(volume); + } + + public static int playEffect(String path){ + return soundPlayer.playEffect(path); + } + + public static void stopEffect(int soundId){ + soundPlayer.stopEffect(soundId); + } + + public static float getEffectsVolume(){ + return soundPlayer.getEffectsVolume(); + } + + public static void setEffectsVolume(float volume){ + soundPlayer.setEffectsVolume(volume); + } + + public static void preloadEffect(String path){ + soundPlayer.preloadEffect(path); + } + + public static void unloadEffect(String path){ + soundPlayer.unloadEffect(path); + } + + public static void end(){ + backgroundMusicPlayer.end(); + soundPlayer.end(); + } + + public static String getCocos2dxPackageName(){ + return packageName; + } + + @Override + protected void onResume() { + super.onResume(); + if (accelerometerEnabled) { + accelerometer.enable(); + } + + // resume background music + resumeBackgroundMusic(); + } + + @Override + protected void onPause() { + super.onPause(); + if (accelerometerEnabled) { + accelerometer.disable(); + } + + // pause background music + pauseBackgroundMusic(); + } + + protected void setPackageName(String packageName) { + Cocos2dxActivity.packageName = packageName; + + String apkFilePath = ""; + ApplicationInfo appInfo = null; + PackageManager packMgmr = getApplication().getPackageManager(); + try { + appInfo = packMgmr.getApplicationInfo(packageName, 0); + } catch (NameNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException("Unable to locate assets, aborting..."); + } + apkFilePath = appInfo.sourceDir; + Log.w("apk path", apkFilePath); + + // add this link at the renderer class + nativeSetPaths(apkFilePath); + } + + private void showDialog(String title, String message){ + Dialog dialog = new AlertDialog.Builder(this) + .setTitle(title) + .setMessage(message) + .setPositiveButton("Ok", + new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int whichButton){ + + } + }).create(); + + dialog.show(); + } +} + +class DialogMessage { + public String title; + public String message; + + public DialogMessage(String title, String message){ + this.message = message; + this.title = title; + } +} diff --git a/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java new file mode 100644 index 0000000000..ea4e8a9460 --- /dev/null +++ b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java @@ -0,0 +1,374 @@ +package org.cocos2dx.lib; + +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.os.Handler; +import android.os.Message; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.inputmethod.InputMethodManager; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; + +class TextInputWraper implements TextWatcher, OnEditorActionListener { + + private static final Boolean debug = false; + private void LogD(String msg) { + if (debug) Log.d("TextInputFilter", msg); + } + + private Cocos2dxGLSurfaceView mMainView; + private String mText; + private String mOriginText; + + private Boolean isFullScreenEdit() { + InputMethodManager imm = (InputMethodManager)mMainView.getTextField().getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + return imm.isFullscreenMode(); + } + + public TextInputWraper(Cocos2dxGLSurfaceView view) { + mMainView = view; + } + + public void setOriginText(String text) { + mOriginText = text; + } + + @Override + public void afterTextChanged(Editable s) { + if (isFullScreenEdit()) { + return; + } + + LogD("afterTextChanged: " + s); + int nModified = s.length() - mText.length(); + if (nModified > 0) { + final String insertText = s.subSequence(mText.length(), s.length()).toString(); + mMainView.insertText(insertText); + LogD("insertText(" + insertText + ")"); + } + else { + for (; nModified < 0; ++nModified) { + mMainView.deleteBackward(); + LogD("deleteBackward"); + } + } + mText = s.toString(); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + LogD("beforeTextChanged(" + s + ")start: " + start + ",count: " + count + ",after: " + after); + mText = s.toString(); + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (mMainView.getTextField() == v && isFullScreenEdit()) { + // user press the action button, delete all old text and insert new text + for (int i = mOriginText.length(); i > 0; --i) { + mMainView.deleteBackward(); + LogD("deleteBackward"); + } + String text = v.getText().toString(); + if ('\n' != text.charAt(text.length() - 1)) { + text += '\n'; + } + final String insertText = text; + mMainView.insertText(insertText); + LogD("insertText(" + insertText + ")"); + } + return false; + } +} + +public class Cocos2dxGLSurfaceView extends GLSurfaceView { + + static private Cocos2dxGLSurfaceView mainView; + + private static final String TAG = Cocos2dxGLSurfaceView.class.getCanonicalName(); + private Cocos2dxRenderer mRenderer; + + private static final boolean debug = false; + + /////////////////////////////////////////////////////////////////////////// + // for initialize + /////////////////////////////////////////////////////////////////////////// + public Cocos2dxGLSurfaceView(Context context) { + super(context); + initView(); + } + + public Cocos2dxGLSurfaceView(Context context, AttributeSet attrs) { + super(context, attrs); + initView(); + } + + protected void initView() { + mRenderer = new Cocos2dxRenderer(); + setFocusableInTouchMode(true); + setRenderer(mRenderer); + + textInputWraper = new TextInputWraper(this); + + handler = new Handler(){ + public void handleMessage(Message msg){ + switch(msg.what){ + case HANDLER_OPEN_IME_KEYBOARD: + if (null != mTextField && mTextField.requestFocus()) { + mTextField.removeTextChangedListener(textInputWraper); + mTextField.setText(""); + String text = (String)msg.obj; + mTextField.append(text); + textInputWraper.setOriginText(text); + mTextField.addTextChangedListener(textInputWraper); + InputMethodManager imm = (InputMethodManager)mainView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(mTextField, 0); + Log.d("GLSurfaceView", "showSoftInput"); + } + break; + + case HANDLER_CLOSE_IME_KEYBOARD: + if (null != mTextField) { + mTextField.removeTextChangedListener(textInputWraper); + InputMethodManager imm = (InputMethodManager)mainView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(mTextField.getWindowToken(), 0); + Log.d("GLSurfaceView", "HideSoftInput"); + } + break; + } + } + }; + + mainView = this; + } + + public void onPause(){ + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleOnPause(); + } + }); + + super.onPause(); + } + + public void onResume(){ + super.onResume(); + + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleOnResume(); + } + }); + } + + /////////////////////////////////////////////////////////////////////////// + // for text input + /////////////////////////////////////////////////////////////////////////// + private final static int HANDLER_OPEN_IME_KEYBOARD = 2; + private final static int HANDLER_CLOSE_IME_KEYBOARD = 3; + private static Handler handler; + private static TextInputWraper textInputWraper; + private TextView mTextField; + + public TextView getTextField() { + return mTextField; + } + + public void setTextField(TextView view) { + mTextField = view; + if (null != mTextField && null != textInputWraper) { + LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) mTextField.getLayoutParams(); + linearParams.height = 0; + mTextField.setLayoutParams(linearParams); + mTextField.setOnEditorActionListener(textInputWraper); + } + } + + public static void openIMEKeyboard() { + Message msg = new Message(); + msg.what = HANDLER_OPEN_IME_KEYBOARD; + msg.obj = mainView.getContentText(); + handler.sendMessage(msg); + + } + + private String getContentText() { + return mRenderer.getContentText(); + } + + public static void closeIMEKeyboard() { + Message msg = new Message(); + msg.what = HANDLER_CLOSE_IME_KEYBOARD; + handler.sendMessage(msg); + } + + public void insertText(final String text) { + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleInsertText(text); + } + }); + } + + public void deleteBackward() { + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleDeleteBackward(); + } + }); + } + + /////////////////////////////////////////////////////////////////////////// + // for touch event + /////////////////////////////////////////////////////////////////////////// + + public boolean onTouchEvent(final MotionEvent event) { + // these data are used in ACTION_MOVE and ACTION_CANCEL + final int pointerNumber = event.getPointerCount(); + final int[] ids = new int[pointerNumber]; + final float[] xs = new float[pointerNumber]; + final float[] ys = new float[pointerNumber]; + + for (int i = 0; i < pointerNumber; i++) { + ids[i] = event.getPointerId(i); + xs[i] = event.getX(i); + ys[i] = event.getY(i); + } + + switch (event.getAction() & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_POINTER_DOWN: + final int idPointerDown = event.getAction() >> MotionEvent.ACTION_POINTER_ID_SHIFT; + final float xPointerDown = event.getX(idPointerDown); + final float yPointerDown = event.getY(idPointerDown); + + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleActionDown(idPointerDown, xPointerDown, yPointerDown); + } + }); + break; + + case MotionEvent.ACTION_DOWN: + // there are only one finger on the screen + final int idDown = event.getPointerId(0); + final float xDown = event.getX(idDown); + final float yDown = event.getY(idDown); + + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleActionDown(idDown, xDown, yDown); + } + }); + break; + + case MotionEvent.ACTION_MOVE: + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleActionMove(ids, xs, ys); + } + }); + break; + + case MotionEvent.ACTION_POINTER_UP: + final int idPointerUp = event.getAction() >> MotionEvent.ACTION_POINTER_ID_SHIFT; + final float xPointerUp = event.getX(idPointerUp); + final float yPointerUp = event.getY(idPointerUp); + + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleActionUp(idPointerUp, xPointerUp, yPointerUp); + } + }); + break; + + case MotionEvent.ACTION_UP: + // there are only one finger on the screen + final int idUp = event.getPointerId(0); + final float xUp = event.getX(idUp); + final float yUp = event.getY(idUp); + + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleActionUp(idUp, xUp, yUp); + } + }); + break; + + case MotionEvent.ACTION_CANCEL: + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleActionCancel(ids, xs, ys); + } + }); + break; + } + + if (debug){ + dumpEvent(event); + } + return true; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + final int kc = keyCode; + if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) { + queueEvent(new Runnable() { + @Override + public void run() { + mRenderer.handleKeyDown(kc); + } + }); + return true; + } + return super.onKeyDown(keyCode, event); + } + // Show an event in the LogCat view, for debugging + private void dumpEvent(MotionEvent event) { + String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" , + "POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" }; + StringBuilder sb = new StringBuilder(); + int action = event.getAction(); + int actionCode = action & MotionEvent.ACTION_MASK; + sb.append("event ACTION_" ).append(names[actionCode]); + if (actionCode == MotionEvent.ACTION_POINTER_DOWN + || actionCode == MotionEvent.ACTION_POINTER_UP) { + sb.append("(pid " ).append( + action >> MotionEvent.ACTION_POINTER_ID_SHIFT); + sb.append(")" ); + } + sb.append("[" ); + for (int i = 0; i < event.getPointerCount(); i++) { + sb.append("#" ).append(i); + sb.append("(pid " ).append(event.getPointerId(i)); + sb.append(")=" ).append((int) event.getX(i)); + sb.append("," ).append((int) event.getY(i)); + if (i + 1 < event.getPointerCount()) + sb.append(";" ); + } + sb.append("]" ); + Log.d(TAG, sb.toString()); + } +} diff --git a/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxMusic.java b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxMusic.java new file mode 100644 index 0000000000..dc41024270 --- /dev/null +++ b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxMusic.java @@ -0,0 +1,177 @@ +package org.cocos2dx.lib; + +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.media.MediaPlayer; +import android.util.Log; + +/** + * + * This class is used for controlling background music + * + */ +public class Cocos2dxMusic { + + private static final String TAG = "Cocos2dxMusic"; + private float mLeftVolume; + private float mRightVolume; + private Context mContext; + private MediaPlayer mBackgroundMediaPlayer; + private boolean mIsPaused; + private String mCurrentPath; + + public Cocos2dxMusic(Context context){ + this.mContext = context; + initData(); + } + + public void playBackgroundMusic(String path, boolean isLoop){ + if (mCurrentPath == null){ + // it is the first time to play background music + // or end() was called + mBackgroundMediaPlayer = createMediaplayerFromAssets(path); + mCurrentPath = path; + } + else { + if (! mCurrentPath.equals(path)){ + // play new background music + + // release old resource and create a new one + if (mBackgroundMediaPlayer != null){ + mBackgroundMediaPlayer.release(); + } + mBackgroundMediaPlayer = createMediaplayerFromAssets(path); + + // record the path + mCurrentPath = path; + } + } + + if (mBackgroundMediaPlayer == null){ + Log.e(TAG, "playBackgroundMusic: background media player is null"); + } else { + // if the music is playing or paused, stop it + mBackgroundMediaPlayer.stop(); + + mBackgroundMediaPlayer.setLooping(isLoop); + + try { + mBackgroundMediaPlayer.prepare(); + mBackgroundMediaPlayer.seekTo(0); + mBackgroundMediaPlayer.start(); + + this.mIsPaused = false; + } catch (Exception e){ + Log.e(TAG, "playBackgroundMusic: error state"); + } + } + } + + public void stopBackgroundMusic(){ + if (mBackgroundMediaPlayer != null){ + mBackgroundMediaPlayer.stop(); + + // should set the state, if not , the following sequence will be error + // play -> pause -> stop -> resume + this.mIsPaused = false; + } + } + + public void pauseBackgroundMusic(){ + if (mBackgroundMediaPlayer != null && mBackgroundMediaPlayer.isPlaying()){ + mBackgroundMediaPlayer.pause(); + this.mIsPaused = true; + } + } + + public void resumeBackgroundMusic(){ + if (mBackgroundMediaPlayer != null && this.mIsPaused){ + mBackgroundMediaPlayer.start(); + this.mIsPaused = false; + } + } + + public void rewindBackgroundMusic(){ + if (mBackgroundMediaPlayer != null){ + mBackgroundMediaPlayer.stop(); + + try { + mBackgroundMediaPlayer.prepare(); + mBackgroundMediaPlayer.seekTo(0); + mBackgroundMediaPlayer.start(); + + this.mIsPaused = false; + } catch (Exception e){ + Log.e(TAG, "rewindBackgroundMusic: error state"); + } + } + } + + public boolean isBackgroundMusicPlaying(){ + boolean ret = false; + + if (mBackgroundMediaPlayer == null){ + ret = false; + } else { + ret = mBackgroundMediaPlayer.isPlaying(); + } + + return ret; + } + + public void end(){ + if (mBackgroundMediaPlayer != null){ + mBackgroundMediaPlayer.release(); + } + + initData(); + } + + public float getBackgroundVolume(){ + if (this.mBackgroundMediaPlayer != null){ + return (this.mLeftVolume + this.mRightVolume) / 2; + } else { + return 0.0f; + } + } + + public void setBackgroundVolume(float volume){ + if (this.mBackgroundMediaPlayer != null){ + this.mLeftVolume = this.mRightVolume = volume; + this.mBackgroundMediaPlayer.setVolume(this.mLeftVolume, this.mRightVolume); + } + } + + private void initData(){ + mLeftVolume =0.5f; + mRightVolume = 0.5f; + mBackgroundMediaPlayer = null; + mIsPaused = false; + mCurrentPath = null; + } + + /** + * create mediaplayer for music + * @param path the path relative to assets + * @return + */ + private MediaPlayer createMediaplayerFromAssets(String path){ + MediaPlayer mediaPlayer = null; + + try{ + AssetFileDescriptor assetFileDescritor = mContext.getAssets().openFd(path); + + mediaPlayer = new MediaPlayer(); + mediaPlayer.setDataSource(assetFileDescritor.getFileDescriptor(), + assetFileDescritor.getStartOffset(), assetFileDescritor.getLength()); + mediaPlayer.prepare(); + + mediaPlayer.setVolume(mLeftVolume, mRightVolume); + }catch (Exception e) { + mediaPlayer = null; + Log.e(TAG, "error: " + e.getMessage(), e); + } + + return mediaPlayer; + } +} diff --git a/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxRenderer.java b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxRenderer.java new file mode 100644 index 0000000000..95139b4dc6 --- /dev/null +++ b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxRenderer.java @@ -0,0 +1,107 @@ +package org.cocos2dx.lib; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +import android.opengl.GLSurfaceView; + +public class Cocos2dxRenderer implements GLSurfaceView.Renderer { + private final static long NANOSECONDSPERSECOND = 1000000000L; + private final static long NANOSECONDSPERMINISECOND = 1000000; + private static long animationInterval = (long)(1.0 / 60 * NANOSECONDSPERSECOND); + private long last; + + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + nativeInit(Cocos2dxActivity.screenWidth, Cocos2dxActivity.screenHeight); + last = System.nanoTime(); + } + + public void onSurfaceChanged(GL10 gl, int w, int h) { + } + + public void onDrawFrame(GL10 gl) { + + long now = System.nanoTime(); + long interval = now - last; + + // should render a frame when onDrawFrame() is called + // or there is a "ghost" + nativeRender(); + + // fps controlling + if (interval < animationInterval){ + try { + // because we render it before, so we should sleep twice time interval + Thread.sleep((animationInterval - interval) * 2 / NANOSECONDSPERMINISECOND); + } catch (Exception e){} + } + + last = now; + } + + public void handleActionDown(int id, float x, float y) + { + nativeTouchesBegin(id, x, y); + } + + public void handleActionUp(int id, float x, float y) + { + nativeTouchesEnd(id, x, y); + } + + public void handleActionCancel(int[] id, float[] x, float[] y) + { + nativeTouchesCancel(id, x, y); + } + + public void handleActionMove(int[] id, float[] x, float[] y) + { + nativeTouchesMove(id, x, y); + } + + public void handleKeyDown(int keyCode) + { + nativeKeyDown(keyCode); + } + + public void handleOnPause(){ + nativeOnPause(); + } + + public void handleOnResume(){ + nativeOnResume(); + } + + public static void setAnimationInterval(double interval){ + animationInterval = (long)(interval * NANOSECONDSPERSECOND); + } + private static native void nativeTouchesBegin(int id, float x, float y); + private static native void nativeTouchesEnd(int id, float x, float y); + private static native void nativeTouchesMove(int[] id, float[] x, float[] y); + private static native void nativeTouchesCancel(int[] id, float[] x, float[] y); + private static native boolean nativeKeyDown(int keyCode); + private static native void nativeRender(); + private static native void nativeInit(int w, int h); + private static native void nativeOnPause(); + private static native void nativeOnResume(); + + ///////////////////////////////////////////////////////////////////////////////// + // handle input method edit message + ///////////////////////////////////////////////////////////////////////////////// + + public void handleInsertText(final String text) { + nativeInsertText(text); + } + + public void handleDeleteBackward() { + nativeDeleteBackward(); + } + + public String getContentText() { + return nativeGetContentText(); + } + + private static native void nativeInsertText(String text); + private static native void nativeDeleteBackward(); + private static native String nativeGetContentText(); +} diff --git a/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxSound.java b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxSound.java new file mode 100644 index 0000000000..f6690f93a5 --- /dev/null +++ b/HelloLua/android/src/org/cocos2dx/lib/Cocos2dxSound.java @@ -0,0 +1,148 @@ +package org.cocos2dx.lib; + +import java.util.HashMap; + +import android.content.Context; +import android.media.AudioManager; +import android.media.SoundPool; +import android.util.Log; + +/** + * + * This class is used for controlling effect + * + */ + +public class Cocos2dxSound { + private Context mContext; + private SoundPool mSoundPool; + private float mLeftVolume; + private float mRightVolume; + + // sound id and stream id map + private HashMap mSoundIdStreamIdMap; + // sound path and sound id map + private HashMap mPathSoundIDMap; + + private static final String TAG = "Cocos2dxSound"; + private static final int MAX_SIMULTANEOUS_STREAMS_DEFAULT = 5; + private static final float SOUND_RATE = 1.0f; + private static final int SOUND_PRIORITY = 1; + private static final int SOUND_LOOP_TIME = 0; + private static final int SOUND_QUALITY = 5; + + private final int INVALID_SOUND_ID = -1; + private final int INVALID_STREAM_ID = -1; + + public Cocos2dxSound(Context context){ + this.mContext = context; + initData(); + } + + public int preloadEffect(String path){ + int soundId = INVALID_SOUND_ID; + + // if the sound is preloaded, pass it + if (this.mPathSoundIDMap.get(path) != null){ + soundId = this.mPathSoundIDMap.get(path).intValue(); + } else { + soundId = createSoundIdFromAsset(path); + + if (soundId != INVALID_SOUND_ID){ + // the sound is loaded but has not been played + this.mSoundIdStreamIdMap.put(soundId, INVALID_STREAM_ID); + + // record path and sound id map + this.mPathSoundIDMap.put(path, soundId); + } + } + + + + return soundId; + } + + public void unloadEffect(String path){ + // get sound id and remove from mPathSoundIDMap + Integer soundId = this.mPathSoundIDMap.remove(path); + + if (soundId != null){ + // unload effect + this.mSoundPool.unload(soundId.intValue()); + + // remove record from mSoundIdStreamIdMap + this.mSoundIdStreamIdMap.remove(soundId); + } + } + + public int playEffect(String path){ + Integer soundId = this.mPathSoundIDMap.get(path); + + if (soundId != null){ + // the sound is preloaded + + // play sound + int streamId = this.mSoundPool.play(soundId.intValue(), this.mLeftVolume, + this.mRightVolume, SOUND_PRIORITY, SOUND_LOOP_TIME, SOUND_RATE); + + // record sound id and stream id map + this.mSoundIdStreamIdMap.put(soundId, streamId); + } else { + // the effect is not prepared + soundId = preloadEffect(path); + if (soundId == INVALID_SOUND_ID){ + // can not preload effect + return INVALID_SOUND_ID; + } + + playEffect(path); + } + + return soundId.intValue(); + } + + public void stopEffect(int soundId){ + Integer streamId = this.mSoundIdStreamIdMap.get(soundId); + + if (streamId != null && streamId.intValue() != INVALID_STREAM_ID){ + this.mSoundPool.stop(streamId.intValue()); + } + } + + public float getEffectsVolume(){ + return (this.mLeftVolume + this.mRightVolume) / 2; + } + + public void setEffectsVolume(float volume){ + this.mLeftVolume = this.mRightVolume = volume; + } + + public void end(){ + this.mSoundPool.release(); + this.mPathSoundIDMap.clear(); + this.mSoundIdStreamIdMap.clear(); + + initData(); + } + + public int createSoundIdFromAsset(String path){ + int soundId = INVALID_SOUND_ID; + + try { + soundId = mSoundPool.load(mContext.getAssets().openFd(path), 0); + } catch(Exception e){ + Log.e(TAG, "error: " + e.getMessage(), e); + } + + return soundId; + } + + private void initData(){ + this.mSoundIdStreamIdMap = new HashMap(); + mSoundPool = new SoundPool(MAX_SIMULTANEOUS_STREAMS_DEFAULT, AudioManager.STREAM_MUSIC, SOUND_QUALITY); + mPathSoundIDMap = new HashMap(); + + this.mLeftVolume = 0.5f; + this.mRightVolume = 0.5f; + } +} diff --git a/HelloLua/ios/HelloLua.xcodeproj/project.pbxproj.REMOVED.git-id b/HelloLua/ios/HelloLua.xcodeproj/project.pbxproj.REMOVED.git-id new file mode 100644 index 0000000000..9cb3c5c92d --- /dev/null +++ b/HelloLua/ios/HelloLua.xcodeproj/project.pbxproj.REMOVED.git-id @@ -0,0 +1 @@ +fa7dfcb01ab5dedab7cf38ce21a1c0b5ea7ceda5 \ No newline at end of file diff --git a/HelloLua/ios/HelloLuaAppController.h b/HelloLua/ios/HelloLuaAppController.h new file mode 100644 index 0000000000..03aa6ad390 --- /dev/null +++ b/HelloLua/ios/HelloLuaAppController.h @@ -0,0 +1,14 @@ +// +// HelloLuaAppController.h +// HelloLua +// +// Created by Walzer on 11-6-15. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// + +@interface HelloLuaAppController : NSObject { + UIWindow *window; +} + +@end + diff --git a/HelloLua/ios/HelloLuaAppController.mm b/HelloLua/ios/HelloLuaAppController.mm new file mode 100644 index 0000000000..ca0b7b4c59 --- /dev/null +++ b/HelloLua/ios/HelloLuaAppController.mm @@ -0,0 +1,97 @@ +// +// HelloLuaAppController.mm +// HelloLua +// +// Created by Walzer on 11-6-15. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// +#import +#import "HelloLuaAppController.h" +#import "cocos2d.h" +#import "EAGLView.h" +#import "AppDelegate.h" + +@implementation HelloLuaAppController + +#pragma mark - +#pragma mark Application lifecycle + +// cocos2d application instance +static AppDelegate s_sharedApplication; + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + + // Override point for customization after application launch. + + // Add the view controller's view to the window and display. + window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; + EAGLView *__glView = [EAGLView viewWithFrame: [window bounds] + pixelFormat: kEAGLColorFormatRGBA8 + depthFormat: GL_DEPTH_COMPONENT16_OES + preserveBackbuffer: NO + sharegroup: nil + multiSampling: NO + numberOfSamples: 0 ]; + [window addSubview: __glView]; + [window makeKeyAndVisible]; + + [[UIApplication sharedApplication] setStatusBarHidden: YES]; + + cocos2d::CCApplication::sharedApplication().run(); + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + /* + Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. + */ + cocos2d::CCDirector::sharedDirector()->pause(); +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + /* + Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + */ + cocos2d::CCDirector::sharedDirector()->resume(); +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + /* + Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + If your application supports background execution, called instead of applicationWillTerminate: when the user quits. + */ + cocos2d::CCDirector::sharedDirector()->stopAnimation(); +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + /* + Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background. + */ + cocos2d::CCDirector::sharedDirector()->startAnimation(); +} + +- (void)applicationWillTerminate:(UIApplication *)application { + /* + Called when the application is about to terminate. + See also applicationDidEnterBackground:. + */ +} + + +#pragma mark - +#pragma mark Memory management + +- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { + /* + Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later. + */ +} + + +- (void)dealloc { + [super dealloc]; +} + + +@end diff --git a/HelloLua/ios/HelloLua_Prefix.pch b/HelloLua/ios/HelloLua_Prefix.pch new file mode 100644 index 0000000000..b4311a0a3d --- /dev/null +++ b/HelloLua/ios/HelloLua_Prefix.pch @@ -0,0 +1,8 @@ +// +// Prefix header for all source files of the 'HelloLua' target in the 'HelloLua' project +// + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/HelloLua/ios/main.m b/HelloLua/ios/main.m new file mode 100644 index 0000000000..c51c378385 --- /dev/null +++ b/HelloLua/ios/main.m @@ -0,0 +1,16 @@ +// +// main.m +// HelloLua +// +// Created by Walzer on 11-6-15. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// + +#import + +int main(int argc, char *argv[]) { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + int retVal = UIApplicationMain(argc, argv, nil, @"HelloLuaAppController"); + [pool release]; + return retVal; +} diff --git a/HelloLua/win32/HelloLua.win32.vcproj b/HelloLua/win32/HelloLua.win32.vcproj new file mode 100644 index 0000000000..b7396a3f63 --- /dev/null +++ b/HelloLua/win32/HelloLua.win32.vcproj @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HelloLua/win32/HelloLua.win32.vcproj.user b/HelloLua/win32/HelloLua.win32.vcproj.user new file mode 100644 index 0000000000..9a000abe2c --- /dev/null +++ b/HelloLua/win32/HelloLua.win32.vcproj.user @@ -0,0 +1,23 @@ + + + + + + + + + + + diff --git a/HelloLua/win32/main.cpp b/HelloLua/win32/main.cpp new file mode 100644 index 0000000000..a553fbb76d --- /dev/null +++ b/HelloLua/win32/main.cpp @@ -0,0 +1,17 @@ +#include "main.h" + +#include "AppDelegate.h" + +int APIENTRY _tWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + + // create the application instance + AppDelegate app; + + return cocos2d::CCApplication::sharedApplication().run(); +} diff --git a/HelloLua/win32/main.h b/HelloLua/win32/main.h new file mode 100644 index 0000000000..b5eb5a54a3 --- /dev/null +++ b/HelloLua/win32/main.h @@ -0,0 +1,13 @@ +#ifndef __MAIN_H__ +#define __MAIN_H__ + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +// Windows Header Files: +#include +#include + +// C RunTime Header Files +#include "CCStdC.h" + +#endif // __MAIN_H__ diff --git a/HelloWorld/android/jni/Android.mk b/HelloWorld/android/jni/Android.mk index bdef5abe06..915ac6baa7 100644 --- a/HelloWorld/android/jni/Android.mk +++ b/HelloWorld/android/jni/Android.mk @@ -3,7 +3,7 @@ include $(CLEAR_VARS) subdirs := $(addprefix $(LOCAL_PATH)/../../../,$(addsuffix /Android.mk, \ cocos2dx \ - CocosDenshion/android \ + CocosDenshion/android )) subdirs += $(LOCAL_PATH)/helloworld/Android.mk diff --git a/HelloWorld/android/jni/Application.mk b/HelloWorld/android/jni/Application.mk index 40ab23a70f..62edb0eee1 100644 --- a/HelloWorld/android/jni/Application.mk +++ b/HelloWorld/android/jni/Application.mk @@ -1,4 +1,4 @@ # it is needed for ndk-r5 APP_STL := stlport_static -APP_MODULES := cocos2d cocosdenshion helloworld \ No newline at end of file +APP_MODULES := helloworld \ No newline at end of file diff --git a/HelloWorld/android/jni/helloworld/Android.mk b/HelloWorld/android/jni/helloworld/Android.mk index 0d370ea1eb..b400c7095c 100644 --- a/HelloWorld/android/jni/helloworld/Android.mk +++ b/HelloWorld/android/jni/helloworld/Android.mk @@ -9,20 +9,30 @@ LOCAL_SRC_FILES := main.cpp \ LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../cocos2dx \ $(LOCAL_PATH)/../../../../cocos2dx/platform \ $(LOCAL_PATH)/../../../../cocos2dx/include \ + $(LOCAL_PATH)/../../../../cocos2dx/lua_support \ $(LOCAL_PATH)/../../../../CocosDenshion/include \ - $(LOCAL_PATH)/../../.. + $(LOCAL_PATH)/../../.. # it is used for ndk-r4 # if you build with nkd-r4, uncomment it -# LOCAL_LDLIBS := -L$(LOCAL_PATH)/../../libs/armeabi -lcocos2d -llog -lcocosdenshion \ -# -L$(LOCAL_PATH)/../../../../cocos2dx/platform/third_party/android/libraries -lcurl +# LOCAL_LDLIBS := -llog -lGLESv1_CM -llog -lz \ +# -L$(LOCAL_PATH)/../../../../cocos2dx/platform/third_party/android/libraries -lcurl \ +# -lpng \ +# -lxml2 \ +# -ljpeg \ +# -lskia # it is used for ndk-r5 # if you build with ndk-r4, comment it # because the new Windows toolchain doesn't support Cygwin's drive # mapping (i.e /cygdrive/c/ instead of C:/) -LOCAL_LDLIBS := -L$(call host-path, $(LOCAL_PATH)/../../libs/armeabi) \ - -lcocos2d -llog -lcocosdenshion \ - -L$(call host-path, $(LOCAL_PATH)/../../../../cocos2dx/platform/third_party/android/libraries) -lcurl +LOCAL_LDLIBS := -llog -lGLESv1_CM -llog -lz \ + -L$(call host-path, $(LOCAL_PATH)/../../../../cocos2dx/platform/third_party/android/libraries) -lcurl \ + -lpng \ + -lxml2 \ + -ljpeg \ + -lskia + +LOCAL_STATIC_LIBRARIES := libcocos2d libcocosdenshion include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/HelloWorld/android/src/org/cocos2dx/application/ApplicationDemo.java b/HelloWorld/android/src/org/cocos2dx/application/ApplicationDemo.java index 7c6cc98655..6d5b3dc51b 100644 --- a/HelloWorld/android/src/org/cocos2dx/application/ApplicationDemo.java +++ b/HelloWorld/android/src/org/cocos2dx/application/ApplicationDemo.java @@ -44,8 +44,6 @@ public class ApplicationDemo extends Cocos2dxActivity{ private GLSurfaceView mGLView; static { - System.loadLibrary("cocos2d"); - System.loadLibrary("cocosdenshion"); System.loadLibrary("helloworld"); } } diff --git a/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id b/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id index 27cf719725..5b906e2bbd 100644 --- a/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -631e30d698eec53284c6bd9facd0f3e44eb4f18c \ No newline at end of file +622833576c05896c841e7beaab322d4def50e54b \ No newline at end of file diff --git a/HelloWorld/win32/HelloWorld.win32.vcproj b/HelloWorld/win32/HelloWorld.win32.vcproj index 03e8ff49f6..e183643469 100644 --- a/HelloWorld/win32/HelloWorld.win32.vcproj +++ b/HelloWorld/win32/HelloWorld.win32.vcproj @@ -41,8 +41,8 @@ tick(m_fDeltaTime); } @@ -884,6 +890,20 @@ void CCDirector::setDeviceOrientation(ccDeviceOrientation kDeviceOrientation) } } + +#ifdef ENABLE_LUA +void CCDirector::registerTick(const char* szfn) +{ + if (szfn == NULL || strlen(szfn) == 0) + { + CCLOG("error registerTick"); + return ; + } + m_luatick = szfn; +} +#endif + + /*************************************************** * implementation of DisplayLinkDirector **************************************************/ diff --git a/cocos2dx/CCScheduler.cpp b/cocos2dx/CCScheduler.cpp index 14d081880f..48669aaf63 100644 --- a/cocos2dx/CCScheduler.cpp +++ b/cocos2dx/CCScheduler.cpp @@ -85,6 +85,33 @@ CCTimer* CCTimer::timerWithTarget(SelectorProtocol *pTarget, SEL_SCHEDULE pfnSel return pTimer; } +#ifdef ENABLE_LUA +CCTimer* CCTimer::timerWithScript(SelectorProtocol* pTarget, const char* szFuncName, ccTime fSeconds) +{ + CCTimer *pTimer = new CCTimer(); + pTimer->initWithScript(pTarget, szFuncName, fSeconds); + pTimer->autorelease(); + return pTimer; +} + +bool CCTimer::initWithScript(SelectorProtocol* pTarget, const char* szFuncName, ccTime fSeconds) +{ + m_pTarget= pTarget; + m_scriptFunc = szFuncName; + m_fElapsed = -1; + m_fInterval = fSeconds; + m_pfnSelector = NULL; + return true; +} +bool CCTimer::isScriptFuncExist( const char* szFuncName) +{ + if (m_pTarget&& szFuncName) + { + return strcmp(m_scriptFunc.c_str(), szFuncName)== 0? true: false; + } + return false; +} +#endif bool CCTimer::initWithTarget(SelectorProtocol *pTarget, SEL_SCHEDULE pfnSelector) { @@ -119,6 +146,13 @@ void CCTimer::update(ccTime dt) (m_pTarget->*m_pfnSelector)(m_fElapsed); m_fElapsed = 0; } +#ifdef ENABLE_LUA + else if (m_scriptFunc.size()) + { + schedule_SCHEDULE(m_pTarget, m_pfnSelector, m_fElapsed, m_scriptFunc); + m_fElapsed = 0; + } +#endif } } @@ -206,10 +240,13 @@ void CCScheduler::unscheduleAllTimers() { assert(false); } - +#ifdef ENABLE_LUA +void CCScheduler::scheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget, float fInterval, bool bPaused, const char* szScriptFunc) +#else void CCScheduler::scheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget, float fInterval, bool bPaused) +#endif { - assert(pfnSelector); + //assert(pfnSelector); assert(pTarget); tHashSelectorEntry *pElement = NULL; @@ -242,32 +279,66 @@ void CCScheduler::scheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *p for (unsigned int i = 0; i < pElement->timers->num; ++i) { CCTimer *timer = (CCTimer*)pElement->timers->arr[i]; +#ifdef ENABLE_LUA + if ((timer->m_pfnSelector &&pfnSelector == timer->m_pfnSelector) + || (szScriptFunc && timer->isScriptFuncExist(szScriptFunc))) + { + CCLOG("CCSheduler#scheduleSelector. Selector already scheduled."); + timer->m_fInterval = fInterval; + return; + } +#else if (pfnSelector == timer->m_pfnSelector) { CCLOG("CCSheduler#scheduleSelector. Selector already scheduled."); timer->m_fInterval = fInterval; return; } + +#endif + } ccArrayEnsureExtraCapacity(pElement->timers, 1); } CCTimer *pTimer = new CCTimer(); +#ifdef ENABLE_LUA + if (szScriptFunc) + { + pTimer->initWithScript(pTarget, szScriptFunc, fInterval); + } + else + { + pTimer->initWithTarget(pTarget, pfnSelector, fInterval); + } + +#else pTimer->initWithTarget(pTarget, pfnSelector, fInterval); +#endif ccArrayAppendObject(pElement->timers, pTimer); pTimer->release(); } - +#ifdef ENABLE_LUA +void CCScheduler::unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget, const char* szScriptFunc) +#else void CCScheduler::unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget) +#endif { // explicity handle nil arguments when removing an object +#ifdef ENABLE_LUA + if (pTarget == 0 || (pfnSelector == 0 && szScriptFunc == 0)) + { + return; + } +#else if (pTarget == 0 || pfnSelector == 0) { return; } +#endif - assert(pTarget); - assert(pfnSelector); + //assert(pTarget); + //assert(pfnSelector); tHashSelectorEntry *pElement = NULL; HASH_FIND_INT(m_pHashForSelectors, &pTarget, pElement); @@ -278,7 +349,12 @@ void CCScheduler::unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol { CCTimer *pTimer = (CCTimer*)(pElement->timers->arr[i]); +#ifdef ENABLE_LUA + if ((pTimer->m_pfnSelector&& pfnSelector == pTimer->m_pfnSelector) || + pTimer->isScriptFuncExist(szScriptFunc)) +#else if (pfnSelector == pTimer->m_pfnSelector) +#endif { if (pTimer == pElement->currentTimer && (! pElement->currentTimerSalvaged)) { @@ -562,7 +638,18 @@ void CCScheduler::tick(ccTime dt) { if (! pEntry->paused) { +#ifdef ENABLE_LUA + if (pEntry->target->m_scriptFunc[ccSEL_Update].size()) + { + schedule_SCHEDULE(NULL, NULL, dt, pEntry->target->m_scriptFunc[ccSEL_Update]); + } + else + { + pEntry->target->update(dt); + } +#else pEntry->target->update(dt); +#endif } } @@ -571,7 +658,19 @@ void CCScheduler::tick(ccTime dt) { if (! pEntry->paused) { +#ifdef ENABLE_LUA + if (pEntry->target->m_scriptFunc[ccSEL_Update].size()) + { + schedule_SCHEDULE(NULL, NULL,dt, pEntry->target->m_scriptFunc[ccSEL_Update]); + } + else + { + pEntry->target->update(dt); + } +#else pEntry->target->update(dt); +#endif + } } @@ -580,7 +679,19 @@ void CCScheduler::tick(ccTime dt) { if (! pEntry->paused) { +#ifdef ENABLE_LUA + if (pEntry->target->m_scriptFunc[ccSEL_Update].size()) + { + schedule_SCHEDULE(NULL, NULL,dt, pEntry->target->m_scriptFunc[ccSEL_Update]); + } + else + { + pEntry->target->update(dt); + } +#else pEntry->target->update(dt); +#endif + } } diff --git a/cocos2dx/actions/CCActionInstant.cpp b/cocos2dx/actions/CCActionInstant.cpp index 6b1aad7e39..12e958708f 100644 --- a/cocos2dx/actions/CCActionInstant.cpp +++ b/cocos2dx/actions/CCActionInstant.cpp @@ -268,6 +268,29 @@ namespace cocos2d { return pCallFunc; } +#ifdef ENABLE_LUA + CCCallFunc * CCCallFunc::actionWithLua(const char * pszfunc) + { + if (pszfunc) + { + + CCCallFunc* pCallFunc = new CCCallFunc(); + pCallFunc->initWithLua(pszfunc); + pCallFunc->autorelease(); + return pCallFunc; + } + return NULL; + } + bool CCCallFunc::initWithLua(const char* pszfn) + { + if (pszfn) + { + m_pLuaCallFun = pszfn; + return true; + } + return false; + } +#endif bool CCCallFunc::initWithTarget(SelectorProtocol* pSelectorTarget) { if (pSelectorTarget) @@ -306,20 +329,28 @@ namespace cocos2d { } void CCCallFunc::execute() { +#ifdef ENABLE_LUA + schedule_CallFunc(m_pSelectorTarget, m_pCallFunc, m_pLuaCallFun); +#else if(m_pCallFunc) { (m_pSelectorTarget->*m_pCallFunc)(); } +#endif } // // CallFuncN // void CCCallFuncN::execute() { +#ifdef ENABLE_LUA + schedule_CallFuncN(m_pSelectorTarget, m_pCallFuncN, m_pTarget, m_pLuaCallFun); +#else if(m_pCallFuncN) { (m_pSelectorTarget->*m_pCallFuncN)(m_pTarget); } +#endif } CCCallFuncN * CCCallFuncN::actionWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncN selector) { @@ -332,6 +363,20 @@ namespace cocos2d { CC_SAFE_DELETE(pRet); return NULL; } +#ifdef ENABLE_LUA + CCCallFuncN * CCCallFuncN::actionWithLua(const char * pszfunc) + { + + if (pszfunc) + { + CCCallFuncN *pRet = new CCCallFuncN(); + pRet->initWithLua(pszfunc); + pRet->autorelease(); + return pRet; + } + return NULL; + } +#endif bool CCCallFuncN::initWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncN selector) { if( CCCallFunc::initWithTarget(pSelectorTarget) ) @@ -341,6 +386,7 @@ namespace cocos2d { } return false; } + CCObject * CCCallFuncN::copyWithZone(CCZone* zone) { CCZone* pNewZone = NULL; @@ -371,6 +417,20 @@ namespace cocos2d { CC_SAFE_DELETE(pRet); return NULL; } +#ifdef ENABLE_LUA + CCCallFuncND * CCCallFuncND::actionWithLua(const char * pszfunc) + { + if (pszfunc) + { + CCCallFuncND* pRet = new CCCallFuncND(); + pRet->autorelease(); + pRet->initWithLua(pszfunc); + return pRet; + } + return NULL; + + } +#endif bool CCCallFuncND::initWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncND selector, void* d) { @@ -402,10 +462,14 @@ namespace cocos2d { void CCCallFuncND::execute() { +#ifdef ENABLE_LUA + schedule_CallFuncND(m_pSelectorTarget,m_pCallFuncND, m_pTarget, m_pData, m_pLuaCallFun); +#else if(m_pCallFuncND) { (m_pSelectorTarget->*m_pCallFuncND)(m_pTarget, m_pData); } +#endif } // @@ -423,10 +487,14 @@ namespace cocos2d { void CCCallFuncO::execute() { +#ifdef ENABLE_LUA + schedule_CallFuncO(m_pSelectorTarget, m_pCallFuncO, m_pObject, m_pLuaCallFun); +#else if(m_pCallFuncO) { (m_pSelectorTarget->*m_pCallFuncO)(m_pObject); } +#endif } CCCallFuncO * CCCallFuncO::actionWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncO selector, CCObject* pObject) { @@ -439,6 +507,20 @@ namespace cocos2d { CC_SAFE_DELETE(pRet); return NULL; } +#ifdef ENABLE_LUA + CCCallFuncO * CCCallFuncO::actionWithLua(const char * pszfunc) + { + if (pszfunc) + { + CCCallFuncO *pRet = new CCCallFuncO(); + pRet->autorelease(); + pRet->initWithLua(pszfunc); + return pRet; + } + return NULL; + + } +#endif bool CCCallFuncO::initWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncO selector, CCObject* pObject) { if( CCCallFunc::initWithTarget(pSelectorTarget) ) diff --git a/cocos2dx/base_nodes/CCNode.cpp b/cocos2dx/base_nodes/CCNode.cpp index 85dc5d588b..9ec241d508 100644 --- a/cocos2dx/base_nodes/CCNode.cpp +++ b/cocos2dx/base_nodes/CCNode.cpp @@ -933,7 +933,33 @@ void CCNode::unschedule(SEL_SCHEDULE selector) CCScheduler::sharedScheduler()->unscheduleSelector(selector, this); } +#ifdef ENABLE_LUA +void CCNode::schedule(const char* selector) +{ + if (selector == NULL || strlen(selector) == 0) + { + CCLog(" schedule Argument must be non-nil"); + } + this->schedule(selector, 0); + +} +void CCNode::schedule(const char* selector, ccTime interval) +{ + if (selector == NULL || strlen(selector) == 0) + { + CCLog(" schedule Argument must be non-nil"); + } + CCScheduler::sharedScheduler()->scheduleSelector(NULL, this, interval, !m_bIsRunning, selector); +} +void CCNode::unschedule(const char* selector) +{ + if (selector == 0) + return; + CCScheduler::sharedScheduler()->unscheduleSelector(NULL, this, selector); + +} +#endif void CCNode::unscheduleAllSelectors() { CCScheduler::sharedScheduler()->unscheduleAllSelectorsForTarget(this); @@ -1095,5 +1121,11 @@ CCPoint CCNode::convertTouchToNodeSpaceAR(CCTouch *touch) point = CCDirector::sharedDirector()->convertToGL(point); return this->convertToNodeSpaceAR(point); } +#ifdef ENABLE_LUA +bool CCNode::registerScriptSelector(const char* szType, const char* szSeletor) +{ + return SelectorProtocol::registerScriptSelector(szType, szSeletor); +} +#endif }//namespace cocos2d diff --git a/cocos2dx/include/CCActionInstant.h b/cocos2dx/include/CCActionInstant.h index 1fc3e4ca32..a61bd9f7f3 100644 --- a/cocos2dx/include/CCActionInstant.h +++ b/cocos2dx/include/CCActionInstant.h @@ -191,6 +191,11 @@ namespace cocos2d { typedef void (SelectorProtocol::*SEL_CallFunc)(); */ +#ifdef ENABLE_LUA + static CCCallFunc * actionWithLua(const char * pszfunc); + virtual bool initWithLua(const char* pszfn); +#endif + virtual bool initWithTarget(SelectorProtocol* pSelectorTarget); /** executes the callback */ virtual void execute(); @@ -200,6 +205,9 @@ namespace cocos2d { protected: SelectorProtocol* m_pSelectorTarget; +#ifdef ENABLE_LUA + std::string m_pLuaCallFun; +#endif union { SEL_CallFunc m_pCallFunc; @@ -227,6 +235,9 @@ namespace cocos2d { typedef void (SelectorProtocol::*SEL_CallFuncN)(CCNode*); */ +#ifdef ENABLE_LUA + static CCCallFuncN * actionWithLua(const char * pszfunc); +#endif virtual bool initWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncN selector); // super methods virtual CCObject* copyWithZone(CCZone *pZone); @@ -244,6 +255,9 @@ namespace cocos2d { /** creates the action with the callback and the data to pass as an argument */ static CCCallFuncND * actionWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncND selector, void* d); +#ifdef ENABLE_LUA + static CCCallFuncND * actionWithLua(const char * pszfunc); +#endif /** initializes the action with the callback and the data to pass as an argument */ virtual bool initWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncND selector, void* d); // super methods @@ -274,6 +288,9 @@ namespace cocos2d { typedef void (SelectorProtocol::*SEL_CallFuncO)(CCObject*); */ +#ifdef ENABLE_LUA + static CCCallFuncO * actionWithLua(const char * pszfunc); +#endif virtual bool initWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncO selector, CCObject* pObject); // super methods virtual CCObject* copyWithZone(CCZone *pZone); diff --git a/cocos2dx/include/CCDirector.h b/cocos2dx/include/CCDirector.h index 5208875abe..07bfc0d941 100644 --- a/cocos2dx/include/CCDirector.h +++ b/cocos2dx/include/CCDirector.h @@ -34,7 +34,9 @@ THE SOFTWARE. #include "CCGeometry.h" #include "CCEGLView.h" #include "CCGL.h" - +#ifdef ENABLE_LUA +#include +#endif namespace cocos2d { enum { @@ -311,6 +313,9 @@ public: /** Ends the execution, releases the running scene. It doesn't remove the OpenGL view from its parent. You have to do it manually. */ +#ifdef ENABLE_LUA + inline void endToLua(void){end();} +#endif void end(void); /** Pauses the running scene. @@ -425,6 +430,10 @@ public: /** detach the cocos2d view from the view/window */ bool detach(void); +#ifdef ENABLE_LUA + std::string m_luatick; + void registerTick(const char* szfn); +#endif public: /** returns a shared instance of the director */ static CCDirector* sharedDirector(void); diff --git a/cocos2dx/include/CCLayer.h b/cocos2dx/include/CCLayer.h index ad1e41dbf3..afcb972f00 100644 --- a/cocos2dx/include/CCLayer.h +++ b/cocos2dx/include/CCLayer.h @@ -225,6 +225,12 @@ public: /** creates a CCMultiplexLayer with one or more layers using a variable argument list. */ static CCMultiplexLayer * layerWithLayers(CCLayer* layer, ... ); + +#ifdef ENABLE_LUA + static CCMultiplexLayer * layerWithLayer(CCLayer* layer); + void addLayer(CCLayer* layer); + bool initWithLayer(CCLayer* layer); +#endif /** initializes a MultiplexLayer with one or more layers using a variable argument list. */ bool initWithLayers(CCLayer* layer, va_list params); /** switches to a certain layer indexed by n. diff --git a/cocos2dx/include/CCMenu.h b/cocos2dx/include/CCMenu.h index f60fcc08c9..cf304c34b7 100644 --- a/cocos2dx/include/CCMenu.h +++ b/cocos2dx/include/CCMenu.h @@ -57,7 +57,9 @@ namespace cocos2d{ virtual ~CCMenu(){} /** creates a CCMenu with it's items */ static CCMenu* menuWithItems(CCMenuItem* item, ...); - +#ifdef ENABLE_LUA + static CCMenu*menuWithItem(CCMenuItem* item); +#endif /** initializes a CCMenu with it's items */ bool initWithItems(CCMenuItem* item, va_list args); diff --git a/cocos2dx/include/CCMenuItem.h b/cocos2dx/include/CCMenuItem.h index b38a9715fb..920d69cd9a 100644 --- a/cocos2dx/include/CCMenuItem.h +++ b/cocos2dx/include/CCMenuItem.h @@ -69,6 +69,10 @@ namespace cocos2d{ virtual void selected(); /** The item was unselected */ virtual void unselected(); +#ifdef ENABLE_LUA + virtual void registerMenuHandler(const char* fn); + std::string m_strScriptFunc; +#endif protected: SelectorProtocol* m_pListener; SEL_MenuHandler m_pfnSelector; diff --git a/cocos2dx/include/CCMutableArray.h b/cocos2dx/include/CCMutableArray.h index ccc0fffbca..5bd0ddd34b 100644 --- a/cocos2dx/include/CCMutableArray.h +++ b/cocos2dx/include/CCMutableArray.h @@ -325,6 +325,12 @@ public: return m_array.rbegin(); } +#ifdef ENABLE_LUA + CCMutableArrayIterator endToLua(void) + { + return m_array.end(); + } +#endif CCMutableArrayIterator end(void) { return m_array.end(); diff --git a/cocos2dx/include/CCMutableDictionary.h b/cocos2dx/include/CCMutableDictionary.h index 8952c7e23f..bc722a28cb 100644 --- a/cocos2dx/include/CCMutableDictionary.h +++ b/cocos2dx/include/CCMutableDictionary.h @@ -182,6 +182,12 @@ public: return pObject; } +#ifdef ENABLE_LUA + void endToLua() + { + end(); + } +#endif void end() { m_bBegin = false; diff --git a/cocos2dx/include/CCNode.h b/cocos2dx/include/CCNode.h index ace5d56fc7..f128ad736c 100644 --- a/cocos2dx/include/CCNode.h +++ b/cocos2dx/include/CCNode.h @@ -450,6 +450,14 @@ namespace cocos2d { /** unschedules a custom selector.*/ void unschedule(SEL_SCHEDULE selector); + /* + ad for lua script + */ +#ifdef ENABLE_LUA + void schedule(const char* selector); + void schedule(const char* selector, ccTime interval); + void unschedule(const char* selector); +#endif /** unschedule all scheduled selectors: custom selectors, and the 'update' selector. Actions are not affected by this method. @since v0.99.3 @@ -525,6 +533,9 @@ namespace cocos2d { @since v0.7.1 */ CCPoint convertTouchToNodeSpaceAR(CCTouch * touch); +#ifdef ENABLE_LUA + bool registerScriptSelector(const char* szType, const char* szSeletor); +#endif }; }//namespace cocos2d diff --git a/cocos2dx/include/CCRenderTexture.h b/cocos2dx/include/CCRenderTexture.h index 51bf3715de..be5e7ca40f 100644 --- a/cocos2dx/include/CCRenderTexture.h +++ b/cocos2dx/include/CCRenderTexture.h @@ -75,6 +75,9 @@ public: void beginWithClear(float r, float g, float b, float a); /** ends grabbing */ +#ifdef ENABLE_LUA + inline void endToLua(){ end();}; +#endif void end(); /** clears the texture with a color */ diff --git a/cocos2dx/include/CCScheduler.h b/cocos2dx/include/CCScheduler.h index 170ed4b773..d8f974d97d 100644 --- a/cocos2dx/include/CCScheduler.h +++ b/cocos2dx/include/CCScheduler.h @@ -60,6 +60,14 @@ public: /** Allocates a timer with a target, a selector and an interval in seconds. */ static CCTimer* timerWithTarget(SelectorProtocol *pTarget, SEL_SCHEDULE pfnSelector, ccTime fSeconds); + +#ifdef ENABLE_LUA + //CCTimer init from Script + static CCTimer* timerWithScript(SelectorProtocol* pTarget, const char* szFuncName, ccTime fSeconds); + bool initWithScript(SelectorProtocol* pTarget, const char* szFuncName, ccTime fSeconds); + bool isScriptFuncExist( const char* szFuncName); + std::string m_scriptFunc; +#endif public: SEL_SCHEDULE m_pfnSelector; @@ -115,8 +123,11 @@ public: @since v0.99.3 */ +#ifdef ENABLE_LUA + void scheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget, ccTime fInterval, bool bPaused, const char* szScriptFunc = NULL); +#else void scheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget, ccTime fInterval, bool bPaused); - +#endif /** Schedules the 'update' selector for a given target with a given priority. The 'update' selector will be called every frame. The lower the priority, the earlier it is called. @@ -128,7 +139,11 @@ public: If you want to unschedule the "update", use unscheudleUpdateForTarget. @since v0.99.3 */ +#ifdef ENABLE_LUA + void unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget, const char* szScriptFunc = NULL); +#else void unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget); +#endif /** Unschedules the update selector for a given target @since v0.99.3 diff --git a/cocos2dx/include/CCTouchDelegateProtocol.h b/cocos2dx/include/CCTouchDelegateProtocol.h index 6e7d3213be..3dac0cc522 100644 --- a/cocos2dx/include/CCTouchDelegateProtocol.h +++ b/cocos2dx/include/CCTouchDelegateProtocol.h @@ -27,7 +27,12 @@ THE SOFTWARE. #define __TOUCH_DISPATHCHER_CCTOUCH_DELEGATE_PROTOCOL_H__ #include "CCObject.h" - +#include "ccConfig.h" +#ifdef ENABLE_LUA +#include "CCMutableDictionary.h" +#include "CCString.h" +#include "../lua_support/CCLuaSrcipt.h" +#endif namespace cocos2d { typedef enum @@ -46,7 +51,9 @@ class CC_DLL CCTouchDelegate { protected: ccTouchDelegateFlag m_eTouchDelegateType; - +#ifdef ENABLE_LUA + CCMutableDictionary *m_pEventDictionary; +#endif public: friend class CCTouchDispatcher; // only CCTouchDispatcher & children can change m_eTouchDelegateType inline ccTouchDelegateFlag getTouchDelegateType(void) { return m_eTouchDelegateType; } @@ -68,6 +75,90 @@ public: virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} + +#ifdef ENABLE_LUA + //use for lua register event + /* + szEventName must be one of follow value + { "ccTouchBegan" "ccTouchMoved" "ccTouchEnded" "ccTouchCancelled" } + */ + + + void registerLuaTouchEvent(const char* szEventName, const char* fn) + { + if (szEventName == NULL || strlen(szEventName) == 0 || fn == NULL || strlen(fn) == 0) + { + CCLog("registerEvent input parameter error "); + return ; + } + + std::string strEventType[] = {"ccTouchBegan", "ccTouchMoved", "ccTouchEnded", "ccTouchCancelled", + "ccMulTouchBegan", "ccMulTouchMoved", "ccMulTouchEnded", "ccMulTouchCancelled"}; + int nSize = sizeof(strEventType); + int nType = -1; + for(int i = 0; i < nSize; i++) + { + if (strcmp(strEventType[i].c_str(), szEventName) == 0) + { + nType = i; + break; + } + } + if(nType != -1) + { + if (m_pEventDictionary == NULL) + { + m_pEventDictionary = new CCMutableDictionary(); + } + + if (m_pEventDictionary->objectForKey(nType) == NULL) + { + CCString *pStr = new CCString(fn); + m_pEventDictionary->setObject(pStr, nType); + } + else + { + CCLog("registerEvent %s already exist", szEventName); + } + } + } + CCString* getLuaEvent(int nType) + { + if (m_pEventDictionary == NULL) + { + return NULL; + } + CCString *pfn = NULL; + pfn = m_pEventDictionary->objectForKey(nType); + return pfn; + + } + void excuteLuaTouchEvent(CCString* pLuafn, CCTouch *pTouch) + { + if (pLuafn) + { + CCLuaScriptModule::sharedLuaScriptModule()->executeTouch(pLuafn->m_sString.c_str(), pTouch); + } + } + + void excuteLuaTouchesEvent(CCString* pLuafn, CCSet *pTouches) + { + if (pLuafn) + { + CCLuaScriptModule::sharedLuaScriptModule()->executeTouchesEvent(pLuafn->m_sString.c_str(), pTouches); + } + } + CCTouchDelegate(){m_pEventDictionary = NULL;} + ~CCTouchDelegate() + { + if (m_pEventDictionary) + { + delete m_pEventDictionary; + m_pEventDictionary = NULL; + } + + } +#endif }; /** @brief diff --git a/cocos2dx/include/selector_protocol.h b/cocos2dx/include/selector_protocol.h index 9ddfb893ca..47be68d98b 100644 --- a/cocos2dx/include/selector_protocol.h +++ b/cocos2dx/include/selector_protocol.h @@ -27,16 +27,74 @@ THE SOFTWARE. #include "ccTypes.h" #include "CCObject.h" +#include + +#ifdef ENABLE_LUA +#include "../lua_support/CCLuaSrcipt.h" +#endif + namespace cocos2d { class CCNode; class CCEvent; +#ifdef ENABLE_LUA +enum ccScriptFuncType +{ + ccSEL_Update, + ccSEL_Tick, + ccSEL_CallFunc, + ccSEL_CallFuncN, + ccSEL_CallFuncND, + ccSEL_MenuHandler, + ccSEL_EventHandler, + ccSEL_Max, +}; +class CC_DLL CCScriptSelector +{ +public: + std::string m_scriptFunc[ccSEL_Max]; + inline bool registerScriptSelector(const char* szType, const char* szSeletor) + { + if (szType == NULL || szSeletor == NULL || strlen(szType) == 0 || strlen(szSeletor) == 0) + { + CCLog("registerScriptSelector input parameter error"); + return false; + } + std::string strType[] ={"SEL_Update", "SEL_Tick", "SEL_CallFunc", "SEL_CallFuncN", \ + "SEL_CallFuncND", "SEL_CallFuncO", "SEL_MenuHandler", "SEL_EventHandler"}; + int nType = -1; + for (int i = 0; i < sizeof(strType); i++) + { + if (strcmp(strType[i].c_str(), szType) == 0) + { + nType = i; + break; + } + } + if (nType == -1) + { + CCLog("registerScriptSelector function type error"); + return false; + } + else + { + m_scriptFunc[nType] = szSeletor; + } + return true; + } +}; +#endif +#ifdef ENABLE_LUA +class CC_DLL SelectorProtocol:public CCScriptSelector +#else class CC_DLL SelectorProtocol +#endif { public: virtual void update(ccTime dt) {CC_UNUSED_PARAM(dt);}; virtual void tick(ccTime dt){CC_UNUSED_PARAM(dt);}; + SelectorProtocol(){}; virtual void callfunc(){}; virtual void callfunc(CCNode* pSender){CC_UNUSED_PARAM(pSender);}; virtual void callfunc(CCNode* pSender, void* pData){CC_UNUSED_PARAM(pSender);CC_UNUSED_PARAM(pData);}; @@ -71,6 +129,101 @@ typedef void (SelectorProtocol::*SEL_EventHandler)(CCEvent*); #define callfuncO_selector(_SELECTOR) (SEL_CallFuncO)(&_SELECTOR) #define menu_selector(_SELECTOR) (SEL_MenuHandler)(&_SELECTOR) #define event_selector(_SELECTOR) (SEL_EventHandler)(&_SELECTOR) + + +inline void schedule_SCHEDULE(SelectorProtocol* pSel,SEL_SCHEDULE pfn, ccTime cc, std::string & strluafnc) +{ + if (pSel && pfn) + { + (pSel->*pfn)(cc); + } + else + { +#ifdef ENABLE_LUA + CCLuaScriptModule::sharedLuaScriptModule()->executeSchedule(strluafnc, cc); +#endif + + } +} + +inline void schedule_CallFunc(SelectorProtocol* pSel,SEL_CallFunc pfn, std::string & strluafnc) +{ + if (pSel && pfn) + { + (pSel->*pfn)(); + } + else + { +#ifdef ENABLE_LUA + CCLuaScriptModule::sharedLuaScriptModule()->executeCallFunc(strluafnc); +#endif + + } +} +inline void schedule_CallFuncN(SelectorProtocol* pSel,SEL_CallFuncN pfn, CCNode* pNode, std::string & strluafnc) +{ + if (pSel && pfn) + { + (pSel->*pfn)(pNode); + } + else + { +#ifdef ENABLE_LUA + CCLuaScriptModule::sharedLuaScriptModule()->executeCallFuncN(strluafnc, pNode); +#endif + } +} + +inline void schedule_CallFuncND(SelectorProtocol* pSel,SEL_CallFuncND pfn, CCNode* pNode, void* pdata, std::string & strluafnc) +{ + if (pSel && pfn) + { + (pSel->*pfn)(pNode, pdata); + } + else + { +#ifdef ENABLE_LUA + CCLuaScriptModule::sharedLuaScriptModule()->executeCallFuncND(strluafnc, pNode, pdata); +#endif + } +} + +inline void schedule_MenuHandler(SelectorProtocol* pSel,SEL_MenuHandler pfn, CCObject* pobj, std::string & strluafnc) +{ + if (pSel && pfn) + { + (pSel->*pfn)(pobj); + } + else + { +#ifdef ENABLE_LUA + CCLuaScriptModule::sharedLuaScriptModule()->executeMenuHandler(strluafnc.c_str(), pobj); +#endif + } +} +inline void schedule_CallFuncO(SelectorProtocol* pSel,SEL_MenuHandler pfn, CCObject* pobj, std::string & strluafnc) +{ + schedule_MenuHandler(pSel, pfn, pobj, strluafnc); +} + + +inline void schedule_EventHandler(SelectorProtocol* pSel,SEL_EventHandler pfn, CCEvent* pEvent, std::string & strluafnc) +{ + if (pSel && pfn) + { + (pSel->*pfn)(pEvent); + } + else + { +#ifdef ENABLE_LUA + CCLuaScriptModule::sharedLuaScriptModule()->executeEventHandler(strluafnc, pEvent); +#endif + + } +} + + + }//namespace cocos2d #endif // __COCOA_SELECTOR_PROTOCOL_H__ diff --git a/cocos2dx/layers_scenes_transitions_nodes/CCLayer.cpp b/cocos2dx/layers_scenes_transitions_nodes/CCLayer.cpp index 33d25b35b7..3609f34264 100644 --- a/cocos2dx/layers_scenes_transitions_nodes/CCLayer.cpp +++ b/cocos2dx/layers_scenes_transitions_nodes/CCLayer.cpp @@ -604,6 +604,29 @@ CCMultiplexLayer * CCMultiplexLayer::layerWithLayers(CCLayer * layer, ...) return NULL; } +#ifdef ENABLE_LUA +CCMultiplexLayer * CCMultiplexLayer::layerWithLayer(CCLayer* layer) +{ + CCMultiplexLayer * pMultiplexLayer = new CCMultiplexLayer(); + pMultiplexLayer->initWithLayer(layer); + pMultiplexLayer->autorelease(); + return pMultiplexLayer; +} +void CCMultiplexLayer::addLayer(CCLayer* layer) +{ + assert(m_pLayers); + m_pLayers->addObject(layer); +} + +bool CCMultiplexLayer::initWithLayer(CCLayer* layer) +{ + m_pLayers = new CCMutableArray(1); + m_pLayers->addObject(layer); + m_nEnabledLayer = 0; + this->addChild(layer); + return true; +} +#endif bool CCMultiplexLayer::initWithLayers(CCLayer *layer, va_list params) { m_pLayers = new CCMutableArray(5); diff --git a/cocos2dx/lua_support/CCLuaSrcipt.cpp b/cocos2dx/lua_support/CCLuaSrcipt.cpp new file mode 100644 index 0000000000..b3ea0bc5b1 --- /dev/null +++ b/cocos2dx/lua_support/CCLuaSrcipt.cpp @@ -0,0 +1,535 @@ +#include "CCLuaSrcipt.h" +#ifdef ENABLE_LUA + +extern "C" { +#include "lualib.h" +#include "lauxlib.h" +} + + +#include "tolua++.h" +#include "CCTouch.h" +#include "CCNode.h" +#include "CCObject.h" +#include "LuaCocos2d.h" +namespace cocos2d +{ + +CCLuaScriptModule* CCLuaScriptModule::s_luaScriptModule = NULL; + +CCLuaScriptModule* CCLuaScriptModule::sharedLuaScriptModule(void) +{ + if (s_luaScriptModule == NULL) + { + s_luaScriptModule = new CCLuaScriptModule(); + } + return s_luaScriptModule; +} +void CCLuaScriptModule::purgeSharedLuaScriptModule() +{ + s_luaScriptModule->release(); + s_luaScriptModule = NULL; +} + +/************************************************************************* + Constructor (creates Lua state) +*************************************************************************/ +CCLuaScriptModule::CCLuaScriptModule() +{ + + d_ownsState = true; + d_state = lua_open(); + luaL_openlibs(d_state); + int nOpen = tolua_Cocos2d_open(d_state); + // init all standard libraries + /*luaopen_base(d_state); + luaopen_io(d_state); + luaopen_string(d_state); + luaopen_table(d_state); + luaopen_math(d_state); + */ + //luaopen_debug(d_state); +} + + +/************************************************************************* + Constructor (uses given Lua state) +*************************************************************************/ +CCLuaScriptModule::CCLuaScriptModule(lua_State* state) +{ + // just use the given state + d_ownsState = false; + d_state = state; +} + + +/************************************************************************* + Destructor +*************************************************************************/ +CCLuaScriptModule::~CCLuaScriptModule() +{ + if ( d_ownsState && d_state ) + { + lua_close( d_state ); + } + s_luaScriptModule = NULL; + +} + +/************************************************************************* + Execute script file +*************************************************************************/ +void CCLuaScriptModule::executeScriptFile(const std::string& filename) +{ + int nRet = luaL_dofile(d_state,filename.c_str()); + if (nRet != 0) + { + CCLog("executeScriptFile Error nRet = %d", nRet); + } +} + + +/************************************************************************* + Execute global script function +*************************************************************************/ +int CCLuaScriptModule::executeScriptGlobal(const std::string& function_name) +{ + // get the function from lua + lua_getglobal(d_state, function_name.c_str()); + // is it a function + if ( !lua_isfunction(d_state,-1) ) + { + CCLog("name does not represent a Lua function"); + lua_settop( d_state, 0 ); + return 0; + } + + // call it + int error = lua_pcall(d_state,0,1,0); + + // handle errors + if ( error ) + { + std::string msg = lua_tostring(d_state,-1); + lua_pop(d_state,1); + CCLog("%s", msg.c_str()); + lua_settop( d_state, 0 ); + return 0; + } + + // get return value + if ( !lua_isnumber(d_state,-1) ) + { + CCLog("return value is not a number %s", function_name.c_str()); + lua_settop( d_state, 0 ); + return 0; + } + + int ret = (int)lua_tonumber(d_state,-1); + lua_pop(d_state,1); + + // return it + return ret; + + +} + + +/************************************************************************* + Execute scripted event handler +*************************************************************************/ + + +bool CCLuaScriptModule::executeSchedule(const std::string& handler_name, ccTime cc) +{ + + if (handler_name.size() == 0) + { + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler: handler_name == NULL\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + + // get the function from lua + lua_getglobal(d_state, handler_name.c_str()); + + // is it a function + if ( !lua_isfunction(d_state,-1) ) + { + lua_settop( d_state, 0 ); + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name+"\n\n"+"name does not represent a Lua function"+"\n"; + CCLog("%s %d", msg.c_str(), __FILE__); + return false; + } + + // push EventArgs as the first parameter + //tolua_pushusertype(d_state,(void*)&cc,"dFloat"); + lua_pushfstring(d_state, "%f", cc); + + // call it + int error = lua_pcall(d_state,1,0,0); + + // handle errors + if ( error ) + { + std::string msg = lua_tostring(d_state,-1); + lua_pop(d_state,1); + lua_settop( d_state, 0 ); + std::string msgerror = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name+"\n\n"+msg+"\n"; + CCLog("%s %d", msgerror.c_str(), __FILE__); + return false; + } + // return it + return true; + + +} +bool CCLuaScriptModule::executeCallFunc(const std::string& handler_name) +{ + + if (handler_name.size() == 0) + { + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler:handler_name == NULL\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + lua_getglobal(d_state, handler_name.c_str()); + + // is it a function + if ( !lua_isfunction(d_state,-1) ) + { + lua_settop( d_state, 0 ); + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name + "name does not represent a Lua functio"+"\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + // push EventArgs as the first parameter + //tolua_pushusertype(d_state,(void*)&cc,"cocos2d::ccTime"); + // call it + int error = lua_pcall(d_state,0,0,0); + // handle errors + if ( error ) + { + std::string msg = lua_tostring(d_state,-1); + lua_pop(d_state,1); + lua_settop( d_state, 0 ); + std::string msgerror = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name + msg +"\n"; + CCLog("%s %d", msgerror.c_str(), __LINE__); + return false; + } + // return it + return true; + +} +bool CCLuaScriptModule::executeCallFuncN(const std::string& handler_name, CCNode* pNode) +{ + + if (handler_name.size() == 0) + { + std::string msg = "(executeCallFuncN) Unable to execute scripted event handler: handler_name == NULL\n"; + CCLog("%s %d ", msg.c_str(), __LINE__); + return false; + } + lua_getglobal(d_state, handler_name.c_str()); + + + // is it a function + if ( !lua_isfunction(d_state,-1) ) + { + lua_settop( d_state, 0 ); + std::string msg = "(executeCallFuncN) Unable to execute scripted event handler: "+handler_name +"name does not represent a Lua function"+"\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + // push EventArgs as the first parameter + tolua_pushusertype(d_state,(void*)pNode,"cocos2d::CCNode"); + // call it + int error = lua_pcall(d_state,1,0,0); + // handle errors + if ( error ) + { + std::string msg = lua_tostring(d_state,-1); + lua_pop(d_state,1); + lua_settop( d_state, 0 ); + std::string msgerror = "(executeCallFuncN) Unable to execute scripted event handler: "+handler_name +msg+"\n"; + CCLog("%s %d", msgerror.c_str(), __LINE__); + return false; + } + // return it + return true; + +} +bool CCLuaScriptModule::executeCallFuncND(const std::string& handler_name, CCNode* pNode, void*pData) +{ + + + if (handler_name.size() == 0) + { + std::string msg = "(executeCallFuncND) Unable to execute scripted event handler: handler_name == NULL\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + // get the function from lua + lua_getglobal(d_state, handler_name.c_str()); + + // is it a function + if ( !lua_isfunction(d_state,-1) ) + { + lua_settop( d_state, 0 ); + std::string msg = "(executeCallFuncND) Unable to execute scripted event handler: "+handler_name +"name does not represent a Lua function"+"\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + // push EventArgs as the first parameter + tolua_pushusertype(d_state,(void*)pNode,"cocos2d::CCNode"); + tolua_pushusertype(d_state,(void*)pData,"void*"); + // call it + int error = lua_pcall(d_state,2,0,0); + // handle errors + if ( error ) + { + std::string msg = lua_tostring(d_state,-1); + lua_pop(d_state,1); + lua_settop( d_state, 0 ); + std::string msgerror = "(executeCallFuncND) Unable to execute scripted event handler: "+handler_name +msg+"\n"; + CCLog("%s %d", msgerror.c_str(), __LINE__); + return false; + } + // return it + return true; + +} +bool CCLuaScriptModule::executeMenuHandler(const std::string& handler_name, CCObject* pobj) +{ + + if (handler_name.size() == 0) + { + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler: handler_name == NULL\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + // get the function from lua + lua_getglobal(d_state, handler_name.c_str()); + + // is it a function + if ( !lua_isfunction(d_state,-1) ) + { + lua_settop( d_state, 0 ); + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name + "name does not represent a Lua function"+"\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + // push EventArgs as the first parameter + tolua_pushusertype(d_state,(void*)pobj,"cocos2d::CCObject"); + // call it + int error = lua_pcall(d_state,1,0,0); + // handle errors + if ( error ) + { + std::string msg = lua_tostring(d_state,-1); + lua_pop(d_state,1); + std::string msgerror = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name +msg+"\n"; + CCLog("%s %d", msgerror.c_str(), __LINE__); + return false; + } + // return it + return true; + +} + +bool CCLuaScriptModule::executeTouchesEvent(const std::string& handler_name, CCSet *pobj) +{ + + if (handler_name.size() == 0) + { + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler: handler_name == null\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + // get the function from lua + lua_getglobal(d_state, handler_name.c_str()); + + // is it a function + if ( !lua_isfunction(d_state,-1) ) + { + lua_settop( d_state, 0 ); + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name+"name does not represent a Lua function"+"\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + // push EventArgs as the first parameter + tolua_pushusertype(d_state,(void*)pobj,"cocos2d::CCSet"); + // call it + int error = lua_pcall(d_state,1,0,0); + // handle errors + if ( error ) + { + std::string msg = lua_tostring(d_state,-1); + lua_pop(d_state,1); + lua_settop( d_state, 0 ); + std::string msgerror = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name+msg+"\n"; + CCLog("%s %d", msgerror.c_str(), __LINE__); + return false; + } + // return it + return true; +} + +bool CCLuaScriptModule::executeTouch(const std::string& handler_name, CCTouch *pobj) +{ + + if (handler_name.size() == 0) + { + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler: handler_name == null\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + // get the function from lua + lua_getglobal(d_state, handler_name.c_str()); + + // is it a function + if ( !lua_isfunction(d_state,-1) ) + { + lua_settop( d_state, 0 ); + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name+"\n\n"+"name does not represent a Lua function"+"\n"; + CCLog("%s ", msg.c_str()); + return false; + } + // push EventArgs as the first parameter + tolua_pushusertype(d_state,(void*)pobj,"cocos2d::CCTouch"); + // call it + int error = lua_pcall(d_state,1,0,0); + // handle errors + if ( error ) + { + std::string msg = lua_tostring(d_state,-1); + lua_pop(d_state,1); + std::string msgerror = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name+"\n\n"+msg+"\n"; + CCLog("%s ", msgerror.c_str()); + return false; + } + // return it + return true; + + +} +bool CCLuaScriptModule::executeEventHandler(const std::string& handler_name, CCEvent* pEvent) +{ + + if (handler_name.size() == 0) + { + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler: handler_name == NULL\n"; + CCLog("%s ", msg.c_str()); + return false; + } + // get the function from lua + lua_getglobal(d_state, handler_name.c_str()); + + // is it a function + if ( !lua_isfunction(d_state,-1) ) + { + lua_settop( d_state, 0 ); + std::string msg = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name+"\n\n"+"name does not represent a Lua function"+"\n"; + CCLog("%s ", msg.c_str()); + return false; + } + // push EventArgs as the first parameter + tolua_pushusertype(d_state,(void*)pEvent,"cocos2d::CCEvent"); + // call it + int error = lua_pcall(d_state,1,0,0); + // handle errors + if ( error ) + { + std::string msg = lua_tostring(d_state,-1); + lua_pop(d_state,1); + lua_settop( d_state, 0 ); + std::string msgerror = "(LuaScriptModule) Unable to execute scripted event handler: "+handler_name+"\n\n"+msg+"\n"; + CCLog("%s ", msgerror.c_str()); + return false; + } + // return it + return true; + +} + +bool CCLuaScriptModule::executeListItem(const std::string& handler_name, int index, CCObject* pobj) +{ + + if (handler_name.size() == 0) + { + std::string msg = "(CCLuaScriptModule) Unable to execute scripted event handler: handler_name == NULL\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + // get the function from lua + lua_getglobal(d_state, handler_name.c_str()); + + // is it a function + if ( !lua_isfunction(d_state,-1) ) + { + lua_settop( d_state, 0 ); + std::string msg = "(CCLuaScriptModule) Unable to execute scripted event handler: "+handler_name +"name does not represent a Lua function"+"\n"; + CCLog("%s %d", msg.c_str(), __LINE__); + return false; + } + // push EventArgs as the first parameter + lua_pushfstring(d_state, "%d", index); + tolua_pushusertype(d_state,(void*)pobj,"cocos2d::CCObject"); + // call it + int error = lua_pcall(d_state,2,0,0); + // handle errors + if ( error ) + { + std::string msg = lua_tostring(d_state,-1); + lua_pop(d_state,1); + lua_settop( d_state, 0 ); + std::string msgerror = "(CCLuaScriptModule) Unable to execute scripted event handler: "+handler_name +msg+"\n"; + CCLog("%s %d", msgerror.c_str(), __LINE__); + return false; + } + // return it + return true; + +} + +/************************************************************************* + Execute script code string +*************************************************************************/ +void CCLuaScriptModule::executeString(const std::string& str) +{ + // load code into lua and call it + int error = luaL_dostring(d_state, str.c_str()); + + // handle errors + if ( error ) + { + CCLog("executeString %d", error); + } + +} + + +/************************************************************************* + Create Lua bindings +*************************************************************************/ +void CCLuaScriptModule::createBindings(void) +{ + + //tolua_Cocos2d_open(d_state); +} + + +/************************************************************************* + Destroy Lua bindings +*************************************************************************/ +void CCLuaScriptModule::destroyBindings(void) +{ + + lua_pushnil(d_state); + lua_setglobal(d_state,"cocos2d"); +} + + +} // namespace CEGUI + +#endif //CC_ENABLE_LUA \ No newline at end of file diff --git a/cocos2dx/lua_support/CCLuaSrcipt.h b/cocos2dx/lua_support/CCLuaSrcipt.h new file mode 100644 index 0000000000..8e901750c2 --- /dev/null +++ b/cocos2dx/lua_support/CCLuaSrcipt.h @@ -0,0 +1,175 @@ +#ifndef _CCLUASRCIPT_H +#define _CCLUASRCIPT_H +#include "ccConfig.h" + +#ifdef ENABLE_LUA +#include "CCCommon.h" +#include "CCObject.h" +#include +#include "ccTypes.h" +// include Lua +extern "C" { +#include "lua.h" +} + + + +namespace cocos2d +{ + class CCEvent; + class CCNode; + class CCObject; + +class CC_DLL CCLuaScriptModule : public CCObject +{ +public: + /************************************************************************* + Construction and Destruction + *************************************************************************/ + /*! + \brief + Constructor for LuaScriptModule class which create a lua_State + */ + CCLuaScriptModule(); + + /*! + \brief + Constructor for LuaScriptModule class which takes a lua_State + + \param state + Pointer to the lua_State that the script module should attach to. + */ + CCLuaScriptModule(lua_State* state); + + + /*! + \brief + Destructor for LuaScriptModule class. + */ + virtual ~CCLuaScriptModule(); + + + /************************************************************************* + Script Execution Functions + *************************************************************************/ + /*! + \brief + Execute a script file. + + \param filename + String object holding the filename of the script file that is to be executed + + */ + void executeScriptFile(const std::string& filename); + + + /*! + \brief + Execute a scripted global function. The function should not take any parameters and should return an integer. + + \param function_name + String object holding the name of the function, in the global script environment, that + is to be executed. + + \return + The integer value returned from the script function. + */ + int executeScriptGlobal(const std::string& function_name); + + + /*! + \brief + Execute a scripted global 'event handler' function. The function should take some kind of EventArgs like parameter + that the concrete implementation of this function can create from the passed EventArgs based object. The function + should not return anything. + + \param handler_name + String object holding the name of the scripted handler function. + + \param e + EventArgs based object that should be passed, by any appropriate means, to the scripted function. + + \return + - true if the event was handled. + - false if the event was not handled. + */ + bool executeSchedule(const std::string& handler_name, ccTime cc); + bool executeCallFunc(const std::string& handler_name); + bool executeCallFuncN(const std::string& handler_name, CCNode* pNode); + bool executeCallFuncND(const std::string& handler_name, CCNode* pNode, void*pData); + bool executeMenuHandler(const std::string& handler_name, CCObject* pobj); + bool executeEventHandler(const std::string& handler_name, CCEvent* pEvent); + bool executeTouchesEvent(const std::string& handler_name, CCSet *pobj); + bool executeTouch(const std::string& handler_name, CCTouch *pobj); + bool executeListItem(const std::string& handler_name, int index, CCObject* pobj); + /*! + \brief + Execute script code contained in the given CEGUI::String object. + + \param str + String object holding the valid script code that should be executed. + + \return + Nothing. + */ + void executeString(const std::string& str); + + + /************************************************************************* + Bindings creation / destruction + *************************************************************************/ + /*! + \brief + Method called during system initialisation, prior to running any scripts via the ScriptModule, to enable the ScriptModule + to perform any operations required to complete initialisation or binding of the script language to the gui system objects. + + \return + Nothing. + */ + void createBindings(void); + + + /*! + \brief + Method called during system destruction, after all scripts have been run via the ScriptModule, to enable the ScriptModule + to perform any operations required to cleanup bindings of the script language to the gui system objects, as set-up in the + earlier createBindings call. + + \return + Nothing. + */ + void destroyBindings(void); + + + /************************************************************************* + Accessor type functions + *************************************************************************/ + /*! + \brief + Method used to get a pointer to the lua_State that the script module is attached to. + + \return + A pointer to the lua_State that the script module is attached to. + */ + lua_State* getLuaState(void) const {return d_state;} + + + static CCLuaScriptModule* sharedLuaScriptModule(void); + + static void purgeSharedLuaScriptModule(); + + +private: + static CCLuaScriptModule* s_luaScriptModule; + /************************************************************************* + Implementation Data + *************************************************************************/ + bool d_ownsState; //!< true when the attached lua_State was created by this script module + lua_State* d_state; //!< The lua_State that this script module uses. + +}; + +} // namespace cocos2d + +#endif //CC_ENABLE_LUA +#endif // end of guard _CCLUASRCIPT_H diff --git a/cocos2dx/lua_support/LuaCocos2d.cpp.REMOVED.git-id b/cocos2dx/lua_support/LuaCocos2d.cpp.REMOVED.git-id new file mode 100644 index 0000000000..6604b139db --- /dev/null +++ b/cocos2dx/lua_support/LuaCocos2d.cpp.REMOVED.git-id @@ -0,0 +1 @@ +4a88465b2e4f0be14a616912fe45fbe1f1ac169a \ No newline at end of file diff --git a/cocos2dx/lua_support/LuaCocos2d.h b/cocos2dx/lua_support/LuaCocos2d.h new file mode 100644 index 0000000000..cbd34ce386 --- /dev/null +++ b/cocos2dx/lua_support/LuaCocos2d.h @@ -0,0 +1,19 @@ +#ifndef LUACOCOS2D_H +#define LUACOCOS2D_H +#include "cocos2d.h" +#ifdef ENABLE_LUA +#include +#include "lua.h" +#include "CCKeypadDispatcher.h" +#include "CCRibbon.h" +#include "CCParallaxNode.h" +#include "CCAutoreleasePool.h" +#include "CCIMEDispatcher.h" +#include "CCMutableArray.h" +//#define TOLUA_RELEASE +#if defined(_WIN32) && defined(_DEBUG) +#pragma warning (disable:4800) +#endif +int tolua_Cocos2d_open(lua_State* tolua_S); +#endif +#endif//LUACOCOS2D_H \ No newline at end of file diff --git a/cocos2dx/menu_nodes/CCMenu.cpp b/cocos2dx/menu_nodes/CCMenu.cpp index 9fad677f38..2a4f890783 100644 --- a/cocos2dx/menu_nodes/CCMenu.cpp +++ b/cocos2dx/menu_nodes/CCMenu.cpp @@ -60,6 +60,14 @@ namespace cocos2d{ return NULL; } +#ifdef ENABLE_LUA + CCMenu* CCMenu::menuWithItem(CCMenuItem* item) + { + return menuWithItems(item, NULL); + } + +#endif + bool CCMenu::initWithItems(CCMenuItem* item, va_list args) { if (CCLayer::init()) diff --git a/cocos2dx/menu_nodes/CCMenuItem.cpp b/cocos2dx/menu_nodes/CCMenuItem.cpp index 704b18b38f..c7c1d63ed8 100644 --- a/cocos2dx/menu_nodes/CCMenuItem.cpp +++ b/cocos2dx/menu_nodes/CCMenuItem.cpp @@ -29,7 +29,9 @@ THE SOFTWARE. #include "CCSprite.h" #include "CCLabelAtlas.h" #include "CCLabelTTF.h" - +#ifdef ENABLE_LUA +#include "CCTouchDispatcher.h" +#endif #include namespace cocos2d{ @@ -64,6 +66,16 @@ namespace cocos2d{ m_bIsSelected = false; return true; } +#ifdef ENABLE_LUA + void CCMenuItem::registerMenuHandler(const char* fn) + { + if (fn && strlen(fn)) + { + //SelectorProtocol is not a child of CCObject Obj->autorelease function can not be use + m_strScriptFunc = fn; + } + } +#endif void CCMenuItem::selected() { m_bIsSelected = true; @@ -74,9 +86,18 @@ namespace cocos2d{ } void CCMenuItem::activate() { - if (m_bIsEnabled && m_pListener) + if (m_bIsEnabled) { - (m_pListener->*m_pfnSelector)(this); + if (m_pListener) + { + (m_pListener->*m_pfnSelector)(this); + } +#ifdef ENABLE_LUA + else if(m_strScriptFunc.size()) + { + schedule_MenuHandler(m_pListener, m_pfnSelector, this, m_strScriptFunc); + } +#endif } } void CCMenuItem::setIsEnabled(bool enabled) diff --git a/cocos2dx/platform/CCCommon.h b/cocos2dx/platform/CCCommon.h index ca698da41d..0f2ee185a9 100644 --- a/cocos2dx/platform/CCCommon.h +++ b/cocos2dx/platform/CCCommon.h @@ -37,6 +37,13 @@ static const int kMaxLogLen = 255; */ void CC_DLL CCLog(const char * pszFormat, ...); +#ifdef ENABLE_LUA +inline void CC_DLL CCLuaLog(const char * pszFormat) +{ + CCLog(pszFormat); +} +#endif + /** @brief Pop out a message box */ diff --git a/cocos2dx/proj.win32/cocos2d-win32.vcproj b/cocos2dx/proj.win32/cocos2d-win32.vcproj index bc34434024..8373c67b2c 100644 --- a/cocos2dx/proj.win32/cocos2d-win32.vcproj +++ b/cocos2dx/proj.win32/cocos2d-win32.vcproj @@ -42,8 +42,8 @@ + + + + + + + + + + diff --git a/cocos2dx/touch_dispatcher/CCTouchDispatcher.cpp b/cocos2dx/touch_dispatcher/CCTouchDispatcher.cpp index c26e28e125..8bdafff35a 100644 --- a/cocos2dx/touch_dispatcher/CCTouchDispatcher.cpp +++ b/cocos2dx/touch_dispatcher/CCTouchDispatcher.cpp @@ -279,7 +279,20 @@ void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int u bool bClaimed = false; if (uIndex == ccTouchBegan) { +#ifdef ENABLE_LUA + CCString*pLuaFn = pHandler->getDelegate()->getLuaEvent(ccTouchBegan); + if (pLuaFn) + { + bClaimed = true; + pHandler->getDelegate()->excuteLuaTouchEvent(pLuaFn, pTouch); + } + else + { + bClaimed = pHandler->getDelegate()->ccTouchBegan(pTouch, pEvent); + } +#else bClaimed = pHandler->getDelegate()->ccTouchBegan(pTouch, pEvent); +#endif if (bClaimed) { pHandler->getClaimedTouches()->addObject(pTouch); @@ -289,7 +302,45 @@ void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int u { // moved ended cancelled bClaimed = true; +#ifdef ENABLE_LUA + CCString*pLuaFn = pHandler->getDelegate()->getLuaEvent(sHelper.m_type); + switch (sHelper.m_type) + { + case ccTouchMoved: + if (pLuaFn) + { + pHandler->getDelegate()->excuteLuaTouchEvent(pLuaFn, pTouch); + } + else + { + pHandler->getDelegate()->ccTouchMoved(pTouch, pEvent); + } + break; + case ccTouchEnded: + if (pLuaFn) + { + pHandler->getDelegate()->excuteLuaTouchEvent(pLuaFn, pTouch); + } + else + { + pHandler->getDelegate()->ccTouchEnded(pTouch, pEvent); + } + pHandler->getClaimedTouches()->removeObject(pTouch); + break; + case ccTouchCancelled: + if (pLuaFn) + { + pHandler->getDelegate()->excuteLuaTouchEvent(pLuaFn, pTouch); + } + else + { + pHandler->getDelegate()->ccTouchCancelled(pTouch, pEvent); + } + pHandler->getClaimedTouches()->removeObject(pTouch); + break; + } +#else switch (sHelper.m_type) { case ccTouchMoved: @@ -304,6 +355,7 @@ void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int u pHandler->getClaimedTouches()->removeObject(pTouch); break; } +#endif } if (bClaimed && pHandler->isSwallowsTouches()) @@ -334,7 +386,34 @@ void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int u { break; } +#ifdef ENABLE_LUA + CCString*pLuaTouchesfn = pHandler->getDelegate()->getLuaEvent(sHelper.m_type); + if (pLuaTouchesfn) + { + pHandler->getDelegate()->excuteLuaTouchesEvent(pLuaTouchesfn, pMutableTouches); + } + else + { + switch (sHelper.m_type) + { + case ccTouchBegan: + pHandler->getDelegate()->ccTouchesBegan(pMutableTouches, pEvent); + break; + case ccTouchMoved: + pHandler->getDelegate()->ccTouchesMoved(pMutableTouches, pEvent); + break; + case ccTouchEnded: + pHandler->getDelegate()->ccTouchesEnded(pMutableTouches, pEvent); + break; + case ccTouchCancelled: + pHandler->getDelegate()->ccTouchesCancelled(pMutableTouches, pEvent); + break; + } + + } + +#else switch (sHelper.m_type) { case ccTouchBegan: @@ -350,6 +429,7 @@ void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int u pHandler->getDelegate()->ccTouchesCancelled(pMutableTouches, pEvent); break; } +#endif } } diff --git a/extensions/NdControls/ControlDefine.h b/extensions/NdControls/ControlDefine.h new file mode 100644 index 0000000000..9f5d78fd75 --- /dev/null +++ b/extensions/NdControls/ControlDefine.h @@ -0,0 +1,43 @@ +#ifndef _CONTROL_DEFINE_H_ +#define _CONTROL_DEFINE_H_ + +namespace NdCxControl +{ + +typedef enum +{ + PARENT_CENTER, + VERTICAL_TOP, + VERTICAL_BOTTOM, + HORIZONTAL_LEFT, + HORIZONTAL_RIGHT, + ABS_WITH_PIXEL, + ABS_WITH_PERCENT, + REF_PREV_X_INC, + REF_PREV_X_DEC, + REF_PREV_Y_INC, + REF_PREV_Y_DEC, + REL_FLOW +} LAYOUT_TYPE; + +typedef struct +{ + LAYOUT_TYPE t; + union + { + float pixel_val; + float percent_val; + } val; +} LayoutParamVal; + +typedef struct +{ + LayoutParamVal val_x; + LayoutParamVal val_y; + float padding; + bool wrap; +} LayoutParam; + +} + +#endif \ No newline at end of file diff --git a/extensions/NdControls/NdCxList.cpp b/extensions/NdControls/NdCxList.cpp new file mode 100644 index 0000000000..101cc3d4d9 --- /dev/null +++ b/extensions/NdControls/NdCxList.cpp @@ -0,0 +1,513 @@ +#include "../effects/CCGrid.h" +#include "NdCxList.h" + +namespace NdCxControl +{ + #define FLOAT_EQUAL(x,y) (fabs((x)-(y)) < 0.0001f) + + NdCxList::NdCxList(float row_height, ccColor4B bg_color, CCSize size) + : sel_item_(NULL) + , row_height_(row_height) + , old_y_(0.f) + , min_y_(0.f) + , max_y_(0.f) + , touch_began_y_(0.f) + , touch_ended_y_(0.f) + , snap_flag_(false) + , list_state_(LS_WAITING) + , item_click_listener_(NULL) + { + if (size.width <= 0 || size.height <= 0) + { + size = CCDirector::sharedDirector()->getWinSize(); + } + + initWithColorWidthHeight(bg_color, size.width, size.height); + + inner_panel_ = CCLayer::node(); + inner_panel_->setPosition(CCPointZero); + inner_panel_->setContentSize(size); + CCLayerColor::addChild(inner_panel_); + + line_color_ = ccc3(0xBD, 0xBD, 0xBD); + sel_item_end_color_ = ccc3(0, 0xFF, 0xFF); + sel_item_start_color_ = ccc3(0xFF, 0xFF, 0); + } + + NdCxList::~NdCxList(void) + { + inner_panel_->removeAllChildrenWithCleanup(true); + } + + int NdCxList::addChild(NdCxListItem *item, bool scroll_to_view) + { + inner_panel_->addChild(item); + item->release(); + + CCArray *children = inner_panel_->getChildren(); + int item_count = children->count(); + if (1 == item_count) + { + item->setDrawTopLine(true); + } + + CCSize panel_size = inner_panel_->getContentSize(); + + item->setLineColor(line_color_); + item->setSelectedColor(sel_item_start_color_, sel_item_end_color_); + item->initWithWidthHeight(panel_size.width, row_height_); + item->requestLayout(); + + // ¼ÆËãλÖã¬itemµÄ¸ß¶È¿ÉÄÜÔÚµ÷ÓÃrequestLayoutºóÓÐËù±ä»¯ + float item_y_pos = 0.f; + CCSize item_size = item->getContentSize(); + if (item_count > 1) + { + CCNode *last_child = (CCNode *)children->objectAtIndex(item_count - 2); + item_y_pos = last_child->getPosition().y - item_size.height; + } + else + { + item_y_pos = panel_size.height - item_size.height; + } + + item->setPosition(CCPointMake(0, item_y_pos)); + + float total_height = 0.f; + for (int i = 0; i < (int)children->count(); ++i) + { + total_height += ((CCNode *)children->objectAtIndex(i))->getContentSize().height; + } + + if (total_height > panel_size.height) + { + max_y_ = total_height - panel_size.height; + } + else + { + max_y_ = 0; + } + + int rst = children->count() - 1; + if (scroll_to_view && (rst + 1) * row_height_ > panel_size.height) + { + doFitPos(max_y_); + } + + return rst; + } + + NdCxListItem *NdCxList::getChild(int row_index) + { + return (NdCxListItem *)inner_panel_->getChildren()->objectAtIndex(row_index); + } + + void NdCxList::clear(void) + { + inner_panel_->removeAllChildrenWithCleanup(true); + sel_item_ = NULL; + old_y_ = 0.f; + min_y_ = 0.f; + max_y_ = 0.f; + touch_began_y_ = 0.f; + touch_ended_y_ = 0.f; + snap_flag_ = false; + list_state_ = LS_WAITING; + inner_panel_->setPosition(CCPointZero); + } + + void NdCxList::onEnter(void) + { + setIsTouchEnabled(true); + CCLayerColor::onEnter(); + } + + void NdCxList::onExit(void) + { + setIsTouchEnabled(false); + CCLayerColor::onExit(); + } + + void NdCxList::registerWithTouchDispatcher() + { + CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, INT_MIN+9999, false); + } + + bool NdCxList::ccTouchBegan(CCTouch* touch, CCEvent* event) + { + if (!containsTouchLocation(touch) || !getIsVisible()) + { + return false; + } + + CCArray *children = inner_panel_->getChildren(); + if (LS_WAITING != list_state_ || !m_bIsVisible || !children) + { + return false; + } + + list_state_ = LS_TRACKINGTOUCH; + CCPoint touchPoint = touch->locationInView(touch->view()); + old_y_ = inner_panel_->getPosition().y; + touch_began_y_ = touch_ended_y_ = CCDirector::sharedDirector()->convertToGL(touchPoint).y; + + snap_flag_ = true; + + NdCxListItem *sel_item = itemForTouch(touch); + if (sel_item && sel_item != sel_item_) + { + sel_item->selected(); + if (sel_item_) + { + sel_item_->unselected(); + } + } + + sel_item_ = sel_item; + + //CCTime::gettimeofdayCocos2d(&touch_began_time_, NULL); + touch_began_time_ = clock(); + + return true; + } + + void NdCxList::doFitPos(float y_pos) + { + inner_panel_->stopAllActions(); + + CCMoveTo *move_to = new CCMoveTo(); + move_to->initWithDuration(0.66f, CCPointMake(0, y_pos)); + CCEaseExponentialOut *ease_action = new CCEaseExponentialOut(); + ease_action->initWithAction(move_to); + move_to->release(); + inner_panel_->runAction(ease_action); + ease_action->release(); + } + + void NdCxList::ccTouchEnded(CCTouch* touch, CCEvent* event) + { + if (LS_TRACKINGTOUCH != list_state_) + { + return; + } + + if (sel_item_) + { + if (FLOAT_EQUAL(touch_began_y_, touch_ended_y_)) + { + if (item_click_listener_) + { + item_click_listener_->onClick( + inner_panel_->getChildren()->indexOfObject(sel_item_), sel_item_); + } +#ifdef ENABLE_LUA + else if (m_scriptSeletor.size()) + { + CCLuaScriptModule::sharedLuaScriptModule()->executeListItem(m_scriptSeletor, + inner_panel_->getChildren()->indexOfObject(sel_item_), sel_item_); + } +#endif + + onItemClick(inner_panel_->getChildren()->indexOfObject(sel_item_), sel_item_); + } + } + + // Èç¹û³¬³ö·¶Î§£¬Ôò·´µ¯»ØÈ¥¡£ + CCPoint pos = inner_panel_->getPosition(); + if (FLOAT_EQUAL(min_y_, max_y_)) + { + if (!FLOAT_EQUAL(pos.y, 0.f)) + { + doFitPos(0.f); + } + } + else + { + if (pos.y < min_y_) + { + doFitPos(min_y_); + } + else if (pos.y > max_y_) + { + doFitPos(max_y_); + } + else + { + if (!FLOAT_EQUAL(touch_began_y_, touch_ended_y_)) + { + float acce_val = 0.f; + float fit_pos = inner_panel_->getPosition().y; + float abs_distance = fabs(touch_ended_y_ - touch_began_y_); + + /*cc_timeval end_time, sub_time; + CCTime::gettimeofdayCocos2d(&end_time, NULL); + CCTime::timersubCocos2d(&sub_time, &touch_began_time_, &end_time); + int time_consume = sub_time.tv_sec * 1000 + sub_time.tv_usec/1000;*/ + int time_consume = clock() - touch_began_time_; + if (time_consume < 400 && abs_distance > row_height_) + { + acce_val = (abs_distance / row_height_) * 3.f * row_height_; + } + else + { + acce_val = float((int)row_height_ / 3); + } + + // ÏòÏÂÍÏק + if (touch_began_y_ > touch_ended_y_) + { + fit_pos -= acce_val; + if (fit_pos < min_y_) + { + fit_pos = min_y_; + } + } + else + { + fit_pos += acce_val; + if (fit_pos > max_y_) + { + fit_pos = max_y_; + } + } + + doFitPos(fit_pos); + } + } + } + + list_state_ = LS_WAITING; + } + + void NdCxList::ccTouchCancelled(CCTouch *touch, CCEvent *event) + { + list_state_ = LS_WAITING; + } + + void NdCxList::ccTouchMoved(CCTouch* touch, CCEvent* event) + { + if (LS_TRACKINGTOUCH != list_state_) + { + return; + } + + CCPoint touchPoint = touch->locationInView(touch->view()); + touchPoint = CCDirector::sharedDirector()->convertToGL(touchPoint); + touch_ended_y_ = touchPoint.y; + + if (snap_flag_ && fabs(touch_ended_y_ - touch_began_y_) < 15.f) + { + return; + } + + snap_flag_ = false; + + inner_panel_->setPosition(CCPointMake(inner_panel_->getPosition().x, + old_y_ + (touch_ended_y_ - touch_began_y_))); + } + + void NdCxList::destroy(void) + { + release(); + } + + void NdCxList::keep(void) + { + retain(); + } + + NdCxListItem* NdCxList::itemForTouch(CCTouch * touch) + { + CCArray *children = inner_panel_->getChildren(); + if (!children || !children->count()) + { + return NULL; + } + + CCPoint touch_loc = touch->locationInView(touch->view()); + touch_loc = CCDirector::sharedDirector()->convertToGL(touch_loc); + CCPoint local_loc = inner_panel_->convertToNodeSpace(touch_loc); + + for (int i = 0, l = (int)children->count(); i != l; ++i) + { + CCNode *node = (CCNode *)children->objectAtIndex(i); + if (CCRect::CCRectContainsPoint(node->boundingBox(), local_loc)) + { + return (NdCxListItem*)node; + } + } + + return NULL; + } + + void NdCxList::selectChild(int row_index) + { + CCArray *children = inner_panel_->getChildren(); + if (!children || !children->count() || row_index < 0 || row_index >= (int)children->count()) + { + return; + } + + NdCxListItem *sel_item = (NdCxListItem *)children->objectAtIndex(row_index); + if (sel_item != sel_item_) + { + sel_item->selected(); + + if (sel_item_) + { + sel_item_->unselected(); + } + + sel_item_ = sel_item; + + CCSize panel_size = inner_panel_->getContentSize(); + CCArray *children = inner_panel_->getChildren(); + float inc_height = 0.f; + for (int i = 0; i <= row_index; ++i) + { + inc_height += ((CCNode *)children->objectAtIndex(i))->getContentSize().height; + } + + if (inc_height > panel_size.height) + { + doFitPos(inc_height - panel_size.height); + } + } + } + + NdCxListItem *NdCxList::getSelectedChild(void) + { + return sel_item_; + } + + void NdCxList::setLineColor(ccColor3B &color) + { + line_color_ = color; + } + + void NdCxList::setSelectedItemColor(ccColor3B &start_color, ccColor3B &end_color) + { + sel_item_start_color_ = start_color; + sel_item_end_color_ = end_color; + } + + int NdCxList::getChildCount(void) + { + CCArray *children = inner_panel_->getChildren(); + if (!children) + { + return 0; + } + else + { + return children->count(); + } + } + + void NdCxList::setRowHeight(float height) + { + row_height_ = height; + } + + float NdCxList::getRowHeight(void) + { + return row_height_; + } + + void NdCxList::registerItemClickListener(NdCxListItemClickListener *listener) + { + item_click_listener_ = listener; + } + + void NdCxList::unregisterItemClickListener(void) + { + item_click_listener_ = NULL; + +#ifdef ENABLE_LUA + m_scriptSeletor.clear(); +#endif + } +#ifdef ENABLE_LUA + void NdCxList::registerItemClickListener(const char* szSeletor) + { + if (szSeletor) + { + m_scriptSeletor = szSeletor; + } + else + { + CCLog("registerItemClickListener Error szSelector == null"); + } + } +#endif + + void NdCxList::visit(void) + { + // quick return if not visible + if (!m_bIsVisible) + { + return; + } + glPushMatrix(); + + /*if (m_pGrid && m_pGrid->isActive()) + { + m_pGrid->beforeDraw(); + this->transformAncestors(); + }*/ + + this->transform(); + + CCNode* pNode = NULL; + unsigned int i = 0; + + if(m_pChildren && m_pChildren->count() > 0) + { + // draw children zOrder < 0 + ccArray *arrayData = m_pChildren->data; + for( ; i < arrayData->num; i++ ) + { + pNode = (CCNode*) arrayData->arr[i]; + + if ( pNode && pNode->getZOrder() < 0 ) + { + pNode->visit(); + } + else + { + break; + } + } + } + + // self draw + this->draw(); + + // ×óϽÇÊÀ½ç×ø±ê + CCPoint world_pt = convertToWorldSpace(CCPointZero); + CCPoint ui_pt = CCDirector::sharedDirector()->convertToUI(world_pt); + CCPoint gl_pt = CCDirector::sharedDirector()->convertToGL(ui_pt); + + glEnable(GL_SCISSOR_TEST); + glScissor((GLsizei)gl_pt.x, (GLsizei)gl_pt.y, (GLsizei)m_tContentSize.width, (GLsizei)m_tContentSize.height); + + // draw children zOrder >= 0 + if (m_pChildren && m_pChildren->count() > 0) + { + ccArray *arrayData = m_pChildren->data; + for( ; i < arrayData->num; i++ ) + { + pNode = (CCNode*) arrayData->arr[i]; + if (pNode) + { + pNode->visit(); + } + } + } + + glDisable(GL_SCISSOR_TEST); + + glPopMatrix(); + } +} + diff --git a/extensions/NdControls/NdCxList.h b/extensions/NdControls/NdCxList.h new file mode 100644 index 0000000000..3665a0d74d --- /dev/null +++ b/extensions/NdControls/NdCxList.h @@ -0,0 +1,109 @@ +#ifndef __NDCX_LIST_H__ +#define __NDCX_LIST_H__ + +#include +#include "../platform/platform.h" +#include "NdCxListItem.h" +#include +using namespace cocos2d; +namespace NdCxControl +{ + class NdCxListItem; + typedef enum + { + LS_WAITING, + LS_TRACKINGTOUCH, + } LIST_STATE; + + struct NdCxListItemClickListener + { + virtual void onClick(int index, NdCxListItem *item) = 0; + }; + + class NdCxList : public CCLayerColor + { + public: + NdCxList(float row_height, + ccColor4B bg_color, + CCSize size); + virtual ~NdCxList(void); + + public: + int addChild(NdCxListItem *item, bool scroll_to_view); + NdCxListItem *getChild(int row_index); + void clear(void); + + void selectChild(int row_index); + + NdCxListItem *getSelectedChild(void); + + void setLineColor(ccColor3B &color); + void setSelectedItemColor(ccColor3B &start_color, ccColor3B &end_color); + int getChildCount(void); + + // ±ØÐëÔÚÌí¼Óitem֮ǰµ÷Óà + void setRowHeight(float height); + float getRowHeight(void); + + public: + virtual void onEnter(void); + virtual void onExit(void); + virtual void registerWithTouchDispatcher(void); + virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event); + virtual void ccTouchEnded(CCTouch* touch, CCEvent* event); + virtual void ccTouchCancelled(CCTouch *touch, CCEvent* event); + virtual void ccTouchMoved(CCTouch* touch, CCEvent* event); + virtual void destroy(void); + virtual void keep(void); + + virtual void registerItemClickListener(NdCxListItemClickListener *listener); + virtual void unregisterItemClickListener(void); +#ifdef ENABLE_LUA + virtual void registerItemClickListener(const char* szSeletor); +#endif + + protected: + virtual void onItemClick(int index, NdCxListItem *item) {} + virtual void visit(void); + + private: + NdCxListItem *itemForTouch(CCTouch * touch); + void doLayout(void); + void doFitPos(float y_pos); + + CCRect rect(void) + { + CCSize s = getContentSize(); + return CCRectMake(-s.width / 2, -s.height / 2, s.width, s.height); + } + + bool containsTouchLocation(CCTouch* touch) + { + return CCRect::CCRectContainsPoint(rect(), convertTouchToNodeSpaceAR(touch)); + } + + private: + NdCxListItem *sel_item_; + float row_height_; + LIST_STATE list_state_; + CCLayer *inner_panel_; + float touch_began_y_; + float touch_ended_y_; + float old_y_; + float min_y_; + float max_y_; + bool snap_flag_; + //cc_timeval touch_began_time_; + clock_t touch_began_time_; + ccColor3B line_color_; + ccColor3B sel_item_start_color_; + ccColor3B sel_item_end_color_; + + NdCxListItemClickListener *item_click_listener_; +#ifdef ENABLE_LUA + std::string m_scriptSeletor; +#endif + }; +} + +#endif \ No newline at end of file diff --git a/extensions/NdControls/NdCxListItem.cpp b/extensions/NdControls/NdCxListItem.cpp new file mode 100644 index 0000000000..48793b817a --- /dev/null +++ b/extensions/NdControls/NdCxListItem.cpp @@ -0,0 +1,363 @@ + +#include "NdCxListItem.h" + +namespace NdCxControl +{ + NdCxListItem::NdCxListItem(void) + : selected_(false) + , draw_top_line_(false) + , draw_bottom_line_(true) + , horizontal_margin_(10.f) + , vertical_margin_(10.f) + { + } + + NdCxListItem::~NdCxListItem(void) + { + } + + void NdCxListItem::updateColor(void) + { + const unsigned int l = sizeof(m_pSquareColors) / sizeof(m_pSquareColors[0]); + + if (selected_) + { + ccColor3B color = sel_item_start_color_; + const unsigned int half = l / 2; + for (unsigned int i=0; i < l; ++i) + { + if (i >= half) + { + color = sel_item_end_color_; + } + + if (i % 4 == 0) + m_pSquareColors[i] = color.r; + else if (i % 4 == 1) + m_pSquareColors[i] = color.g; + else if (i % 4 ==2) + m_pSquareColors[i] = color.b; + else + m_pSquareColors[i] = m_cOpacity; + } + } + else + { + for( unsigned int i=0; i < 4; i++ ) + { + m_pSquareColors[i * 4] = m_tColor.r; + m_pSquareColors[i * 4 + 1] = m_tColor.g; + m_pSquareColors[i * 4 + 2] = m_tColor.b; + m_pSquareColors[i * 4 + 3] = m_cOpacity; + } + } + } + + void NdCxListItem::draw(void) + { + updateColor(); + + CCSize size = getContentSize(); + if (selected_) + { + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisable(GL_TEXTURE_2D); + glShadeModel(GL_SMOOTH); + + glVertexPointer(2, GL_FLOAT, 0, m_pSquareVertices); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, m_pSquareColors); + + bool newBlend = false; + if( m_tBlendFunc.src != CC_BLEND_SRC || m_tBlendFunc.dst != CC_BLEND_DST ) { + newBlend = true; + glBlendFunc(m_tBlendFunc.src, m_tBlendFunc.dst); + } + else if( m_cOpacity != 255 ) { + newBlend = true; + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + if( newBlend ) + glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); + + // restore default GL state + glShadeModel(GL_FLAT); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnable(GL_TEXTURE_2D); + } + else + { + CCLayerColor::draw(); + } + + glDisable(GL_LINE_SMOOTH); + + if (draw_top_line_) + { + glLineWidth(1.0f); + glColor4ub(line_color_.r, line_color_.g, line_color_.b, 0xFF); + ccDrawLine(CCPointMake(0, size.height-0.5f), CCPointMake(size.width, size.height-0.5f)); + } + + if (draw_bottom_line_) + { + glLineWidth(1.0f); + glColor4ub(line_color_.r, line_color_.g, line_color_.b, 0xFF); + ccDrawLine(CCPointMake(0, 0.5f), CCPointMake(size.width, 0.5f)); + } + } + + CCRect NdCxListItem::rect(void) + { + return CCRectMake( m_tPosition.x - m_tContentSize.width * m_tAnchorPoint.x, + m_tPosition.y - m_tContentSize.height * m_tAnchorPoint.y, + m_tContentSize.width, m_tContentSize.height); + } + + void NdCxListItem::selected(void) + { + selected_ = true; + } + + void NdCxListItem::unselected(void) + { + selected_ = false; + } + + void NdCxListItem::setItemColor(const ccColor3B &color) + { + setColor(color); + } + + void NdCxListItem::setMargin(CCSize margin) + { + horizontal_margin_ = margin.width; + vertical_margin_ = margin.height; + } + + CCSize NdCxListItem::getMargin(void) + { + return CCSizeMake(horizontal_margin_, vertical_margin_); + } + + void NdCxListItem::addChild(NdCxListItemChild *child, const LayoutParam &layout) + { + addChild(child, layout, 0); + } + + void NdCxListItem::addChild(NdCxListItemChild *child, const LayoutParam &layout, int tag) + { + layout_info_.insert(std::make_pair(child, layout)); + child->setIsRelativeAnchorPoint(false); + CCLayerColor::addChild(child, 0, tag); + child->release(); + } + + NdCxListItemChild *NdCxListItem::getChildByTag(int tag) + { + return (NdCxListItemChild *)CCLayerColor::getChildByTag(tag); + } + + void NdCxListItem::requestLayout(void) + { + if (m_pChildren && m_pChildren->count() > 0) + { + CCPoint child_pos; + CCSize size = getContentSize(); + CCPoint curr_pos; + CCPoint prev_pos; + float vertical_height = size.height; + bool height_changed = false; + + for (int i = 0, l = m_pChildren->count(); i < l; ++i) + { + CCNode *it = (CCNode *)m_pChildren->objectAtIndex(i); + if (!(it)) + { + break; + } + + CCSize child_size = (*(it)).getContentSize(); + child_size.width *= (*(it)).getScaleX(); + child_size.height *= (*(it)).getScaleY(); + + std::map::iterator pos = layout_info_.find(it); + CCAssert(layout_info_.end() != pos, "!!"); + LayoutParam *lp = &pos->second; + switch ((*lp).val_x.t) + { + case PARENT_CENTER: + child_pos.x = (size.width - child_size.width) / 2; + break; + case HORIZONTAL_LEFT: + child_pos.x = horizontal_margin_; + break; + case HORIZONTAL_RIGHT: + child_pos.x = size.width - child_size.width - horizontal_margin_; + break; + case ABS_WITH_PIXEL: + child_pos.x = (float)(*lp).val_x.val.pixel_val; + break; + case ABS_WITH_PERCENT: + child_pos.x = horizontal_margin_ + (*lp).val_x.val.percent_val * (size.width - 2*horizontal_margin_); + break; + case REF_PREV_X_INC: + { + child_pos.x = prev_pos.x + (*lp).padding; + break; + } + case REF_PREV_X_DEC: + { + child_pos.x = prev_pos.x - (*lp).padding; + break; + } + case REL_FLOW: + child_pos.x = curr_pos.x + (*lp).padding; + break; + } + + if (!(*lp).wrap) + { + curr_pos.x = child_pos.x + child_size.width; + } + + switch ((*lp).val_y.t) + { + case PARENT_CENTER: + { + if (child_size.height > vertical_height - 2*vertical_margin_) + { + vertical_height += child_size.height - (vertical_height - 2*vertical_margin_); + height_changed = true; + } + + child_pos.y = (vertical_height - child_size.height)*0.5f; + + break; + } + case VERTICAL_TOP: + { + if (child_size.height > vertical_height - 2*vertical_margin_) + { + vertical_height += child_size.height - (vertical_height - 2*vertical_margin_); + height_changed = true; + } + + child_pos.y = vertical_height - (child_size.height + vertical_margin_); + + break; + } + case VERTICAL_BOTTOM: + { + if (child_size.height > vertical_height - 2*vertical_margin_) + { + vertical_height += child_size.height - (vertical_height - 2*vertical_margin_); + height_changed = true; + } + + child_pos.y = vertical_margin_; + + break; + } + case ABS_WITH_PIXEL: + { + child_pos.y = (float)(*lp).val_y.val.pixel_val; + if (child_pos.y + child_size.height > vertical_height - vertical_margin_) + { + vertical_height = child_pos.y + child_size.height + vertical_margin_; + height_changed = true; + } + + break; + } + case ABS_WITH_PERCENT: + { + child_pos.y = (*lp).val_y.val.percent_val * (vertical_height - 2*vertical_margin_); + if (child_pos.y + child_size.height > vertical_height - vertical_margin_) + { + vertical_height = child_pos.y + child_size.height + vertical_margin_; + height_changed = true; + } + + break; + } + case REF_PREV_Y_INC: + { + child_pos.y = prev_pos.y + (*lp).padding; + if (child_pos.y + child_size.height > + vertical_height - vertical_margin_) + { + vertical_height = child_pos.y + child_size.height + vertical_margin_; + height_changed = true; + } + + break; + } + case REF_PREV_Y_DEC: + { + child_pos.y = prev_pos.y - (child_size.height + (*lp).padding); + if (child_pos.y < vertical_margin_) + { + vertical_height += vertical_margin_-child_pos.y + vertical_margin_; + child_pos.y = vertical_margin_; + height_changed = true; + } + + break; + } + case REL_FLOW: + { + child_pos.y = curr_pos.y + (*lp).padding; + if (child_pos.y + child_size.height > vertical_height - vertical_margin_) + { + vertical_height = curr_pos.y + child_size.height + vertical_margin_; + height_changed = true; + } + + break; + } + + curr_pos.y = child_pos.y + child_size.height; + } + + prev_pos = child_pos; + + (*it).setPosition(child_pos); + } + + setContentSize(CCSizeMake(size.width, vertical_height)); + + if (height_changed) + { + requestLayout(); + } + } + } + + NdCxListItem *NdCxListItem::itemWithColor(const ccColor3B &color) + { + NdCxListItem *pRet = new NdCxListItem(); + pRet->setOpacity(255); + pRet->setColor(color); + return pRet; + } + + bool NdCxListItem::initWithWidthHeight(GLfloat width, GLfloat height) + { + ccColor3B color = getColor(); + ccColor4B cl4b = { color.r, color.g, color.b, getOpacity() }; + return CCLayerColor::initWithColorWidthHeight(cl4b, width, height); + } + + void NdCxListItem::setLineColor(const ccColor3B &color) + { + line_color_ = color; + } + + void NdCxListItem::setSelectedColor(const ccColor3B &start_color, const ccColor3B &end_color) + { + sel_item_start_color_ = start_color; + sel_item_end_color_ = end_color; + } +} \ No newline at end of file diff --git a/extensions/NdControls/NdCxListItem.h b/extensions/NdControls/NdCxListItem.h new file mode 100644 index 0000000000..4839716d99 --- /dev/null +++ b/extensions/NdControls/NdCxListItem.h @@ -0,0 +1,60 @@ +#ifndef __NDCX_LIST_ITEM_H_ +#define __NDCX_LIST_ITEM_H_ + +#include "ControlDefine.h" +#include "cocos2d.h" + +using namespace cocos2d; + +namespace NdCxControl { + +#define NdCxListItemChild CCNode + +class NdCxListItem : public CCLayerColor +{ + friend class NdCxList; +protected: + NdCxListItem(void); + virtual ~NdCxListItem(void); + +public: + static NdCxListItem *itemWithColor(const ccColor3B &color); + + CCRect rect(void); + void selected(void); + void unselected(void); + void setItemColor(const ccColor3B &color); + void setMargin(CCSize margin); + CCSize getMargin(void); + +public: + void addChild(NdCxListItemChild *child, const LayoutParam &layout); + void addChild(NdCxListItemChild *child, const LayoutParam &layout, int tag); + NdCxListItemChild *getChildByTag(int tag); + void setDrawTopLine(bool value) { draw_top_line_ = value; } + void setDrawBottomLine(bool value) { draw_bottom_line_ = value; } + +protected: + bool initWithWidthHeight(GLfloat width, GLfloat height); + void requestLayout(void); + void setLineColor(const ccColor3B &color); + void setSelectedColor(const ccColor3B &start_color, const ccColor3B &end_color); + void updateColor(void); + + virtual void draw(void); + +private: + bool selected_; + ccColor3B line_color_; + ccColor3B sel_item_start_color_; + ccColor3B sel_item_end_color_; + bool draw_top_line_; + bool draw_bottom_line_; + std::map layout_info_; + float horizontal_margin_; + float vertical_margin_; +}; + +} + +#endif \ No newline at end of file diff --git a/lua/jni/Android.mk b/lua/jni/Android.mk new file mode 100644 index 0000000000..6bde62fce4 --- /dev/null +++ b/lua/jni/Android.mk @@ -0,0 +1,62 @@ +# Copyright (C) 2009 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := lua +LOCAL_SRC_FILES :=../src/lapi.c \ + ../src/lauxlib.c \ + ../src/lbaselib.c \ + ../src/lcode.c \ + ../src/ldblib.c \ + ../src/ldebug.c \ + ../src/ldo.c \ + ../src/ldump.c \ + ../src/lfunc.c \ + ../src/lgc.c \ + ../src/linit.c \ + ../src/liolib.c \ + ../src/llex.c \ + ../src/lmathlib.c \ + ../src/lmem.c \ + ../src/loadlib.c \ + ../src/lobject.c \ + ../src/lopcodes.c \ + ../src/loslib.c \ + ../src/lparser.c \ + ../src/lstate.c \ + ../src/lstring.c \ + ../src/lstrlib.c \ + ../src/ltable.c \ + ../src/ltablib.c \ + ../src/ltm.c \ + ../src/lua.c \ + ../src/luac.c \ + ../src/lundump.c \ + ../src/lvm.c \ + ../src/lzio.c \ + ../src/print.c \ + ../tolua/tolua_event.c \ + ../tolua/tolua_is.c \ + ../tolua/tolua_map.c \ + ../tolua/tolua_push.c \ + ../tolua/tolua_to.c +LOCAL_C_INCLUDES := $(LOCAL_PATH)/ \ + $(LOCAL_PATH)/../src \ + $(LOCAL_PATH)/../tolua +#LOCAL_PRELINK_MODULE := false + +include $(BUILD_STATIC_LIBRARY) diff --git a/lua/jni/Application.mk b/lua/jni/Application.mk new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lua/lua.vcproj b/lua/lua.vcproj new file mode 100644 index 0000000000..b6fbed0230 --- /dev/null +++ b/lua/lua.vcproj @@ -0,0 +1,428 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lua/src/Makefile b/lua/src/Makefile new file mode 100644 index 0000000000..e4a3cd6108 --- /dev/null +++ b/lua/src/Makefile @@ -0,0 +1,182 @@ +# makefile for building Lua +# see ../INSTALL for installation instructions +# see ../Makefile and luaconf.h for further customization + +# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= + +# Your platform. See PLATS for possible values. +PLAT= none + +CC= gcc +CFLAGS= -O2 -Wall $(MYCFLAGS) +AR= ar rcu +RANLIB= ranlib +RM= rm -f +LIBS= -lm $(MYLIBS) + +MYCFLAGS= +MYLDFLAGS= +MYLIBS= + +# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= + +PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris + +LUA_A= liblua.a +CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ + lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ + lundump.o lvm.o lzio.o +LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ + lstrlib.o loadlib.o linit.o + +LUA_T= lua +LUA_O= lua.o + +LUAC_T= luac +LUAC_O= luac.o print.o + +ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O) +ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) +ALL_A= $(LUA_A) + +default: $(PLAT) + +all: $(ALL_T) + +o: $(ALL_O) + +a: $(ALL_A) + +$(LUA_A): $(CORE_O) $(LIB_O) + $(AR) $@ $? + $(RANLIB) $@ + +$(LUA_T): $(LUA_O) $(LUA_A) + $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) + +$(LUAC_T): $(LUAC_O) $(LUA_A) + $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) + +clean: + $(RM) $(ALL_T) $(ALL_O) + +depend: + @$(CC) $(CFLAGS) -MM l*.c print.c + +echo: + @echo "PLAT = $(PLAT)" + @echo "CC = $(CC)" + @echo "CFLAGS = $(CFLAGS)" + @echo "AR = $(AR)" + @echo "RANLIB = $(RANLIB)" + @echo "RM = $(RM)" + @echo "MYCFLAGS = $(MYCFLAGS)" + @echo "MYLDFLAGS = $(MYLDFLAGS)" + @echo "MYLIBS = $(MYLIBS)" + +# convenience targets for popular platforms + +none: + @echo "Please choose a platform:" + @echo " $(PLATS)" + +aix: + $(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" + +ansi: + $(MAKE) all MYCFLAGS=-DLUA_ANSI + +bsd: + $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" + +freebsd: + $(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline" + +generic: + $(MAKE) all MYCFLAGS= + +linux: + $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" + +macosx: + $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-lreadline" +# use this on Mac OS X 10.3- +# $(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX + +mingw: + $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ + "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ + "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe + $(MAKE) "LUAC_T=luac.exe" luac.exe + +posix: + $(MAKE) all MYCFLAGS=-DLUA_USE_POSIX + +solaris: + $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" + +# list targets that do not create files (but not all makes understand .PHONY) +.PHONY: all $(PLATS) default o a clean depend echo none + +# DO NOT DELETE + +lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \ + lstate.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h \ + lundump.h lvm.h +lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h +lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h +lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ + lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ + ltable.h +ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h +ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \ + llex.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ + lfunc.h lstring.h lgc.h ltable.h lvm.h +ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ + lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h lstring.h \ + ltable.h lundump.h lvm.h +ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ + lzio.h lmem.h lundump.h +lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ + lstate.h ltm.h lzio.h +lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ + lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h +linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h +liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h +llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \ + lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h +lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h +lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h ldo.h +loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h +lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \ + ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h +lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h +loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h +lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ + lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ + lfunc.h lstring.h lgc.h ltable.h +lstate.o: lstate.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h llex.h lstring.h ltable.h +lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ + ltm.h lzio.h lstring.h lgc.h +lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h +ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h +ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h +ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ + lmem.h lstring.h lgc.h ltable.h +lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h +luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \ + lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \ + lundump.h +lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \ + llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h +lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ + lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h +lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ + lzio.h +print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h lopcodes.h lundump.h + +# (end of Makefile) diff --git a/lua/src/lapi.c b/lua/src/lapi.c new file mode 100644 index 0000000000..5d5145d2eb --- /dev/null +++ b/lua/src/lapi.c @@ -0,0 +1,1087 @@ +/* +** $Id: lapi.c,v 2.55.1.5 2008/07/04 18:41:18 roberto Exp $ +** Lua API +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define lapi_c +#define LUA_CORE + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" + + + +const char lua_ident[] = + "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n" + "$Authors: " LUA_AUTHORS " $\n" + "$URL: www.lua.org $\n"; + + + +#define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) + +#define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject) + +#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} + + + +static TValue *index2adr (lua_State *L, int idx) { + if (idx > 0) { + TValue *o = L->base + (idx - 1); + api_check(L, idx <= L->ci->top - L->base); + if (o >= L->top) return cast(TValue *, luaO_nilobject); + else return o; + } + else if (idx > LUA_REGISTRYINDEX) { + api_check(L, idx != 0 && -idx <= L->top - L->base); + return L->top + idx; + } + else switch (idx) { /* pseudo-indices */ + case LUA_REGISTRYINDEX: return registry(L); + case LUA_ENVIRONINDEX: { + Closure *func = curr_func(L); + sethvalue(L, &L->env, func->c.env); + return &L->env; + } + case LUA_GLOBALSINDEX: return gt(L); + default: { + Closure *func = curr_func(L); + idx = LUA_GLOBALSINDEX - idx; + return (idx <= func->c.nupvalues) + ? &func->c.upvalue[idx-1] + : cast(TValue *, luaO_nilobject); + } + } +} + + +static Table *getcurrenv (lua_State *L) { + if (L->ci == L->base_ci) /* no enclosing function? */ + return hvalue(gt(L)); /* use global table as environment */ + else { + Closure *func = curr_func(L); + return func->c.env; + } +} + + +void luaA_pushobject (lua_State *L, const TValue *o) { + setobj2s(L, L->top, o); + api_incr_top(L); +} + + +LUA_API int lua_checkstack (lua_State *L, int size) { + int res = 1; + lua_lock(L); + if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK) + res = 0; /* stack overflow */ + else if (size > 0) { + luaD_checkstack(L, size); + if (L->ci->top < L->top + size) + L->ci->top = L->top + size; + } + lua_unlock(L); + return res; +} + + +LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { + int i; + if (from == to) return; + lua_lock(to); + api_checknelems(from, n); + api_check(from, G(from) == G(to)); + api_check(from, to->ci->top - to->top >= n); + from->top -= n; + for (i = 0; i < n; i++) { + setobj2s(to, to->top++, from->top + i); + } + lua_unlock(to); +} + + +LUA_API void lua_setlevel (lua_State *from, lua_State *to) { + to->nCcalls = from->nCcalls; +} + + +LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { + lua_CFunction old; + lua_lock(L); + old = G(L)->panic; + G(L)->panic = panicf; + lua_unlock(L); + return old; +} + + +LUA_API lua_State *lua_newthread (lua_State *L) { + lua_State *L1; + lua_lock(L); + luaC_checkGC(L); + L1 = luaE_newthread(L); + setthvalue(L, L->top, L1); + api_incr_top(L); + lua_unlock(L); + luai_userstatethread(L, L1); + return L1; +} + + + +/* +** basic stack manipulation +*/ + + +LUA_API int lua_gettop (lua_State *L) { + return cast_int(L->top - L->base); +} + + +LUA_API void lua_settop (lua_State *L, int idx) { + lua_lock(L); + if (idx >= 0) { + api_check(L, idx <= L->stack_last - L->base); + while (L->top < L->base + idx) + setnilvalue(L->top++); + L->top = L->base + idx; + } + else { + api_check(L, -(idx+1) <= (L->top - L->base)); + L->top += idx+1; /* `subtract' index (index is negative) */ + } + lua_unlock(L); +} + + +LUA_API void lua_remove (lua_State *L, int idx) { + StkId p; + lua_lock(L); + p = index2adr(L, idx); + api_checkvalidindex(L, p); + while (++p < L->top) setobjs2s(L, p-1, p); + L->top--; + lua_unlock(L); +} + + +LUA_API void lua_insert (lua_State *L, int idx) { + StkId p; + StkId q; + lua_lock(L); + p = index2adr(L, idx); + api_checkvalidindex(L, p); + for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); + setobjs2s(L, p, L->top); + lua_unlock(L); +} + + +LUA_API void lua_replace (lua_State *L, int idx) { + StkId o; + lua_lock(L); + /* explicit test for incompatible code */ + if (idx == LUA_ENVIRONINDEX && L->ci == L->base_ci) + luaG_runerror(L, "no calling environment"); + api_checknelems(L, 1); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + if (idx == LUA_ENVIRONINDEX) { + Closure *func = curr_func(L); + api_check(L, ttistable(L->top - 1)); + func->c.env = hvalue(L->top - 1); + luaC_barrier(L, func, L->top - 1); + } + else { + setobj(L, o, L->top - 1); + if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ + luaC_barrier(L, curr_func(L), L->top - 1); + } + L->top--; + lua_unlock(L); +} + + +LUA_API void lua_pushvalue (lua_State *L, int idx) { + lua_lock(L); + setobj2s(L, L->top, index2adr(L, idx)); + api_incr_top(L); + lua_unlock(L); +} + + + +/* +** access functions (stack -> C) +*/ + + +LUA_API int lua_type (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); +} + + +LUA_API const char *lua_typename (lua_State *L, int t) { + UNUSED(L); + return (t == LUA_TNONE) ? "no value" : luaT_typenames[t]; +} + + +LUA_API int lua_iscfunction (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + return iscfunction(o); +} + + +LUA_API int lua_isnumber (lua_State *L, int idx) { + TValue n; + const TValue *o = index2adr(L, idx); + return tonumber(o, &n); +} + + +LUA_API int lua_isstring (lua_State *L, int idx) { + int t = lua_type(L, idx); + return (t == LUA_TSTRING || t == LUA_TNUMBER); +} + + +LUA_API int lua_isuserdata (lua_State *L, int idx) { + const TValue *o = index2adr(L, idx); + return (ttisuserdata(o) || ttislightuserdata(o)); +} + + +LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { + StkId o1 = index2adr(L, index1); + StkId o2 = index2adr(L, index2); + return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 + : luaO_rawequalObj(o1, o2); +} + + +LUA_API int lua_equal (lua_State *L, int index1, int index2) { + StkId o1, o2; + int i; + lua_lock(L); /* may call tag method */ + o1 = index2adr(L, index1); + o2 = index2adr(L, index2); + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); + lua_unlock(L); + return i; +} + + +LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { + StkId o1, o2; + int i; + lua_lock(L); /* may call tag method */ + o1 = index2adr(L, index1); + o2 = index2adr(L, index2); + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 + : luaV_lessthan(L, o1, o2); + lua_unlock(L); + return i; +} + + + +LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { + TValue n; + const TValue *o = index2adr(L, idx); + if (tonumber(o, &n)) + return nvalue(o); + else + return 0; +} + + +LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { + TValue n; + const TValue *o = index2adr(L, idx); + if (tonumber(o, &n)) { + lua_Integer res; + lua_Number num = nvalue(o); + lua_number2integer(res, num); + return res; + } + else + return 0; +} + + +LUA_API int lua_toboolean (lua_State *L, int idx) { + const TValue *o = index2adr(L, idx); + return !l_isfalse(o); +} + + +LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { + StkId o = index2adr(L, idx); + if (!ttisstring(o)) { + lua_lock(L); /* `luaV_tostring' may create a new string */ + if (!luaV_tostring(L, o)) { /* conversion failed? */ + if (len != NULL) *len = 0; + lua_unlock(L); + return NULL; + } + luaC_checkGC(L); + o = index2adr(L, idx); /* previous call may reallocate the stack */ + lua_unlock(L); + } + if (len != NULL) *len = tsvalue(o)->len; + return svalue(o); +} + + +LUA_API size_t lua_objlen (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TSTRING: return tsvalue(o)->len; + case LUA_TUSERDATA: return uvalue(o)->len; + case LUA_TTABLE: return luaH_getn(hvalue(o)); + case LUA_TNUMBER: { + size_t l; + lua_lock(L); /* `luaV_tostring' may create a new string */ + l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); + lua_unlock(L); + return l; + } + default: return 0; + } +} + + +LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; +} + + +LUA_API void *lua_touserdata (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TUSERDATA: return (rawuvalue(o) + 1); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return NULL; + } +} + + +LUA_API lua_State *lua_tothread (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + return (!ttisthread(o)) ? NULL : thvalue(o); +} + + +LUA_API const void *lua_topointer (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TTABLE: return hvalue(o); + case LUA_TFUNCTION: return clvalue(o); + case LUA_TTHREAD: return thvalue(o); + case LUA_TUSERDATA: + case LUA_TLIGHTUSERDATA: + return lua_touserdata(L, idx); + default: return NULL; + } +} + + + +/* +** push functions (C -> stack) +*/ + + +LUA_API void lua_pushnil (lua_State *L) { + lua_lock(L); + setnilvalue(L->top); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { + lua_lock(L); + setnvalue(L->top, n); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { + lua_lock(L); + setnvalue(L->top, cast_num(n)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { + lua_lock(L); + luaC_checkGC(L); + setsvalue2s(L, L->top, luaS_newlstr(L, s, len)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushstring (lua_State *L, const char *s) { + if (s == NULL) + lua_pushnil(L); + else + lua_pushlstring(L, s, strlen(s)); +} + + +LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, + va_list argp) { + const char *ret; + lua_lock(L); + luaC_checkGC(L); + ret = luaO_pushvfstring(L, fmt, argp); + lua_unlock(L); + return ret; +} + + +LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { + const char *ret; + va_list argp; + lua_lock(L); + luaC_checkGC(L); + va_start(argp, fmt); + ret = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + lua_unlock(L); + return ret; +} + + +LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { + Closure *cl; + lua_lock(L); + luaC_checkGC(L); + api_checknelems(L, n); + cl = luaF_newCclosure(L, n, getcurrenv(L)); + cl->c.f = fn; + L->top -= n; + while (n--) + setobj2n(L, &cl->c.upvalue[n], L->top+n); + setclvalue(L, L->top, cl); + lua_assert(iswhite(obj2gco(cl))); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushboolean (lua_State *L, int b) { + lua_lock(L); + setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { + lua_lock(L); + setpvalue(L->top, p); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API int lua_pushthread (lua_State *L) { + lua_lock(L); + setthvalue(L, L->top, L); + api_incr_top(L); + lua_unlock(L); + return (G(L)->mainthread == L); +} + + + +/* +** get functions (Lua -> stack) +*/ + + +LUA_API void lua_gettable (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + luaV_gettable(L, t, L->top - 1, L->top - 1); + lua_unlock(L); +} + + +LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { + StkId t; + TValue key; + lua_lock(L); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, &key, luaS_new(L, k)); + luaV_gettable(L, t, &key, L->top); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_rawget (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2adr(L, idx); + api_check(L, ttistable(t)); + setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); + lua_unlock(L); +} + + +LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { + StkId o; + lua_lock(L); + o = index2adr(L, idx); + api_check(L, ttistable(o)); + setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { + lua_lock(L); + luaC_checkGC(L); + sethvalue(L, L->top, luaH_new(L, narray, nrec)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API int lua_getmetatable (lua_State *L, int objindex) { + const TValue *obj; + Table *mt = NULL; + int res; + lua_lock(L); + obj = index2adr(L, objindex); + switch (ttype(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; + default: + mt = G(L)->mt[ttype(obj)]; + break; + } + if (mt == NULL) + res = 0; + else { + sethvalue(L, L->top, mt); + api_incr_top(L); + res = 1; + } + lua_unlock(L); + return res; +} + + +LUA_API void lua_getfenv (lua_State *L, int idx) { + StkId o; + lua_lock(L); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + switch (ttype(o)) { + case LUA_TFUNCTION: + sethvalue(L, L->top, clvalue(o)->c.env); + break; + case LUA_TUSERDATA: + sethvalue(L, L->top, uvalue(o)->env); + break; + case LUA_TTHREAD: + setobj2s(L, L->top, gt(thvalue(o))); + break; + default: + setnilvalue(L->top); + break; + } + api_incr_top(L); + lua_unlock(L); +} + + +/* +** set functions (stack -> Lua) +*/ + + +LUA_API void lua_settable (lua_State *L, int idx) { + StkId t; + lua_lock(L); + api_checknelems(L, 2); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + luaV_settable(L, t, L->top - 2, L->top - 1); + L->top -= 2; /* pop index and value */ + lua_unlock(L); +} + + +LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + StkId t; + TValue key; + lua_lock(L); + api_checknelems(L, 1); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, &key, luaS_new(L, k)); + luaV_settable(L, t, &key, L->top - 1); + L->top--; /* pop value */ + lua_unlock(L); +} + + +LUA_API void lua_rawset (lua_State *L, int idx) { + StkId t; + lua_lock(L); + api_checknelems(L, 2); + t = index2adr(L, idx); + api_check(L, ttistable(t)); + setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); + luaC_barriert(L, hvalue(t), L->top-1); + L->top -= 2; + lua_unlock(L); +} + + +LUA_API void lua_rawseti (lua_State *L, int idx, int n) { + StkId o; + lua_lock(L); + api_checknelems(L, 1); + o = index2adr(L, idx); + api_check(L, ttistable(o)); + setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); + luaC_barriert(L, hvalue(o), L->top-1); + L->top--; + lua_unlock(L); +} + + +LUA_API int lua_setmetatable (lua_State *L, int objindex) { + TValue *obj; + Table *mt; + lua_lock(L); + api_checknelems(L, 1); + obj = index2adr(L, objindex); + api_checkvalidindex(L, obj); + if (ttisnil(L->top - 1)) + mt = NULL; + else { + api_check(L, ttistable(L->top - 1)); + mt = hvalue(L->top - 1); + } + switch (ttype(obj)) { + case LUA_TTABLE: { + hvalue(obj)->metatable = mt; + if (mt) + luaC_objbarriert(L, hvalue(obj), mt); + break; + } + case LUA_TUSERDATA: { + uvalue(obj)->metatable = mt; + if (mt) + luaC_objbarrier(L, rawuvalue(obj), mt); + break; + } + default: { + G(L)->mt[ttype(obj)] = mt; + break; + } + } + L->top--; + lua_unlock(L); + return 1; +} + + +LUA_API int lua_setfenv (lua_State *L, int idx) { + StkId o; + int res = 1; + lua_lock(L); + api_checknelems(L, 1); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + api_check(L, ttistable(L->top - 1)); + switch (ttype(o)) { + case LUA_TFUNCTION: + clvalue(o)->c.env = hvalue(L->top - 1); + break; + case LUA_TUSERDATA: + uvalue(o)->env = hvalue(L->top - 1); + break; + case LUA_TTHREAD: + sethvalue(L, gt(thvalue(o)), hvalue(L->top - 1)); + break; + default: + res = 0; + break; + } + if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); + L->top--; + lua_unlock(L); + return res; +} + + +/* +** `load' and `call' functions (run Lua code) +*/ + + +#define adjustresults(L,nres) \ + { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; } + + +#define checkresults(L,na,nr) \ + api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na))) + + +LUA_API void lua_call (lua_State *L, int nargs, int nresults) { + StkId func; + lua_lock(L); + api_checknelems(L, nargs+1); + checkresults(L, nargs, nresults); + func = L->top - (nargs+1); + luaD_call(L, func, nresults); + adjustresults(L, nresults); + lua_unlock(L); +} + + + +/* +** Execute a protected call. +*/ +struct CallS { /* data to `f_call' */ + StkId func; + int nresults; +}; + + +static void f_call (lua_State *L, void *ud) { + struct CallS *c = cast(struct CallS *, ud); + luaD_call(L, c->func, c->nresults); +} + + + +LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { + struct CallS c; + int status; + ptrdiff_t func; + lua_lock(L); + api_checknelems(L, nargs+1); + checkresults(L, nargs, nresults); + if (errfunc == 0) + func = 0; + else { + StkId o = index2adr(L, errfunc); + api_checkvalidindex(L, o); + func = savestack(L, o); + } + c.func = L->top - (nargs+1); /* function to be called */ + c.nresults = nresults; + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + adjustresults(L, nresults); + lua_unlock(L); + return status; +} + + +/* +** Execute a protected C call. +*/ +struct CCallS { /* data to `f_Ccall' */ + lua_CFunction func; + void *ud; +}; + + +static void f_Ccall (lua_State *L, void *ud) { + struct CCallS *c = cast(struct CCallS *, ud); + Closure *cl; + cl = luaF_newCclosure(L, 0, getcurrenv(L)); + cl->c.f = c->func; + setclvalue(L, L->top, cl); /* push function */ + api_incr_top(L); + setpvalue(L->top, c->ud); /* push only argument */ + api_incr_top(L); + luaD_call(L, L->top - 2, 0); +} + + +LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { + struct CCallS c; + int status; + lua_lock(L); + c.func = func; + c.ud = ud; + status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0); + lua_unlock(L); + return status; +} + + +LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, + const char *chunkname) { + ZIO z; + int status; + lua_lock(L); + if (!chunkname) chunkname = "?"; + luaZ_init(L, &z, reader, data); + status = luaD_protectedparser(L, &z, chunkname); + lua_unlock(L); + return status; +} + + +LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { + int status; + TValue *o; + lua_lock(L); + api_checknelems(L, 1); + o = L->top - 1; + if (isLfunction(o)) + status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0); + else + status = 1; + lua_unlock(L); + return status; +} + + +LUA_API int lua_status (lua_State *L) { + return L->status; +} + + +/* +** Garbage-collection function +*/ + +LUA_API int lua_gc (lua_State *L, int what, int data) { + int res = 0; + global_State *g; + lua_lock(L); + g = G(L); + switch (what) { + case LUA_GCSTOP: { + g->GCthreshold = MAX_LUMEM; + break; + } + case LUA_GCRESTART: { + g->GCthreshold = g->totalbytes; + break; + } + case LUA_GCCOLLECT: { + luaC_fullgc(L); + break; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + res = cast_int(g->totalbytes >> 10); + break; + } + case LUA_GCCOUNTB: { + res = cast_int(g->totalbytes & 0x3ff); + break; + } + case LUA_GCSTEP: { + lu_mem a = (cast(lu_mem, data) << 10); + if (a <= g->totalbytes) + g->GCthreshold = g->totalbytes - a; + else + g->GCthreshold = 0; + while (g->GCthreshold <= g->totalbytes) { + luaC_step(L); + if (g->gcstate == GCSpause) { /* end of cycle? */ + res = 1; /* signal it */ + break; + } + } + break; + } + case LUA_GCSETPAUSE: { + res = g->gcpause; + g->gcpause = data; + break; + } + case LUA_GCSETSTEPMUL: { + res = g->gcstepmul; + g->gcstepmul = data; + break; + } + default: res = -1; /* invalid option */ + } + lua_unlock(L); + return res; +} + + + +/* +** miscellaneous functions +*/ + + +LUA_API int lua_error (lua_State *L) { + lua_lock(L); + api_checknelems(L, 1); + luaG_errormsg(L); + lua_unlock(L); + return 0; /* to avoid warnings */ +} + + +LUA_API int lua_next (lua_State *L, int idx) { + StkId t; + int more; + lua_lock(L); + t = index2adr(L, idx); + api_check(L, ttistable(t)); + more = luaH_next(L, hvalue(t), L->top - 1); + if (more) { + api_incr_top(L); + } + else /* no more elements */ + L->top -= 1; /* remove key */ + lua_unlock(L); + return more; +} + + +LUA_API void lua_concat (lua_State *L, int n) { + lua_lock(L); + api_checknelems(L, n); + if (n >= 2) { + luaC_checkGC(L); + luaV_concat(L, n, cast_int(L->top - L->base) - 1); + L->top -= (n-1); + } + else if (n == 0) { /* push empty string */ + setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); + api_incr_top(L); + } + /* else n == 1; nothing to do */ + lua_unlock(L); +} + + +LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { + lua_Alloc f; + lua_lock(L); + if (ud) *ud = G(L)->ud; + f = G(L)->frealloc; + lua_unlock(L); + return f; +} + + +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { + lua_lock(L); + G(L)->ud = ud; + G(L)->frealloc = f; + lua_unlock(L); +} + + +LUA_API void *lua_newuserdata (lua_State *L, size_t size) { + Udata *u; + lua_lock(L); + luaC_checkGC(L); + u = luaS_newudata(L, size, getcurrenv(L)); + setuvalue(L, L->top, u); + api_incr_top(L); + lua_unlock(L); + return u + 1; +} + + + + +static const char *aux_upvalue (StkId fi, int n, TValue **val) { + Closure *f; + if (!ttisfunction(fi)) return NULL; + f = clvalue(fi); + if (f->c.isC) { + if (!(1 <= n && n <= f->c.nupvalues)) return NULL; + *val = &f->c.upvalue[n-1]; + return ""; + } + else { + Proto *p = f->l.p; + if (!(1 <= n && n <= p->sizeupvalues)) return NULL; + *val = f->l.upvals[n-1]->v; + return getstr(p->upvalues[n-1]); + } +} + + +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val; + lua_lock(L); + name = aux_upvalue(index2adr(L, funcindex), n, &val); + if (name) { + setobj2s(L, L->top, val); + api_incr_top(L); + } + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val; + StkId fi; + lua_lock(L); + fi = index2adr(L, funcindex); + api_checknelems(L, 1); + name = aux_upvalue(fi, n, &val); + if (name) { + L->top--; + setobj(L, val, L->top); + luaC_barrier(L, clvalue(fi), L->top); + } + lua_unlock(L); + return name; +} + diff --git a/lua/src/lapi.h b/lua/src/lapi.h new file mode 100644 index 0000000000..2c3fab244e --- /dev/null +++ b/lua/src/lapi.h @@ -0,0 +1,16 @@ +/* +** $Id: lapi.h,v 2.2.1.1 2007/12/27 13:02:25 roberto Exp $ +** Auxiliary functions from Lua API +** See Copyright Notice in lua.h +*/ + +#ifndef lapi_h +#define lapi_h + + +#include "lobject.h" + + +LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o); + +#endif diff --git a/lua/src/lauxlib.c b/lua/src/lauxlib.c new file mode 100644 index 0000000000..10f14e2c08 --- /dev/null +++ b/lua/src/lauxlib.c @@ -0,0 +1,652 @@ +/* +** $Id: lauxlib.c,v 1.159.1.3 2008/01/21 13:20:51 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include +#include +#include + + +/* This file uses only the official API of Lua. +** Any function declared here could be written as an application function. +*/ + +#define lauxlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" + + +#define FREELIST_REF 0 /* free list of references */ + + +/* convert a stack index to positive */ +#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ + lua_gettop(L) + (i) + 1) + + +/* +** {====================================================== +** Error-report functions +** ======================================================= +*/ + + +LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { + lua_Debug ar; + if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ + return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); + lua_getinfo(L, "n", &ar); + if (strcmp(ar.namewhat, "method") == 0) { + narg--; /* do not count `self' */ + if (narg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling " LUA_QS " on bad self (%s)", + ar.name, extramsg); + } + if (ar.name == NULL) + ar.name = "?"; + return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", + narg, ar.name, extramsg); +} + + +LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { + const char *msg = lua_pushfstring(L, "%s expected, got %s", + tname, luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); +} + + +static void tag_error (lua_State *L, int narg, int tag) { + luaL_typerror(L, narg, lua_typename(L, tag)); +} + + +LUALIB_API void luaL_where (lua_State *L, int level) { + lua_Debug ar; + if (lua_getstack(L, level, &ar)) { /* check function at level */ + lua_getinfo(L, "Sl", &ar); /* get info about it */ + if (ar.currentline > 0) { /* is there info? */ + lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); + return; + } + } + lua_pushliteral(L, ""); /* else, no information available... */ +} + + +LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + luaL_where(L, 1); + lua_pushvfstring(L, fmt, argp); + va_end(argp); + lua_concat(L, 2); + return lua_error(L); +} + +/* }====================================================== */ + + +LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, + const char *const lst[]) { + const char *name = (def) ? luaL_optstring(L, narg, def) : + luaL_checkstring(L, narg); + int i; + for (i=0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) + return i; + return luaL_argerror(L, narg, + lua_pushfstring(L, "invalid option " LUA_QS, name)); +} + + +LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ + if (!lua_isnil(L, -1)) /* name already in use? */ + return 0; /* leave previous value on top, but return 0 */ + lua_pop(L, 1); + lua_newtable(L); /* create metatable */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ + return 1; +} + + +LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ + if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + } + luaL_typerror(L, ud, tname); /* else error */ + return NULL; /* to avoid warnings */ +} + + +LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { + if (!lua_checkstack(L, space)) + luaL_error(L, "stack overflow (%s)", mes); +} + + +LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { + if (lua_type(L, narg) != t) + tag_error(L, narg, t); +} + + +LUALIB_API void luaL_checkany (lua_State *L, int narg) { + if (lua_type(L, narg) == LUA_TNONE) + luaL_argerror(L, narg, "value expected"); +} + + +LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { + const char *s = lua_tolstring(L, narg, len); + if (!s) tag_error(L, narg, LUA_TSTRING); + return s; +} + + +LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, + const char *def, size_t *len) { + if (lua_isnoneornil(L, narg)) { + if (len) + *len = (def ? strlen(def) : 0); + return def; + } + else return luaL_checklstring(L, narg, len); +} + + +LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { + lua_Number d = lua_tonumber(L, narg); + if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ + tag_error(L, narg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { + return luaL_opt(L, luaL_checknumber, narg, def); +} + + +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { + lua_Integer d = lua_tointeger(L, narg); + if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ + tag_error(L, narg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, + lua_Integer def) { + return luaL_opt(L, luaL_checkinteger, narg, def); +} + + +LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { + if (!lua_getmetatable(L, obj)) /* no metatable? */ + return 0; + lua_pushstring(L, event); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { + lua_pop(L, 2); /* remove metatable and metafield */ + return 0; + } + else { + lua_remove(L, -2); /* remove only metatable */ + return 1; + } +} + + +LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { + obj = abs_index(L, obj); + if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ + return 0; + lua_pushvalue(L, obj); + lua_call(L, 1, 1); + return 1; +} + + +LUALIB_API void (luaL_register) (lua_State *L, const char *libname, + const luaL_Reg *l) { + luaI_openlib(L, libname, l, 0); +} + + +static int libsize (const luaL_Reg *l) { + int size = 0; + for (; l->name; l++) size++; + return size; +} + + +LUALIB_API void luaI_openlib (lua_State *L, const char *libname, + const luaL_Reg *l, int nup) { + if (libname) { + int size = libsize(l); + /* check whether lib already exists */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); + lua_getfield(L, -1, libname); /* get _LOADED[libname] */ + if (!lua_istable(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) + luaL_error(L, "name conflict for module " LUA_QS, libname); + lua_pushvalue(L, -1); + lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ + } + lua_remove(L, -2); /* remove _LOADED table */ + lua_insert(L, -(nup+1)); /* move library table to below upvalues */ + } + for (; l->name; l++) { + int i; + for (i=0; ifunc, nup); + lua_setfield(L, -(nup+2), l->name); + } + lua_pop(L, nup); /* remove upvalues */ +} + + + +/* +** {====================================================== +** getn-setn: size for arrays +** ======================================================= +*/ + +#if defined(LUA_COMPAT_GETN) + +static int checkint (lua_State *L, int topop) { + int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; + lua_pop(L, topop); + return n; +} + + +static void getsizes (lua_State *L) { + lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); + if (lua_isnil(L, -1)) { /* no `size' table? */ + lua_pop(L, 1); /* remove nil */ + lua_newtable(L); /* create it */ + lua_pushvalue(L, -1); /* `size' will be its own metatable */ + lua_setmetatable(L, -2); + lua_pushliteral(L, "kv"); + lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); /* store in register */ + } +} + + +LUALIB_API void luaL_setn (lua_State *L, int t, int n) { + t = abs_index(L, t); + lua_pushliteral(L, "n"); + lua_rawget(L, t); + if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ + lua_pushliteral(L, "n"); /* use it */ + lua_pushinteger(L, n); + lua_rawset(L, t); + } + else { /* use `sizes' */ + getsizes(L); + lua_pushvalue(L, t); + lua_pushinteger(L, n); + lua_rawset(L, -3); /* sizes[t] = n */ + lua_pop(L, 1); /* remove `sizes' */ + } +} + + +LUALIB_API int luaL_getn (lua_State *L, int t) { + int n; + t = abs_index(L, t); + lua_pushliteral(L, "n"); /* try t.n */ + lua_rawget(L, t); + if ((n = checkint(L, 1)) >= 0) return n; + getsizes(L); /* else try sizes[t] */ + lua_pushvalue(L, t); + lua_rawget(L, -2); + if ((n = checkint(L, 2)) >= 0) return n; + return (int)lua_objlen(L, t); +} + +#endif + +/* }====================================================== */ + + + +LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, + const char *r) { + const char *wild; + size_t l = strlen(p); + luaL_Buffer b; + luaL_buffinit(L, &b); + while ((wild = strstr(s, p)) != NULL) { + luaL_addlstring(&b, s, wild - s); /* push prefix */ + luaL_addstring(&b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after `p' */ + } + luaL_addstring(&b, s); /* push last suffix */ + luaL_pushresult(&b); + return lua_tostring(L, -1); +} + + +LUALIB_API const char *luaL_findtable (lua_State *L, int idx, + const char *fname, int szhint) { + const char *e; + lua_pushvalue(L, idx); + do { + e = strchr(fname, '.'); + if (e == NULL) e = fname + strlen(fname); + lua_pushlstring(L, fname, e - fname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { /* no such field? */ + lua_pop(L, 1); /* remove this nil */ + lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ + lua_pushlstring(L, fname, e - fname); + lua_pushvalue(L, -2); + lua_settable(L, -4); /* set new table into field */ + } + else if (!lua_istable(L, -1)) { /* field has a non-table value? */ + lua_pop(L, 2); /* remove table and value */ + return fname; /* return problematic part of the name */ + } + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + } while (*e == '.'); + return NULL; +} + + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + + +#define bufflen(B) ((B)->p - (B)->buffer) +#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) + +#define LIMIT (LUA_MINSTACK/2) + + +static int emptybuffer (luaL_Buffer *B) { + size_t l = bufflen(B); + if (l == 0) return 0; /* put nothing on stack */ + else { + lua_pushlstring(B->L, B->buffer, l); + B->p = B->buffer; + B->lvl++; + return 1; + } +} + + +static void adjuststack (luaL_Buffer *B) { + if (B->lvl > 1) { + lua_State *L = B->L; + int toget = 1; /* number of levels to concat */ + size_t toplen = lua_strlen(L, -1); + do { + size_t l = lua_strlen(L, -(toget+1)); + if (B->lvl - toget + 1 >= LIMIT || toplen > l) { + toplen += l; + toget++; + } + else break; + } while (toget < B->lvl); + lua_concat(L, toget); + B->lvl = B->lvl - toget + 1; + } +} + + +LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { + if (emptybuffer(B)) + adjuststack(B); + return B->buffer; +} + + +LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { + while (l--) + luaL_addchar(B, *s++); +} + + +LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { + luaL_addlstring(B, s, strlen(s)); +} + + +LUALIB_API void luaL_pushresult (luaL_Buffer *B) { + emptybuffer(B); + lua_concat(B->L, B->lvl); + B->lvl = 1; +} + + +LUALIB_API void luaL_addvalue (luaL_Buffer *B) { + lua_State *L = B->L; + size_t vl; + const char *s = lua_tolstring(L, -1, &vl); + if (vl <= bufffree(B)) { /* fit into buffer? */ + memcpy(B->p, s, vl); /* put it there */ + B->p += vl; + lua_pop(L, 1); /* remove from stack */ + } + else { + if (emptybuffer(B)) + lua_insert(L, -2); /* put buffer before new value */ + B->lvl++; /* add new value into B stack */ + adjuststack(B); + } +} + + +LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { + B->L = L; + B->p = B->buffer; + B->lvl = 0; +} + +/* }====================================================== */ + + +LUALIB_API int luaL_ref (lua_State *L, int t) { + int ref; + t = abs_index(L, t); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* remove from stack */ + return LUA_REFNIL; /* `nil' has a unique fixed reference */ + } + lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ + ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ + lua_pop(L, 1); /* remove it from stack */ + if (ref != 0) { /* any free element? */ + lua_rawgeti(L, t, ref); /* remove it from list */ + lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ + } + else { /* no free elements */ + ref = (int)lua_objlen(L, t); + ref++; /* create new reference */ + } + lua_rawseti(L, t, ref); + return ref; +} + + +LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { + if (ref >= 0) { + t = abs_index(L, t); + lua_rawgeti(L, t, FREELIST_REF); + lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ + lua_pushinteger(L, ref); + lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ + } +} + + + +/* +** {====================================================== +** Load functions +** ======================================================= +*/ + +typedef struct LoadF { + int extraline; + FILE *f; + char buff[LUAL_BUFFERSIZE]; +} LoadF; + + +static const char *getF (lua_State *L, void *ud, size_t *size) { + LoadF *lf = (LoadF *)ud; + (void)L; + if (lf->extraline) { + lf->extraline = 0; + *size = 1; + return "\n"; + } + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); + return (*size > 0) ? lf->buff : NULL; +} + + +static int errfile (lua_State *L, const char *what, int fnameindex) { + const char *serr = strerror(errno); + const char *filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; +} + + +LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { + LoadF lf; + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + lf.extraline = 0; + if (filename == NULL) { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else { + lua_pushfstring(L, "@%s", filename); + lf.f = fopen(filename, "r"); + if (lf.f == NULL) return errfile(L, "open", fnameindex); + } + c = getc(lf.f); + if (c == '#') { /* Unix exec. file? */ + lf.extraline = 1; + while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ + if (c == '\n') c = getc(lf.f); + } + if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == NULL) return errfile(L, "reopen", fnameindex); + /* skip eventual `#!...' */ + while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; + lf.extraline = 0; + } + ungetc(c, lf.f); + status = lua_load(L, getF, &lf, lua_tostring(L, -1)); + readstatus = ferror(lf.f); + if (filename) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) { + lua_settop(L, fnameindex); /* ignore results from `lua_load' */ + return errfile(L, "read", fnameindex); + } + lua_remove(L, fnameindex); + return status; +} + + +typedef struct LoadS { + const char *s; + size_t size; +} LoadS; + + +static const char *getS (lua_State *L, void *ud, size_t *size) { + LoadS *ls = (LoadS *)ud; + (void)L; + if (ls->size == 0) return NULL; + *size = ls->size; + ls->size = 0; + return ls->s; +} + + +LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, + const char *name) { + LoadS ls; + ls.s = buff; + ls.size = size; + return lua_load(L, getS, &ls, name); +} + + +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) { + return luaL_loadbuffer(L, s, strlen(s), s); +} + + + +/* }====================================================== */ + + +static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; + (void)osize; + if (nsize == 0) { + free(ptr); + return NULL; + } + else + return realloc(ptr, nsize); +} + + +static int panic (lua_State *L) { + (void)L; /* to avoid warnings */ + fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); + return 0; +} + + +LUALIB_API lua_State *luaL_newstate (void) { + lua_State *L = lua_newstate(l_alloc, NULL); + if (L) lua_atpanic(L, &panic); + return L; +} + diff --git a/lua/src/lauxlib.h b/lua/src/lauxlib.h new file mode 100644 index 0000000000..34258235db --- /dev/null +++ b/lua/src/lauxlib.h @@ -0,0 +1,174 @@ +/* +** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lauxlib_h +#define lauxlib_h + + +#include +#include + +#include "lua.h" + + +#if defined(LUA_COMPAT_GETN) +LUALIB_API int (luaL_getn) (lua_State *L, int t); +LUALIB_API void (luaL_setn) (lua_State *L, int t, int n); +#else +#define luaL_getn(L,i) ((int)lua_objlen(L, i)) +#define luaL_setn(L,i,j) ((void)0) /* no op! */ +#endif + +#if defined(LUA_COMPAT_OPENLIB) +#define luaI_openlib luaL_openlib +#endif + + +/* extra error code for `luaL_load' */ +#define LUA_ERRFILE (LUA_ERRERR+1) + + +typedef struct luaL_Reg { + const char *name; + lua_CFunction func; +} luaL_Reg; + + + +LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname, + const luaL_Reg *l, int nup); +LUALIB_API void (luaL_register) (lua_State *L, const char *libname, + const luaL_Reg *l); +LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); +LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); +LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, + size_t *l); +LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, + const char *def, size_t *l); +LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); +LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); + +LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); +LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, + lua_Integer def); + +LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); +LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); +LUALIB_API void (luaL_checkany) (lua_State *L, int narg); + +LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); + +LUALIB_API void (luaL_where) (lua_State *L, int lvl); +LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); + +LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, + const char *const lst[]); + +LUALIB_API int (luaL_ref) (lua_State *L, int t); +LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); + +LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); +LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, + const char *name); +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); + +LUALIB_API lua_State *(luaL_newstate) (void); + + +LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, + const char *r); + +LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, + const char *fname, int szhint); + + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#define luaL_argcheck(L, cond,numarg,extramsg) \ + ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) +#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) +#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) + +#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) + +#define luaL_dofile(L, fn) \ + (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_dostring(L, s) \ + (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) + +#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + + + +typedef struct luaL_Buffer { + char *p; /* current position in buffer */ + int lvl; /* number of strings in the stack (level) */ + lua_State *L; + char buffer[LUAL_BUFFERSIZE]; +} luaL_Buffer; + +#define luaL_addchar(B,c) \ + ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ + (*(B)->p++ = (char)(c))) + +/* compatibility only */ +#define luaL_putchar(B,c) luaL_addchar(B,c) + +#define luaL_addsize(B,n) ((B)->p += (n)) + +LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); +LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); +LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); +LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); +LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); + + +/* }====================================================== */ + + +/* compatibility with ref system */ + +/* pre-defined references */ +#define LUA_NOREF (-2) +#define LUA_REFNIL (-1) + +#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ + (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) + +#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) + +#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) + + +#define luaL_reg luaL_Reg + +#endif + + diff --git a/lua/src/lbaselib.c b/lua/src/lbaselib.c new file mode 100644 index 0000000000..2a4c079d3b --- /dev/null +++ b/lua/src/lbaselib.c @@ -0,0 +1,653 @@ +/* +** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $ +** Basic library +** See Copyright Notice in lua.h +*/ + + + +#include +#include +#include +#include + +#define lbaselib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + + +/* +** If your system does not support `stdout', you can just remove this function. +** If you need, you can define your own `print' function, following this +** model but changing `fputs' to put the strings at a proper place +** (a console window or a log file, for instance). +*/ +static int luaB_print (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + lua_getglobal(L, "tostring"); + for (i=1; i<=n; i++) { + const char *s; + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + s = lua_tostring(L, -1); /* get result */ + if (s == NULL) + return luaL_error(L, LUA_QL("tostring") " must return a string to " + LUA_QL("print")); + if (i>1) fputs("\t", stdout); + fputs(s, stdout); + lua_pop(L, 1); /* pop result */ + } + fputs("\n", stdout); + return 0; +} + + +static int luaB_tonumber (lua_State *L) { + int base = luaL_optint(L, 2, 10); + if (base == 10) { /* standard conversion */ + luaL_checkany(L, 1); + if (lua_isnumber(L, 1)) { + lua_pushnumber(L, lua_tonumber(L, 1)); + return 1; + } + } + else { + const char *s1 = luaL_checkstring(L, 1); + char *s2; + unsigned long n; + luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); + n = strtoul(s1, &s2, base); + if (s1 != s2) { /* at least one valid digit? */ + while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */ + if (*s2 == '\0') { /* no invalid trailing characters? */ + lua_pushnumber(L, (lua_Number)n); + return 1; + } + } + } + lua_pushnil(L); /* else not a number */ + return 1; +} + + +static int luaB_error (lua_State *L) { + int level = luaL_optint(L, 2, 1); + lua_settop(L, 1); + if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ + luaL_where(L, level); + lua_pushvalue(L, 1); + lua_concat(L, 2); + } + return lua_error(L); +} + + +static int luaB_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); + return 1; /* no metatable */ + } + luaL_getmetafield(L, 1, "__metatable"); + return 1; /* returns either __metatable field (if present) or metatable */ +} + + +static int luaB_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + if (luaL_getmetafield(L, 1, "__metatable")) + luaL_error(L, "cannot change a protected metatable"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; +} + + +static void getfunc (lua_State *L, int opt) { + if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); + else { + lua_Debug ar; + int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); + luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); + if (lua_getstack(L, level, &ar) == 0) + luaL_argerror(L, 1, "invalid level"); + lua_getinfo(L, "f", &ar); + if (lua_isnil(L, -1)) + luaL_error(L, "no function environment for tail call at level %d", + level); + } +} + + +static int luaB_getfenv (lua_State *L) { + getfunc(L, 1); + if (lua_iscfunction(L, -1)) /* is a C function? */ + lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ + else + lua_getfenv(L, -1); + return 1; +} + + +static int luaB_setfenv (lua_State *L) { + luaL_checktype(L, 2, LUA_TTABLE); + getfunc(L, 0); + lua_pushvalue(L, 2); + if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { + /* change environment of current thread */ + lua_pushthread(L); + lua_insert(L, -2); + lua_setfenv(L, -2); + return 0; + } + else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) + luaL_error(L, + LUA_QL("setfenv") " cannot change environment of given object"); + return 1; +} + + +static int luaB_rawequal (lua_State *L) { + luaL_checkany(L, 1); + luaL_checkany(L, 2); + lua_pushboolean(L, lua_rawequal(L, 1, 2)); + return 1; +} + + +static int luaB_rawget (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_rawget(L, 1); + return 1; +} + +static int luaB_rawset (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + luaL_checkany(L, 3); + lua_settop(L, 3); + lua_rawset(L, 1); + return 1; +} + + +static int luaB_gcinfo (lua_State *L) { + lua_pushinteger(L, lua_getgccount(L)); + return 1; +} + + +static int luaB_collectgarbage (lua_State *L) { + static const char *const opts[] = {"stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", NULL}; + static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; + int o = luaL_checkoption(L, 1, "collect", opts); + int ex = luaL_optint(L, 2, 0); + int res = lua_gc(L, optsnum[o], ex); + switch (optsnum[o]) { + case LUA_GCCOUNT: { + int b = lua_gc(L, LUA_GCCOUNTB, 0); + lua_pushnumber(L, res + ((lua_Number)b/1024)); + return 1; + } + case LUA_GCSTEP: { + lua_pushboolean(L, res); + return 1; + } + default: { + lua_pushnumber(L, res); + return 1; + } + } +} + + +static int luaB_type (lua_State *L) { + luaL_checkany(L, 1); + lua_pushstring(L, luaL_typename(L, 1)); + return 1; +} + + +static int luaB_next (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lua_next(L, 1)) + return 2; + else { + lua_pushnil(L); + return 1; + } +} + + +static int luaB_pairs (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushnil(L); /* and initial value */ + return 3; +} + + +static int ipairsaux (lua_State *L) { + int i = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + i++; /* next value */ + lua_pushinteger(L, i); + lua_rawgeti(L, 1, i); + return (lua_isnil(L, -1)) ? 0 : 2; +} + + +static int luaB_ipairs (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushinteger(L, 0); /* and initial value */ + return 3; +} + + +static int load_aux (lua_State *L, int status) { + if (status == 0) /* OK? */ + return 1; + else { + lua_pushnil(L); + lua_insert(L, -2); /* put before error message */ + return 2; /* return nil plus error message */ + } +} + + +static int luaB_loadstring (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + const char *chunkname = luaL_optstring(L, 2, s); + return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); +} + + +static int luaB_loadfile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + return load_aux(L, luaL_loadfile(L, fname)); +} + + +/* +** Reader for generic `load' function: `lua_load' uses the +** stack for internal stuff, so the reader cannot change the +** stack top. Instead, it keeps its resulting string in a +** reserved slot inside the stack. +*/ +static const char *generic_reader (lua_State *L, void *ud, size_t *size) { + (void)ud; /* to avoid warnings */ + luaL_checkstack(L, 2, "too many nested functions"); + lua_pushvalue(L, 1); /* get function */ + lua_call(L, 0, 1); /* call it */ + if (lua_isnil(L, -1)) { + *size = 0; + return NULL; + } + else if (lua_isstring(L, -1)) { + lua_replace(L, 3); /* save string in a reserved stack slot */ + return lua_tolstring(L, 3, size); + } + else luaL_error(L, "reader function must return a string"); + return NULL; /* to avoid warnings */ +} + + +static int luaB_load (lua_State *L) { + int status; + const char *cname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ + status = lua_load(L, generic_reader, NULL, cname); + return load_aux(L, status); +} + + +static int luaB_dofile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + int n = lua_gettop(L); + if (luaL_loadfile(L, fname) != 0) lua_error(L); + lua_call(L, 0, LUA_MULTRET); + return lua_gettop(L) - n; +} + + +static int luaB_assert (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_toboolean(L, 1)) + return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); + return lua_gettop(L); +} + + +static int luaB_unpack (lua_State *L) { + int i, e, n; + luaL_checktype(L, 1, LUA_TTABLE); + i = luaL_optint(L, 2, 1); + e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); + if (i > e) return 0; /* empty range */ + n = e - i + 1; /* number of elements */ + if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ + return luaL_error(L, "too many results to unpack"); + lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ + while (i++ < e) /* push arg[i + 1...e] */ + lua_rawgeti(L, 1, i); + return n; +} + + +static int luaB_select (lua_State *L) { + int n = lua_gettop(L); + if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { + lua_pushinteger(L, n-1); + return 1; + } + else { + int i = luaL_checkint(L, 1); + if (i < 0) i = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); + return n - i; + } +} + + +static int luaB_pcall (lua_State *L) { + int status; + luaL_checkany(L, 1); + status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); + lua_pushboolean(L, (status == 0)); + lua_insert(L, 1); + return lua_gettop(L); /* return status + all results */ +} + + +static int luaB_xpcall (lua_State *L) { + int status; + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_insert(L, 1); /* put error function under function to be called */ + status = lua_pcall(L, 0, LUA_MULTRET, 1); + lua_pushboolean(L, (status == 0)); + lua_replace(L, 1); + return lua_gettop(L); /* return status + all results */ +} + + +static int luaB_tostring (lua_State *L) { + luaL_checkany(L, 1); + if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ + return 1; /* use its value */ + switch (lua_type(L, 1)) { + case LUA_TNUMBER: + lua_pushstring(L, lua_tostring(L, 1)); + break; + case LUA_TSTRING: + lua_pushvalue(L, 1); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: + lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); + break; + } + return 1; +} + + +static int luaB_newproxy (lua_State *L) { + lua_settop(L, 1); + lua_newuserdata(L, 0); /* create proxy */ + if (lua_toboolean(L, 1) == 0) + return 1; /* no metatable */ + else if (lua_isboolean(L, 1)) { + lua_newtable(L); /* create a new metatable `m' ... */ + lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */ + lua_pushboolean(L, 1); + lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */ + } + else { + int validproxy = 0; /* to check if weaktable[metatable(u)] == true */ + if (lua_getmetatable(L, 1)) { + lua_rawget(L, lua_upvalueindex(1)); + validproxy = lua_toboolean(L, -1); + lua_pop(L, 1); /* remove value */ + } + luaL_argcheck(L, validproxy, 1, "boolean or proxy expected"); + lua_getmetatable(L, 1); /* metatable is valid; get it */ + } + lua_setmetatable(L, 2); + return 1; +} + + +static const luaL_Reg base_funcs[] = { + {"assert", luaB_assert}, + {"collectgarbage", luaB_collectgarbage}, + {"dofile", luaB_dofile}, + {"error", luaB_error}, + {"gcinfo", luaB_gcinfo}, + {"getfenv", luaB_getfenv}, + {"getmetatable", luaB_getmetatable}, + {"loadfile", luaB_loadfile}, + {"load", luaB_load}, + {"loadstring", luaB_loadstring}, + {"next", luaB_next}, + {"pcall", luaB_pcall}, + {"print", luaB_print}, + {"rawequal", luaB_rawequal}, + {"rawget", luaB_rawget}, + {"rawset", luaB_rawset}, + {"select", luaB_select}, + {"setfenv", luaB_setfenv}, + {"setmetatable", luaB_setmetatable}, + {"tonumber", luaB_tonumber}, + {"tostring", luaB_tostring}, + {"type", luaB_type}, + {"unpack", luaB_unpack}, + {"xpcall", luaB_xpcall}, + {NULL, NULL} +}; + + +/* +** {====================================================== +** Coroutine library +** ======================================================= +*/ + +#define CO_RUN 0 /* running */ +#define CO_SUS 1 /* suspended */ +#define CO_NOR 2 /* 'normal' (it resumed another coroutine) */ +#define CO_DEAD 3 + +static const char *const statnames[] = + {"running", "suspended", "normal", "dead"}; + +static int costatus (lua_State *L, lua_State *co) { + if (L == co) return CO_RUN; + switch (lua_status(co)) { + case LUA_YIELD: + return CO_SUS; + case 0: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + return CO_NOR; /* it is running */ + else if (lua_gettop(co) == 0) + return CO_DEAD; + else + return CO_SUS; /* initial state */ + } + default: /* some error occured */ + return CO_DEAD; + } +} + + +static int luaB_costatus (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "coroutine expected"); + lua_pushstring(L, statnames[costatus(L, co)]); + return 1; +} + + +static int auxresume (lua_State *L, lua_State *co, int narg) { + int status = costatus(L, co); + if (!lua_checkstack(co, narg)) + luaL_error(L, "too many arguments to resume"); + if (status != CO_SUS) { + lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]); + return -1; /* error flag */ + } + lua_xmove(L, co, narg); + lua_setlevel(L, co); + status = lua_resume(co, narg); + if (status == 0 || status == LUA_YIELD) { + int nres = lua_gettop(co); + if (!lua_checkstack(L, nres + 1)) + luaL_error(L, "too many results to resume"); + lua_xmove(co, L, nres); /* move yielded values */ + return nres; + } + else { + lua_xmove(co, L, 1); /* move error message */ + return -1; /* error flag */ + } +} + + +static int luaB_coresume (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + int r; + luaL_argcheck(L, co, 1, "coroutine expected"); + r = auxresume(L, co, lua_gettop(L) - 1); + if (r < 0) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); + return r + 1; /* return true + `resume' returns */ + } +} + + +static int luaB_auxwrap (lua_State *L) { + lua_State *co = lua_tothread(L, lua_upvalueindex(1)); + int r = auxresume(L, co, lua_gettop(L)); + if (r < 0) { + if (lua_isstring(L, -1)) { /* error object is a string? */ + luaL_where(L, 1); /* add extra info */ + lua_insert(L, -2); + lua_concat(L, 2); + } + lua_error(L); /* propagate error */ + } + return r; +} + + +static int luaB_cocreate (lua_State *L) { + lua_State *NL = lua_newthread(L); + luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, + "Lua function expected"); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ + return 1; +} + + +static int luaB_cowrap (lua_State *L) { + luaB_cocreate(L); + lua_pushcclosure(L, luaB_auxwrap, 1); + return 1; +} + + +static int luaB_yield (lua_State *L) { + return lua_yield(L, lua_gettop(L)); +} + + +static int luaB_corunning (lua_State *L) { + if (lua_pushthread(L)) + lua_pushnil(L); /* main thread is not a coroutine */ + return 1; +} + + +static const luaL_Reg co_funcs[] = { + {"create", luaB_cocreate}, + {"resume", luaB_coresume}, + {"running", luaB_corunning}, + {"status", luaB_costatus}, + {"wrap", luaB_cowrap}, + {"yield", luaB_yield}, + {NULL, NULL} +}; + +/* }====================================================== */ + + +static void auxopen (lua_State *L, const char *name, + lua_CFunction f, lua_CFunction u) { + lua_pushcfunction(L, u); + lua_pushcclosure(L, f, 1); + lua_setfield(L, -2, name); +} + + +static void base_open (lua_State *L) { + /* set global _G */ + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setglobal(L, "_G"); + /* open lib into global table */ + luaL_register(L, "_G", base_funcs); + lua_pushliteral(L, LUA_VERSION); + lua_setglobal(L, "_VERSION"); /* set global _VERSION */ + /* `ipairs' and `pairs' need auxliliary functions as upvalues */ + auxopen(L, "ipairs", luaB_ipairs, ipairsaux); + auxopen(L, "pairs", luaB_pairs, luaB_next); + /* `newproxy' needs a weaktable as upvalue */ + lua_createtable(L, 0, 1); /* new table `w' */ + lua_pushvalue(L, -1); /* `w' will be its own metatable */ + lua_setmetatable(L, -2); + lua_pushliteral(L, "kv"); + lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ + lua_pushcclosure(L, luaB_newproxy, 1); + lua_setglobal(L, "newproxy"); /* set global `newproxy' */ +} + + +LUALIB_API int luaopen_base (lua_State *L) { + base_open(L); + luaL_register(L, LUA_COLIBNAME, co_funcs); + return 2; +} + diff --git a/lua/src/lcode.c b/lua/src/lcode.c new file mode 100644 index 0000000000..cff626b7fa --- /dev/null +++ b/lua/src/lcode.c @@ -0,0 +1,839 @@ +/* +** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + + +#include + +#define lcode_c +#define LUA_CORE + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "ltable.h" + + +#define hasjumps(e) ((e)->t != (e)->f) + + +static int isnumeral(expdesc *e) { + return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); +} + + +void luaK_nil (FuncState *fs, int from, int n) { + Instruction *previous; + if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ + if (fs->pc == 0) { /* function start? */ + if (from >= fs->nactvar) + return; /* positions are already clean */ + } + else { + previous = &fs->f->code[fs->pc-1]; + if (GET_OPCODE(*previous) == OP_LOADNIL) { + int pfrom = GETARG_A(*previous); + int pto = GETARG_B(*previous); + if (pfrom <= from && from <= pto+1) { /* can connect both? */ + if (from+n-1 > pto) + SETARG_B(*previous, from+n-1); + return; + } + } + } + } + luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */ +} + + +int luaK_jump (FuncState *fs) { + int jpc = fs->jpc; /* save list of jumps to here */ + int j; + fs->jpc = NO_JUMP; + j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); + luaK_concat(fs, &j, jpc); /* keep them on hold */ + return j; +} + + +void luaK_ret (FuncState *fs, int first, int nret) { + luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); +} + + +static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { + luaK_codeABC(fs, op, A, B, C); + return luaK_jump(fs); +} + + +static void fixjump (FuncState *fs, int pc, int dest) { + Instruction *jmp = &fs->f->code[pc]; + int offset = dest-(pc+1); + lua_assert(dest != NO_JUMP); + if (abs(offset) > MAXARG_sBx) + luaX_syntaxerror(fs->ls, "control structure too long"); + SETARG_sBx(*jmp, offset); +} + + +/* +** returns current `pc' and marks it as a jump target (to avoid wrong +** optimizations with consecutive instructions not in the same basic block). +*/ +int luaK_getlabel (FuncState *fs) { + fs->lasttarget = fs->pc; + return fs->pc; +} + + +static int getjump (FuncState *fs, int pc) { + int offset = GETARG_sBx(fs->f->code[pc]); + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc+1)+offset; /* turn offset into absolute position */ +} + + +static Instruction *getjumpcontrol (FuncState *fs, int pc) { + Instruction *pi = &fs->f->code[pc]; + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) + return pi-1; + else + return pi; +} + + +/* +** check whether list has any jump that do not produce a value +** (or produce an inverted value) +*/ +static int need_value (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) { + Instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TESTSET) return 1; + } + return 0; /* not found */ +} + + +static int patchtestreg (FuncState *fs, int node, int reg) { + Instruction *i = getjumpcontrol(fs, node); + if (GET_OPCODE(*i) != OP_TESTSET) + return 0; /* cannot patch other instructions */ + if (reg != NO_REG && reg != GETARG_B(*i)) + SETARG_A(*i, reg); + else /* no register to put value or register already has the value */ + *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); + + return 1; +} + + +static void removevalues (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); +} + + +static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, + int dtarget) { + while (list != NO_JUMP) { + int next = getjump(fs, list); + if (patchtestreg(fs, list, reg)) + fixjump(fs, list, vtarget); + else + fixjump(fs, list, dtarget); /* jump to default target */ + list = next; + } +} + + +static void dischargejpc (FuncState *fs) { + patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); + fs->jpc = NO_JUMP; +} + + +void luaK_patchlist (FuncState *fs, int list, int target) { + if (target == fs->pc) + luaK_patchtohere(fs, list); + else { + lua_assert(target < fs->pc); + patchlistaux(fs, list, target, NO_REG, target); + } +} + + +void luaK_patchtohere (FuncState *fs, int list) { + luaK_getlabel(fs); + luaK_concat(fs, &fs->jpc, list); +} + + +void luaK_concat (FuncState *fs, int *l1, int l2) { + if (l2 == NO_JUMP) return; + else if (*l1 == NO_JUMP) + *l1 = l2; + else { + int list = *l1; + int next; + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, l2); + } +} + + +void luaK_checkstack (FuncState *fs, int n) { + int newstack = fs->freereg + n; + if (newstack > fs->f->maxstacksize) { + if (newstack >= MAXSTACK) + luaX_syntaxerror(fs->ls, "function or expression too complex"); + fs->f->maxstacksize = cast_byte(newstack); + } +} + + +void luaK_reserveregs (FuncState *fs, int n) { + luaK_checkstack(fs, n); + fs->freereg += n; +} + + +static void freereg (FuncState *fs, int reg) { + if (!ISK(reg) && reg >= fs->nactvar) { + fs->freereg--; + lua_assert(reg == fs->freereg); + } +} + + +static void freeexp (FuncState *fs, expdesc *e) { + if (e->k == VNONRELOC) + freereg(fs, e->u.s.info); +} + + +static int addk (FuncState *fs, TValue *k, TValue *v) { + lua_State *L = fs->L; + TValue *idx = luaH_set(L, fs->h, k); + Proto *f = fs->f; + int oldsize = f->sizek; + if (ttisnumber(idx)) { + lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); + return cast_int(nvalue(idx)); + } + else { /* constant not found; create a new entry */ + setnvalue(idx, cast_num(fs->nk)); + luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, + MAXARG_Bx, "constant table overflow"); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[fs->nk], v); + luaC_barrier(L, f, v); + return fs->nk++; + } +} + + +int luaK_stringK (FuncState *fs, TString *s) { + TValue o; + setsvalue(fs->L, &o, s); + return addk(fs, &o, &o); +} + + +int luaK_numberK (FuncState *fs, lua_Number r) { + TValue o; + setnvalue(&o, r); + return addk(fs, &o, &o); +} + + +static int boolK (FuncState *fs, int b) { + TValue o; + setbvalue(&o, b); + return addk(fs, &o, &o); +} + + +static int nilK (FuncState *fs) { + TValue k, v; + setnilvalue(&v); + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs->L, &k, fs->h); + return addk(fs, &k, &v); +} + + +void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { + if (e->k == VCALL) { /* expression is an open function call? */ + SETARG_C(getcode(fs, e), nresults+1); + } + else if (e->k == VVARARG) { + SETARG_B(getcode(fs, e), nresults+1); + SETARG_A(getcode(fs, e), fs->freereg); + luaK_reserveregs(fs, 1); + } +} + + +void luaK_setoneret (FuncState *fs, expdesc *e) { + if (e->k == VCALL) { /* expression is an open function call? */ + e->k = VNONRELOC; + e->u.s.info = GETARG_A(getcode(fs, e)); + } + else if (e->k == VVARARG) { + SETARG_B(getcode(fs, e), 2); + e->k = VRELOCABLE; /* can relocate its simple result */ + } +} + + +void luaK_dischargevars (FuncState *fs, expdesc *e) { + switch (e->k) { + case VLOCAL: { + e->k = VNONRELOC; + break; + } + case VUPVAL: { + e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0); + e->k = VRELOCABLE; + break; + } + case VGLOBAL: { + e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); + e->k = VRELOCABLE; + break; + } + case VINDEXED: { + freereg(fs, e->u.s.aux); + freereg(fs, e->u.s.info); + e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux); + e->k = VRELOCABLE; + break; + } + case VVARARG: + case VCALL: { + luaK_setoneret(fs, e); + break; + } + default: break; /* there is one value available (somewhere) */ + } +} + + +static int code_label (FuncState *fs, int A, int b, int jump) { + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); +} + + +static void discharge2reg (FuncState *fs, expdesc *e, int reg) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: { + luaK_nil(fs, reg, 1); + break; + } + case VFALSE: case VTRUE: { + luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); + break; + } + case VK: { + luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); + break; + } + case VKNUM: { + luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); + break; + } + case VRELOCABLE: { + Instruction *pc = &getcode(fs, e); + SETARG_A(*pc, reg); + break; + } + case VNONRELOC: { + if (reg != e->u.s.info) + luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0); + break; + } + default: { + lua_assert(e->k == VVOID || e->k == VJMP); + return; /* nothing to do... */ + } + } + e->u.s.info = reg; + e->k = VNONRELOC; +} + + +static void discharge2anyreg (FuncState *fs, expdesc *e) { + if (e->k != VNONRELOC) { + luaK_reserveregs(fs, 1); + discharge2reg(fs, e, fs->freereg-1); + } +} + + +static void exp2reg (FuncState *fs, expdesc *e, int reg) { + discharge2reg(fs, e, reg); + if (e->k == VJMP) + luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */ + if (hasjumps(e)) { + int final; /* position after whole expression */ + int p_f = NO_JUMP; /* position of an eventual LOAD false */ + int p_t = NO_JUMP; /* position of an eventual LOAD true */ + if (need_value(fs, e->t) || need_value(fs, e->f)) { + int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); + p_f = code_label(fs, reg, 0, 1); + p_t = code_label(fs, reg, 1, 0); + luaK_patchtohere(fs, fj); + } + final = luaK_getlabel(fs); + patchlistaux(fs, e->f, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t); + } + e->f = e->t = NO_JUMP; + e->u.s.info = reg; + e->k = VNONRELOC; +} + + +void luaK_exp2nextreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + freeexp(fs, e); + luaK_reserveregs(fs, 1); + exp2reg(fs, e, fs->freereg - 1); +} + + +int luaK_exp2anyreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + if (e->k == VNONRELOC) { + if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */ + if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */ + exp2reg(fs, e, e->u.s.info); /* put value on it */ + return e->u.s.info; + } + } + luaK_exp2nextreg(fs, e); /* default */ + return e->u.s.info; +} + + +void luaK_exp2val (FuncState *fs, expdesc *e) { + if (hasjumps(e)) + luaK_exp2anyreg(fs, e); + else + luaK_dischargevars(fs, e); +} + + +int luaK_exp2RK (FuncState *fs, expdesc *e) { + luaK_exp2val(fs, e); + switch (e->k) { + case VKNUM: + case VTRUE: + case VFALSE: + case VNIL: { + if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ + e->u.s.info = (e->k == VNIL) ? nilK(fs) : + (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : + boolK(fs, (e->k == VTRUE)); + e->k = VK; + return RKASK(e->u.s.info); + } + else break; + } + case VK: { + if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ + return RKASK(e->u.s.info); + else break; + } + default: break; + } + /* not a constant in the right range: put it in a register */ + return luaK_exp2anyreg(fs, e); +} + + +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { + switch (var->k) { + case VLOCAL: { + freeexp(fs, ex); + exp2reg(fs, ex, var->u.s.info); + return; + } + case VUPVAL: { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); + break; + } + case VGLOBAL: { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); + break; + } + case VINDEXED: { + int e = luaK_exp2RK(fs, ex); + luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); + break; + } + default: { + lua_assert(0); /* invalid var kind to store */ + break; + } + } + freeexp(fs, ex); +} + + +void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { + int func; + luaK_exp2anyreg(fs, e); + freeexp(fs, e); + func = fs->freereg; + luaK_reserveregs(fs, 2); + luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); + freeexp(fs, key); + e->u.s.info = func; + e->k = VNONRELOC; +} + + +static void invertjump (FuncState *fs, expdesc *e) { + Instruction *pc = getjumpcontrol(fs, e->u.s.info); + lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && + GET_OPCODE(*pc) != OP_TEST); + SETARG_A(*pc, !(GETARG_A(*pc))); +} + + +static int jumponcond (FuncState *fs, expdesc *e, int cond) { + if (e->k == VRELOCABLE) { + Instruction ie = getcode(fs, e); + if (GET_OPCODE(ie) == OP_NOT) { + fs->pc--; /* remove previous OP_NOT */ + return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); + } + /* else go through */ + } + discharge2anyreg(fs, e); + freeexp(fs, e); + return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond); +} + + +void luaK_goiftrue (FuncState *fs, expdesc *e) { + int pc; /* pc of last jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VK: case VKNUM: case VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ + break; + } + case VFALSE: { + pc = luaK_jump(fs); /* always jump */ + break; + } + case VJMP: { + invertjump(fs, e); + pc = e->u.s.info; + break; + } + default: { + pc = jumponcond(fs, e, 0); + break; + } + } + luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ + luaK_patchtohere(fs, e->t); + e->t = NO_JUMP; +} + + +static void luaK_goiffalse (FuncState *fs, expdesc *e) { + int pc; /* pc of last jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: case VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ + break; + } + case VTRUE: { + pc = luaK_jump(fs); /* always jump */ + break; + } + case VJMP: { + pc = e->u.s.info; + break; + } + default: { + pc = jumponcond(fs, e, 1); + break; + } + } + luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ + luaK_patchtohere(fs, e->f); + e->f = NO_JUMP; +} + + +static void codenot (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: case VFALSE: { + e->k = VTRUE; + break; + } + case VK: case VKNUM: case VTRUE: { + e->k = VFALSE; + break; + } + case VJMP: { + invertjump(fs, e); + break; + } + case VRELOCABLE: + case VNONRELOC: { + discharge2anyreg(fs, e); + freeexp(fs, e); + e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0); + e->k = VRELOCABLE; + break; + } + default: { + lua_assert(0); /* cannot happen */ + break; + } + } + /* interchange true and false lists */ + { int temp = e->f; e->f = e->t; e->t = temp; } + removevalues(fs, e->f); + removevalues(fs, e->t); +} + + +void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { + t->u.s.aux = luaK_exp2RK(fs, k); + t->k = VINDEXED; +} + + +static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { + lua_Number v1, v2, r; + if (!isnumeral(e1) || !isnumeral(e2)) return 0; + v1 = e1->u.nval; + v2 = e2->u.nval; + switch (op) { + case OP_ADD: r = luai_numadd(v1, v2); break; + case OP_SUB: r = luai_numsub(v1, v2); break; + case OP_MUL: r = luai_nummul(v1, v2); break; + case OP_DIV: + if (v2 == 0) return 0; /* do not attempt to divide by 0 */ + r = luai_numdiv(v1, v2); break; + case OP_MOD: + if (v2 == 0) return 0; /* do not attempt to divide by 0 */ + r = luai_nummod(v1, v2); break; + case OP_POW: r = luai_numpow(v1, v2); break; + case OP_UNM: r = luai_numunm(v1); break; + case OP_LEN: return 0; /* no constant folding for 'len' */ + default: lua_assert(0); r = 0; break; + } + if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ + e1->u.nval = r; + return 1; +} + + +static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { + if (constfolding(op, e1, e2)) + return; + else { + int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; + int o1 = luaK_exp2RK(fs, e1); + if (o1 > o2) { + freeexp(fs, e1); + freeexp(fs, e2); + } + else { + freeexp(fs, e2); + freeexp(fs, e1); + } + e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); + e1->k = VRELOCABLE; + } +} + + +static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, + expdesc *e2) { + int o1 = luaK_exp2RK(fs, e1); + int o2 = luaK_exp2RK(fs, e2); + freeexp(fs, e2); + freeexp(fs, e1); + if (cond == 0 && op != OP_EQ) { + int temp; /* exchange args to replace by `<' or `<=' */ + temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ + cond = 1; + } + e1->u.s.info = condjump(fs, op, cond, o1, o2); + e1->k = VJMP; +} + + +void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { + expdesc e2; + e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; + switch (op) { + case OPR_MINUS: { + if (!isnumeral(e)) + luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ + codearith(fs, OP_UNM, e, &e2); + break; + } + case OPR_NOT: codenot(fs, e); break; + case OPR_LEN: { + luaK_exp2anyreg(fs, e); /* cannot operate on constants */ + codearith(fs, OP_LEN, e, &e2); + break; + } + default: lua_assert(0); + } +} + + +void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { + switch (op) { + case OPR_AND: { + luaK_goiftrue(fs, v); + break; + } + case OPR_OR: { + luaK_goiffalse(fs, v); + break; + } + case OPR_CONCAT: { + luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ + break; + } + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_MOD: case OPR_POW: { + if (!isnumeral(v)) luaK_exp2RK(fs, v); + break; + } + default: { + luaK_exp2RK(fs, v); + break; + } + } +} + + +void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { + switch (op) { + case OPR_AND: { + lua_assert(e1->t == NO_JUMP); /* list must be closed */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e2->f, e1->f); + *e1 = *e2; + break; + } + case OPR_OR: { + lua_assert(e1->f == NO_JUMP); /* list must be closed */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e2->t, e1->t); + *e1 = *e2; + break; + } + case OPR_CONCAT: { + luaK_exp2val(fs, e2); + if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { + lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); + freeexp(fs, e1); + SETARG_B(getcode(fs, e2), e1->u.s.info); + e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info; + } + else { + luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ + codearith(fs, OP_CONCAT, e1, e2); + } + break; + } + case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; + case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; + case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; + case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; + case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; + case OPR_POW: codearith(fs, OP_POW, e1, e2); break; + case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; + case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; + case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; + case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; + case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; + case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; + default: lua_assert(0); + } +} + + +void luaK_fixline (FuncState *fs, int line) { + fs->f->lineinfo[fs->pc - 1] = line; +} + + +static int luaK_code (FuncState *fs, Instruction i, int line) { + Proto *f = fs->f; + dischargejpc(fs); /* `pc' will change */ + /* put new instruction in code array */ + luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "code size overflow"); + f->code[fs->pc] = i; + /* save corresponding line information */ + luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, + MAX_INT, "code size overflow"); + f->lineinfo[fs->pc] = line; + return fs->pc++; +} + + +int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { + lua_assert(getOpMode(o) == iABC); + lua_assert(getBMode(o) != OpArgN || b == 0); + lua_assert(getCMode(o) != OpArgN || c == 0); + return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); +} + + +int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { + lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + lua_assert(getCMode(o) == OpArgN); + return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); +} + + +void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { + int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; + int b = (tostore == LUA_MULTRET) ? 0 : tostore; + lua_assert(tostore != 0); + if (c <= MAXARG_C) + luaK_codeABC(fs, OP_SETLIST, base, b, c); + else { + luaK_codeABC(fs, OP_SETLIST, base, b, 0); + luaK_code(fs, cast(Instruction, c), fs->ls->lastline); + } + fs->freereg = base + 1; /* free registers with list values */ +} + diff --git a/lua/src/lcode.h b/lua/src/lcode.h new file mode 100644 index 0000000000..b941c60721 --- /dev/null +++ b/lua/src/lcode.h @@ -0,0 +1,76 @@ +/* +** $Id: lcode.h,v 1.48.1.1 2007/12/27 13:02:25 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lcode_h +#define lcode_h + +#include "llex.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" + + +/* +** Marks the end of a patch list. It is an invalid value both as an absolute +** address, and as a list link (would link an element to itself). +*/ +#define NO_JUMP (-1) + + +/* +** grep "ORDER OPR" if you change these enums +*/ +typedef enum BinOpr { + OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, + OPR_CONCAT, + OPR_NE, OPR_EQ, + OPR_LT, OPR_LE, OPR_GT, OPR_GE, + OPR_AND, OPR_OR, + OPR_NOBINOPR +} BinOpr; + + +typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; + + +#define getcode(fs,e) ((fs)->f->code[(e)->u.s.info]) + +#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) + +#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) + +LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); +LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); +LUAI_FUNC void luaK_fixline (FuncState *fs, int line); +LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); +LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); +LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); +LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); +LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r); +LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); +LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); +LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); +LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); +LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_jump (FuncState *fs); +LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); +LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); +LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); +LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); +LUAI_FUNC int luaK_getlabel (FuncState *fs); +LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); +LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); +LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2); +LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); + + +#endif diff --git a/lua/src/ldblib.c b/lua/src/ldblib.c new file mode 100644 index 0000000000..67de1222a9 --- /dev/null +++ b/lua/src/ldblib.c @@ -0,0 +1,397 @@ +/* +** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $ +** Interface from Lua to its debug API +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +#define ldblib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + +static int db_getregistry (lua_State *L) { + lua_pushvalue(L, LUA_REGISTRYINDEX); + return 1; +} + + +static int db_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); /* no metatable */ + } + return 1; +} + + +static int db_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + lua_settop(L, 2); + lua_pushboolean(L, lua_setmetatable(L, 1)); + return 1; +} + + +static int db_getfenv (lua_State *L) { + lua_getfenv(L, 1); + return 1; +} + + +static int db_setfenv (lua_State *L) { + luaL_checktype(L, 2, LUA_TTABLE); + lua_settop(L, 2); + if (lua_setfenv(L, 1) == 0) + luaL_error(L, LUA_QL("setfenv") + " cannot change environment of given object"); + return 1; +} + + +static void settabss (lua_State *L, const char *i, const char *v) { + lua_pushstring(L, v); + lua_setfield(L, -2, i); +} + + +static void settabsi (lua_State *L, const char *i, int v) { + lua_pushinteger(L, v); + lua_setfield(L, -2, i); +} + + +static lua_State *getthread (lua_State *L, int *arg) { + if (lua_isthread(L, 1)) { + *arg = 1; + return lua_tothread(L, 1); + } + else { + *arg = 0; + return L; + } +} + + +static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { + if (L == L1) { + lua_pushvalue(L, -2); + lua_remove(L, -3); + } + else + lua_xmove(L1, L, 1); + lua_setfield(L, -2, fname); +} + + +static int db_getinfo (lua_State *L) { + lua_Debug ar; + int arg; + lua_State *L1 = getthread(L, &arg); + const char *options = luaL_optstring(L, arg+2, "flnSu"); + if (lua_isnumber(L, arg+1)) { + if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { + lua_pushnil(L); /* level out of range */ + return 1; + } + } + else if (lua_isfunction(L, arg+1)) { + lua_pushfstring(L, ">%s", options); + options = lua_tostring(L, -1); + lua_pushvalue(L, arg+1); + lua_xmove(L, L1, 1); + } + else + return luaL_argerror(L, arg+1, "function or level expected"); + if (!lua_getinfo(L1, options, &ar)) + return luaL_argerror(L, arg+2, "invalid option"); + lua_createtable(L, 0, 2); + if (strchr(options, 'S')) { + settabss(L, "source", ar.source); + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabsi(L, "lastlinedefined", ar.lastlinedefined); + settabss(L, "what", ar.what); + } + if (strchr(options, 'l')) + settabsi(L, "currentline", ar.currentline); + if (strchr(options, 'u')) + settabsi(L, "nups", ar.nups); + if (strchr(options, 'n')) { + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); + } + if (strchr(options, 'L')) + treatstackoption(L, L1, "activelines"); + if (strchr(options, 'f')) + treatstackoption(L, L1, "func"); + return 1; /* return table */ +} + + +static int db_getlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + const char *name; + if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); + if (name) { + lua_xmove(L1, L, 1); + lua_pushstring(L, name); + lua_pushvalue(L, -2); + return 2; + } + else { + lua_pushnil(L); + return 1; + } +} + + +static int db_setlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + luaL_checkany(L, arg+3); + lua_settop(L, arg+3); + lua_xmove(L, L1, 1); + lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); + return 1; +} + + +static int auxupvalue (lua_State *L, int get) { + const char *name; + int n = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); + if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ + name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); + if (name == NULL) return 0; + lua_pushstring(L, name); + lua_insert(L, -(get+1)); + return get + 1; +} + + +static int db_getupvalue (lua_State *L) { + return auxupvalue(L, 1); +} + + +static int db_setupvalue (lua_State *L) { + luaL_checkany(L, 3); + return auxupvalue(L, 0); +} + + + +static const char KEY_HOOK = 'h'; + + +static void hookf (lua_State *L, lua_Debug *ar) { + static const char *const hooknames[] = + {"call", "return", "line", "count", "tail return"}; + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushlightuserdata(L, L); + lua_rawget(L, -2); + if (lua_isfunction(L, -1)) { + lua_pushstring(L, hooknames[(int)ar->event]); + if (ar->currentline >= 0) + lua_pushinteger(L, ar->currentline); + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); + } +} + + +static int makemask (const char *smask, int count) { + int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + return mask; +} + + +static char *unmakemask (int mask, char *smask) { + int i = 0; + if (mask & LUA_MASKCALL) smask[i++] = 'c'; + if (mask & LUA_MASKRET) smask[i++] = 'r'; + if (mask & LUA_MASKLINE) smask[i++] = 'l'; + smask[i] = '\0'; + return smask; +} + + +static void gethooktable (lua_State *L) { + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + lua_createtable(L, 0, 1); + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + } +} + + +static int db_sethook (lua_State *L) { + int arg, mask, count; + lua_Hook func; + lua_State *L1 = getthread(L, &arg); + if (lua_isnoneornil(L, arg+1)) { + lua_settop(L, arg+1); + func = NULL; mask = 0; count = 0; /* turn off hooks */ + } + else { + const char *smask = luaL_checkstring(L, arg+2); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + count = luaL_optint(L, arg+3, 0); + func = hookf; mask = makemask(smask, count); + } + gethooktable(L); + lua_pushlightuserdata(L, L1); + lua_pushvalue(L, arg+1); + lua_rawset(L, -3); /* set new hook */ + lua_pop(L, 1); /* remove hook table */ + lua_sethook(L1, func, mask, count); /* set hooks */ + return 0; +} + + +static int db_gethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + char buff[5]; + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); + if (hook != NULL && hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else { + gethooktable(L); + lua_pushlightuserdata(L, L1); + lua_rawget(L, -2); /* get hook */ + lua_remove(L, -2); /* remove hook table */ + } + lua_pushstring(L, unmakemask(mask, buff)); + lua_pushinteger(L, lua_gethookcount(L1)); + return 3; +} + + +static int db_debug (lua_State *L) { + for (;;) { + char buffer[250]; + fputs("lua_debug> ", stderr); + if (fgets(buffer, sizeof(buffer), stdin) == 0 || + strcmp(buffer, "cont\n") == 0) + return 0; + if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || + lua_pcall(L, 0, 0, 0)) { + fputs(lua_tostring(L, -1), stderr); + fputs("\n", stderr); + } + lua_settop(L, 0); /* remove eventual returns */ + } +} + + +#define LEVELS1 12 /* size of the first part of the stack */ +#define LEVELS2 10 /* size of the second part of the stack */ + +static int db_errorfb (lua_State *L) { + int level; + int firstpart = 1; /* still before eventual `...' */ + int arg; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + if (lua_isnumber(L, arg+2)) { + level = (int)lua_tointeger(L, arg+2); + lua_pop(L, 1); + } + else + level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ + if (lua_gettop(L) == arg) + lua_pushliteral(L, ""); + else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */ + else lua_pushliteral(L, "\n"); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L1, level++, &ar)) { + if (level > LEVELS1 && firstpart) { + /* no more than `LEVELS2' more levels? */ + if (!lua_getstack(L1, level+LEVELS2, &ar)) + level--; /* keep going */ + else { + lua_pushliteral(L, "\n\t..."); /* too many levels */ + while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */ + level++; + } + firstpart = 0; + continue; + } + lua_pushliteral(L, "\n\t"); + lua_getinfo(L1, "Snl", &ar); + lua_pushfstring(L, "%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + if (*ar.namewhat != '\0') /* is there a name? */ + lua_pushfstring(L, " in function " LUA_QS, ar.name); + else { + if (*ar.what == 'm') /* main? */ + lua_pushfstring(L, " in main chunk"); + else if (*ar.what == 'C' || *ar.what == 't') + lua_pushliteral(L, " ?"); /* C function or tail call */ + else + lua_pushfstring(L, " in function <%s:%d>", + ar.short_src, ar.linedefined); + } + lua_concat(L, lua_gettop(L) - arg); + } + lua_concat(L, lua_gettop(L) - arg); + return 1; +} + + +static const luaL_Reg dblib[] = { + {"debug", db_debug}, + {"getfenv", db_getfenv}, + {"gethook", db_gethook}, + {"getinfo", db_getinfo}, + {"getlocal", db_getlocal}, + {"getregistry", db_getregistry}, + {"getmetatable", db_getmetatable}, + {"getupvalue", db_getupvalue}, + {"setfenv", db_setfenv}, + {"sethook", db_sethook}, + {"setlocal", db_setlocal}, + {"setmetatable", db_setmetatable}, + {"setupvalue", db_setupvalue}, + {"traceback", db_errorfb}, + {NULL, NULL} +}; + + +LUALIB_API int luaopen_debug (lua_State *L) { + luaL_register(L, LUA_DBLIBNAME, dblib); + return 1; +} + diff --git a/lua/src/ldebug.c b/lua/src/ldebug.c new file mode 100644 index 0000000000..50ad3d3803 --- /dev/null +++ b/lua/src/ldebug.c @@ -0,0 +1,638 @@ +/* +** $Id: ldebug.c,v 2.29.1.6 2008/05/08 16:56:26 roberto Exp $ +** Debug Interface +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + + +#define ldebug_c +#define LUA_CORE + +#include "lua.h" + +#include "lapi.h" +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + + +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); + + +static int currentpc (lua_State *L, CallInfo *ci) { + if (!isLua(ci)) return -1; /* function is not a Lua function? */ + if (ci == L->ci) + ci->savedpc = L->savedpc; + return pcRel(ci->savedpc, ci_func(ci)->l.p); +} + + +static int currentline (lua_State *L, CallInfo *ci) { + int pc = currentpc(L, ci); + if (pc < 0) + return -1; /* only active lua functions have current-line information */ + else + return getline(ci_func(ci)->l.p, pc); +} + + +/* +** this function can be called asynchronous (e.g. during a signal) +*/ +LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { + if (func == NULL || mask == 0) { /* turn off hooks? */ + mask = 0; + func = NULL; + } + L->hook = func; + L->basehookcount = count; + resethookcount(L); + L->hookmask = cast_byte(mask); + return 1; +} + + +LUA_API lua_Hook lua_gethook (lua_State *L) { + return L->hook; +} + + +LUA_API int lua_gethookmask (lua_State *L) { + return L->hookmask; +} + + +LUA_API int lua_gethookcount (lua_State *L) { + return L->basehookcount; +} + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { + int status; + CallInfo *ci; + lua_lock(L); + for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { + level--; + if (f_isLua(ci)) /* Lua function? */ + level -= ci->tailcalls; /* skip lost tail calls */ + } + if (level == 0 && ci > L->base_ci) { /* level found? */ + status = 1; + ar->i_ci = cast_int(ci - L->base_ci); + } + else if (level < 0) { /* level is of a lost tail call? */ + status = 1; + ar->i_ci = 0; + } + else status = 0; /* no such level */ + lua_unlock(L); + return status; +} + + +static Proto *getluaproto (CallInfo *ci) { + return (isLua(ci) ? ci_func(ci)->l.p : NULL); +} + + +static const char *findlocal (lua_State *L, CallInfo *ci, int n) { + const char *name; + Proto *fp = getluaproto(ci); + if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL) + return name; /* is a local variable in a Lua function */ + else { + StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; + if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */ + return "(*temporary)"; + else + return NULL; + } +} + + +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { + CallInfo *ci = L->base_ci + ar->i_ci; + const char *name = findlocal(L, ci, n); + lua_lock(L); + if (name) + luaA_pushobject(L, ci->base + (n - 1)); + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { + CallInfo *ci = L->base_ci + ar->i_ci; + const char *name = findlocal(L, ci, n); + lua_lock(L); + if (name) + setobjs2s(L, ci->base + (n - 1), L->top - 1); + L->top--; /* pop value */ + lua_unlock(L); + return name; +} + + +static void funcinfo (lua_Debug *ar, Closure *cl) { + if (cl->c.isC) { + ar->source = "=[C]"; + ar->linedefined = -1; + ar->lastlinedefined = -1; + ar->what = "C"; + } + else { + ar->source = getstr(cl->l.p->source); + ar->linedefined = cl->l.p->linedefined; + ar->lastlinedefined = cl->l.p->lastlinedefined; + ar->what = (ar->linedefined == 0) ? "main" : "Lua"; + } + luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); +} + + +static void info_tailcall (lua_Debug *ar) { + ar->name = ar->namewhat = ""; + ar->what = "tail"; + ar->lastlinedefined = ar->linedefined = ar->currentline = -1; + ar->source = "=(tail call)"; + luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); + ar->nups = 0; +} + + +static void collectvalidlines (lua_State *L, Closure *f) { + if (f == NULL || f->c.isC) { + setnilvalue(L->top); + } + else { + Table *t = luaH_new(L, 0, 0); + int *lineinfo = f->l.p->lineinfo; + int i; + for (i=0; il.p->sizelineinfo; i++) + setbvalue(luaH_setnum(L, t, lineinfo[i]), 1); + sethvalue(L, L->top, t); + } + incr_top(L); +} + + +static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, + Closure *f, CallInfo *ci) { + int status = 1; + if (f == NULL) { + info_tailcall(ar); + return status; + } + for (; *what; what++) { + switch (*what) { + case 'S': { + funcinfo(ar, f); + break; + } + case 'l': { + ar->currentline = (ci) ? currentline(L, ci) : -1; + break; + } + case 'u': { + ar->nups = f->c.nupvalues; + break; + } + case 'n': { + ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL; + if (ar->namewhat == NULL) { + ar->namewhat = ""; /* not found */ + ar->name = NULL; + } + break; + } + case 'L': + case 'f': /* handled by lua_getinfo */ + break; + default: status = 0; /* invalid option */ + } + } + return status; +} + + +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { + int status; + Closure *f = NULL; + CallInfo *ci = NULL; + lua_lock(L); + if (*what == '>') { + StkId func = L->top - 1; + luai_apicheck(L, ttisfunction(func)); + what++; /* skip the '>' */ + f = clvalue(func); + L->top--; /* pop function */ + } + else if (ar->i_ci != 0) { /* no tail call? */ + ci = L->base_ci + ar->i_ci; + lua_assert(ttisfunction(ci->func)); + f = clvalue(ci->func); + } + status = auxgetinfo(L, what, ar, f, ci); + if (strchr(what, 'f')) { + if (f == NULL) setnilvalue(L->top); + else setclvalue(L, L->top, f); + incr_top(L); + } + if (strchr(what, 'L')) + collectvalidlines(L, f); + lua_unlock(L); + return status; +} + + +/* +** {====================================================== +** Symbolic Execution and code checker +** ======================================================= +*/ + +#define check(x) if (!(x)) return 0; + +#define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode) + +#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize) + + + +static int precheck (const Proto *pt) { + check(pt->maxstacksize <= MAXSTACK); + check(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); + check(!(pt->is_vararg & VARARG_NEEDSARG) || + (pt->is_vararg & VARARG_HASARG)); + check(pt->sizeupvalues <= pt->nups); + check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); + check(pt->sizecode > 0 && GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); + return 1; +} + + +#define checkopenop(pt,pc) luaG_checkopenop((pt)->code[(pc)+1]) + +int luaG_checkopenop (Instruction i) { + switch (GET_OPCODE(i)) { + case OP_CALL: + case OP_TAILCALL: + case OP_RETURN: + case OP_SETLIST: { + check(GETARG_B(i) == 0); + return 1; + } + default: return 0; /* invalid instruction after an open call */ + } +} + + +static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { + switch (mode) { + case OpArgN: check(r == 0); break; + case OpArgU: break; + case OpArgR: checkreg(pt, r); break; + case OpArgK: + check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); + break; + } + return 1; +} + + +static Instruction symbexec (const Proto *pt, int lastpc, int reg) { + int pc; + int last; /* stores position of last instruction that changed `reg' */ + last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ + check(precheck(pt)); + for (pc = 0; pc < lastpc; pc++) { + Instruction i = pt->code[pc]; + OpCode op = GET_OPCODE(i); + int a = GETARG_A(i); + int b = 0; + int c = 0; + check(op < NUM_OPCODES); + checkreg(pt, a); + switch (getOpMode(op)) { + case iABC: { + b = GETARG_B(i); + c = GETARG_C(i); + check(checkArgMode(pt, b, getBMode(op))); + check(checkArgMode(pt, c, getCMode(op))); + break; + } + case iABx: { + b = GETARG_Bx(i); + if (getBMode(op) == OpArgK) check(b < pt->sizek); + break; + } + case iAsBx: { + b = GETARG_sBx(i); + if (getBMode(op) == OpArgR) { + int dest = pc+1+b; + check(0 <= dest && dest < pt->sizecode); + if (dest > 0) { + int j; + /* check that it does not jump to a setlist count; this + is tricky, because the count from a previous setlist may + have the same value of an invalid setlist; so, we must + go all the way back to the first of them (if any) */ + for (j = 0; j < dest; j++) { + Instruction d = pt->code[dest-1-j]; + if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break; + } + /* if 'j' is even, previous value is not a setlist (even if + it looks like one) */ + check((j&1) == 0); + } + } + break; + } + } + if (testAMode(op)) { + if (a == reg) last = pc; /* change register `a' */ + } + if (testTMode(op)) { + check(pc+2 < pt->sizecode); /* check skip */ + check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); + } + switch (op) { + case OP_LOADBOOL: { + if (c == 1) { /* does it jump? */ + check(pc+2 < pt->sizecode); /* check its jump */ + check(GET_OPCODE(pt->code[pc+1]) != OP_SETLIST || + GETARG_C(pt->code[pc+1]) != 0); + } + break; + } + case OP_LOADNIL: { + if (a <= reg && reg <= b) + last = pc; /* set registers from `a' to `b' */ + break; + } + case OP_GETUPVAL: + case OP_SETUPVAL: { + check(b < pt->nups); + break; + } + case OP_GETGLOBAL: + case OP_SETGLOBAL: { + check(ttisstring(&pt->k[b])); + break; + } + case OP_SELF: { + checkreg(pt, a+1); + if (reg == a+1) last = pc; + break; + } + case OP_CONCAT: { + check(b < c); /* at least two operands */ + break; + } + case OP_TFORLOOP: { + check(c >= 1); /* at least one result (control variable) */ + checkreg(pt, a+2+c); /* space for results */ + if (reg >= a+2) last = pc; /* affect all regs above its base */ + break; + } + case OP_FORLOOP: + case OP_FORPREP: + checkreg(pt, a+3); + /* go through */ + case OP_JMP: { + int dest = pc+1+b; + /* not full check and jump is forward and do not skip `lastpc'? */ + if (reg != NO_REG && pc < dest && dest <= lastpc) + pc += b; /* do the jump */ + break; + } + case OP_CALL: + case OP_TAILCALL: { + if (b != 0) { + checkreg(pt, a+b-1); + } + c--; /* c = num. returns */ + if (c == LUA_MULTRET) { + check(checkopenop(pt, pc)); + } + else if (c != 0) + checkreg(pt, a+c-1); + if (reg >= a) last = pc; /* affect all registers above base */ + break; + } + case OP_RETURN: { + b--; /* b = num. returns */ + if (b > 0) checkreg(pt, a+b-1); + break; + } + case OP_SETLIST: { + if (b > 0) checkreg(pt, a + b); + if (c == 0) { + pc++; + check(pc < pt->sizecode - 1); + } + break; + } + case OP_CLOSURE: { + int nup, j; + check(b < pt->sizep); + nup = pt->p[b]->nups; + check(pc + nup < pt->sizecode); + for (j = 1; j <= nup; j++) { + OpCode op1 = GET_OPCODE(pt->code[pc + j]); + check(op1 == OP_GETUPVAL || op1 == OP_MOVE); + } + if (reg != NO_REG) /* tracing? */ + pc += nup; /* do not 'execute' these pseudo-instructions */ + break; + } + case OP_VARARG: { + check((pt->is_vararg & VARARG_ISVARARG) && + !(pt->is_vararg & VARARG_NEEDSARG)); + b--; + if (b == LUA_MULTRET) check(checkopenop(pt, pc)); + checkreg(pt, a+b-1); + break; + } + default: break; + } + } + return pt->code[last]; +} + +#undef check +#undef checkjump +#undef checkreg + +/* }====================================================== */ + + +int luaG_checkcode (const Proto *pt) { + return (symbexec(pt, pt->sizecode, NO_REG) != 0); +} + + +static const char *kname (Proto *p, int c) { + if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) + return svalue(&p->k[INDEXK(c)]); + else + return "?"; +} + + +static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, + const char **name) { + if (isLua(ci)) { /* a Lua function? */ + Proto *p = ci_func(ci)->l.p; + int pc = currentpc(L, ci); + Instruction i; + *name = luaF_getlocalname(p, stackpos+1, pc); + if (*name) /* is a local? */ + return "local"; + i = symbexec(p, pc, stackpos); /* try symbolic execution */ + lua_assert(pc != -1); + switch (GET_OPCODE(i)) { + case OP_GETGLOBAL: { + int g = GETARG_Bx(i); /* global index */ + lua_assert(ttisstring(&p->k[g])); + *name = svalue(&p->k[g]); + return "global"; + } + case OP_MOVE: { + int a = GETARG_A(i); + int b = GETARG_B(i); /* move from `b' to `a' */ + if (b < a) + return getobjname(L, ci, b, name); /* get name for `b' */ + break; + } + case OP_GETTABLE: { + int k = GETARG_C(i); /* key index */ + *name = kname(p, k); + return "field"; + } + case OP_GETUPVAL: { + int u = GETARG_B(i); /* upvalue index */ + *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; + return "upvalue"; + } + case OP_SELF: { + int k = GETARG_C(i); /* key index */ + *name = kname(p, k); + return "method"; + } + default: break; + } + } + return NULL; /* no useful name found */ +} + + +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { + Instruction i; + if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) + return NULL; /* calling function is not Lua (or is unknown) */ + ci--; /* calling function */ + i = ci_func(ci)->l.p->code[currentpc(L, ci)]; + if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || + GET_OPCODE(i) == OP_TFORLOOP) + return getobjname(L, ci, GETARG_A(i), name); + else + return NULL; /* no useful name can be found */ +} + + +/* only ANSI way to check whether a pointer points to an array */ +static int isinstack (CallInfo *ci, const TValue *o) { + StkId p; + for (p = ci->base; p < ci->top; p++) + if (o == p) return 1; + return 0; +} + + +void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + const char *name = NULL; + const char *t = luaT_typenames[ttype(o)]; + const char *kind = (isinstack(L->ci, o)) ? + getobjname(L, L->ci, cast_int(o - L->base), &name) : + NULL; + if (kind) + luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", + op, kind, name, t); + else + luaG_runerror(L, "attempt to %s a %s value", op, t); +} + + +void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { + if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; + lua_assert(!ttisstring(p1) && !ttisnumber(p1)); + luaG_typeerror(L, p1, "concatenate"); +} + + +void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { + TValue temp; + if (luaV_tonumber(p1, &temp) == NULL) + p2 = p1; /* first operand is wrong */ + luaG_typeerror(L, p2, "perform arithmetic on"); +} + + +int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { + const char *t1 = luaT_typenames[ttype(p1)]; + const char *t2 = luaT_typenames[ttype(p2)]; + if (t1[2] == t2[2]) + luaG_runerror(L, "attempt to compare two %s values", t1); + else + luaG_runerror(L, "attempt to compare %s with %s", t1, t2); + return 0; +} + + +static void addinfo (lua_State *L, const char *msg) { + CallInfo *ci = L->ci; + if (isLua(ci)) { /* is Lua code? */ + char buff[LUA_IDSIZE]; /* add file:line information */ + int line = currentline(L, ci); + luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); + luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); + } +} + + +void luaG_errormsg (lua_State *L) { + if (L->errfunc != 0) { /* is there an error handling function? */ + StkId errfunc = restorestack(L, L->errfunc); + if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); + setobjs2s(L, L->top, L->top - 1); /* move argument */ + setobjs2s(L, L->top - 1, errfunc); /* push function */ + incr_top(L); + luaD_call(L, L->top - 2, 1); /* call it */ + } + luaD_throw(L, LUA_ERRRUN); +} + + +void luaG_runerror (lua_State *L, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + addinfo(L, luaO_pushvfstring(L, fmt, argp)); + va_end(argp); + luaG_errormsg(L); +} + diff --git a/lua/src/ldebug.h b/lua/src/ldebug.h new file mode 100644 index 0000000000..ba28a97248 --- /dev/null +++ b/lua/src/ldebug.h @@ -0,0 +1,33 @@ +/* +** $Id: ldebug.h,v 2.3.1.1 2007/12/27 13:02:25 roberto Exp $ +** Auxiliary functions from Debug Interface module +** See Copyright Notice in lua.h +*/ + +#ifndef ldebug_h +#define ldebug_h + + +#include "lstate.h" + + +#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) + +#define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) + +#define resethookcount(L) (L->hookcount = L->basehookcount) + + +LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o, + const char *opname); +LUAI_FUNC void luaG_concaterror (lua_State *L, StkId p1, StkId p2); +LUAI_FUNC void luaG_aritherror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...); +LUAI_FUNC void luaG_errormsg (lua_State *L); +LUAI_FUNC int luaG_checkcode (const Proto *pt); +LUAI_FUNC int luaG_checkopenop (Instruction i); + +#endif diff --git a/lua/src/ldo.c b/lua/src/ldo.c new file mode 100644 index 0000000000..8de05f728e --- /dev/null +++ b/lua/src/ldo.c @@ -0,0 +1,518 @@ +/* +** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +#define ldo_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" +#include "lzio.h" + + + + +/* +** {====================================================== +** Error-recovery functions +** ======================================================= +*/ + + +/* chain list of long jump buffers */ +struct lua_longjmp { + struct lua_longjmp *previous; + luai_jmpbuf b; + volatile int status; /* error code */ +}; + + +void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { + switch (errcode) { + case LUA_ERRMEM: { + setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); + break; + } + case LUA_ERRERR: { + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); + break; + } + case LUA_ERRSYNTAX: + case LUA_ERRRUN: { + setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ + break; + } + } + L->top = oldtop + 1; +} + + +static void restore_stack_limit (lua_State *L) { + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); + if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ + int inuse = cast_int(L->ci - L->base_ci); + if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ + luaD_reallocCI(L, LUAI_MAXCALLS); + } +} + + +static void resetstack (lua_State *L, int status) { + L->ci = L->base_ci; + L->base = L->ci->base; + luaF_close(L, L->base); /* close eventual pending closures */ + luaD_seterrorobj(L, status, L->base); + L->nCcalls = L->baseCcalls; + L->allowhook = 1; + restore_stack_limit(L); + L->errfunc = 0; + L->errorJmp = NULL; +} + + +void luaD_throw (lua_State *L, int errcode) { + if (L->errorJmp) { + L->errorJmp->status = errcode; + LUAI_THROW(L, L->errorJmp); + } + else { + L->status = cast_byte(errcode); + if (G(L)->panic) { + resetstack(L, errcode); + lua_unlock(L); + G(L)->panic(L); + } + exit(EXIT_FAILURE); + } +} + + +int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { + struct lua_longjmp lj; + lj.status = 0; + lj.previous = L->errorJmp; /* chain new error handler */ + L->errorJmp = &lj; + LUAI_TRY(L, &lj, + (*f)(L, ud); + ); + L->errorJmp = lj.previous; /* restore old error handler */ + return lj.status; +} + +/* }====================================================== */ + + +static void correctstack (lua_State *L, TValue *oldstack) { + CallInfo *ci; + GCObject *up; + L->top = (L->top - oldstack) + L->stack; + for (up = L->openupval; up != NULL; up = up->gch.next) + gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; + for (ci = L->base_ci; ci <= L->ci; ci++) { + ci->top = (ci->top - oldstack) + L->stack; + ci->base = (ci->base - oldstack) + L->stack; + ci->func = (ci->func - oldstack) + L->stack; + } + L->base = (L->base - oldstack) + L->stack; +} + + +void luaD_reallocstack (lua_State *L, int newsize) { + TValue *oldstack = L->stack; + int realsize = newsize + 1 + EXTRA_STACK; + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); + luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); + L->stacksize = realsize; + L->stack_last = L->stack+newsize; + correctstack(L, oldstack); +} + + +void luaD_reallocCI (lua_State *L, int newsize) { + CallInfo *oldci = L->base_ci; + luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); + L->size_ci = newsize; + L->ci = (L->ci - oldci) + L->base_ci; + L->end_ci = L->base_ci + L->size_ci - 1; +} + + +void luaD_growstack (lua_State *L, int n) { + if (n <= L->stacksize) /* double size is enough? */ + luaD_reallocstack(L, 2*L->stacksize); + else + luaD_reallocstack(L, L->stacksize + n); +} + + +static CallInfo *growCI (lua_State *L) { + if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ + luaD_throw(L, LUA_ERRERR); + else { + luaD_reallocCI(L, 2*L->size_ci); + if (L->size_ci > LUAI_MAXCALLS) + luaG_runerror(L, "stack overflow"); + } + return ++L->ci; +} + + +void luaD_callhook (lua_State *L, int event, int line) { + lua_Hook hook = L->hook; + if (hook && L->allowhook) { + ptrdiff_t top = savestack(L, L->top); + ptrdiff_t ci_top = savestack(L, L->ci->top); + lua_Debug ar; + ar.event = event; + ar.currentline = line; + if (event == LUA_HOOKTAILRET) + ar.i_ci = 0; /* tail call; no debug information about it */ + else + ar.i_ci = cast_int(L->ci - L->base_ci); + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + L->ci->top = L->top + LUA_MINSTACK; + lua_assert(L->ci->top <= L->stack_last); + L->allowhook = 0; /* cannot call hooks inside a hook */ + lua_unlock(L); + (*hook)(L, &ar); + lua_lock(L); + lua_assert(!L->allowhook); + L->allowhook = 1; + L->ci->top = restorestack(L, ci_top); + L->top = restorestack(L, top); + } +} + + +static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { + int i; + int nfixargs = p->numparams; + Table *htab = NULL; + StkId base, fixed; + for (; actual < nfixargs; ++actual) + setnilvalue(L->top++); +#if defined(LUA_COMPAT_VARARG) + if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ + int nvar = actual - nfixargs; /* number of extra arguments */ + lua_assert(p->is_vararg & VARARG_HASARG); + luaC_checkGC(L); + htab = luaH_new(L, nvar, 1); /* create `arg' table */ + for (i=0; itop - nvar + i); + /* store counter in field `n' */ + setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); + } +#endif + /* move fixed parameters to final position */ + fixed = L->top - actual; /* first fixed argument */ + base = L->top; /* final position of first argument */ + for (i=0; itop++, fixed+i); + setnilvalue(fixed+i); + } + /* add `arg' parameter */ + if (htab) { + sethvalue(L, L->top++, htab); + lua_assert(iswhite(obj2gco(htab))); + } + return base; +} + + +static StkId tryfuncTM (lua_State *L, StkId func) { + const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); + StkId p; + ptrdiff_t funcr = savestack(L, func); + if (!ttisfunction(tm)) + luaG_typeerror(L, func, "call"); + /* Open a hole inside the stack at `func' */ + for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); + incr_top(L); + func = restorestack(L, funcr); /* previous call may change stack */ + setobj2s(L, func, tm); /* tag method is the new function to be called */ + return func; +} + + + +#define inc_ci(L) \ + ((L->ci == L->end_ci) ? growCI(L) : \ + (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) + + +int luaD_precall (lua_State *L, StkId func, int nresults) { + LClosure *cl; + ptrdiff_t funcr; + if (!ttisfunction(func)) /* `func' is not a function? */ + func = tryfuncTM(L, func); /* check the `function' tag method */ + funcr = savestack(L, func); + cl = &clvalue(func)->l; + L->ci->savedpc = L->savedpc; + if (!cl->isC) { /* Lua function? prepare its call */ + CallInfo *ci; + StkId st, base; + Proto *p = cl->p; + luaD_checkstack(L, p->maxstacksize); + func = restorestack(L, funcr); + if (!p->is_vararg) { /* no varargs? */ + base = func + 1; + if (L->top > base + p->numparams) + L->top = base + p->numparams; + } + else { /* vararg function */ + int nargs = cast_int(L->top - func) - 1; + base = adjust_varargs(L, p, nargs); + func = restorestack(L, funcr); /* previous call may change the stack */ + } + ci = inc_ci(L); /* now `enter' new function */ + ci->func = func; + L->base = ci->base = base; + ci->top = L->base + p->maxstacksize; + lua_assert(ci->top <= L->stack_last); + L->savedpc = p->code; /* starting point */ + ci->tailcalls = 0; + ci->nresults = nresults; + for (st = L->top; st < ci->top; st++) + setnilvalue(st); + L->top = ci->top; + if (L->hookmask & LUA_MASKCALL) { + L->savedpc++; /* hooks assume 'pc' is already incremented */ + luaD_callhook(L, LUA_HOOKCALL, -1); + L->savedpc--; /* correct 'pc' */ + } + return PCRLUA; + } + else { /* if is a C function, call it */ + CallInfo *ci; + int n; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + ci = inc_ci(L); /* now `enter' new function */ + ci->func = restorestack(L, funcr); + L->base = ci->base = ci->func + 1; + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + ci->nresults = nresults; + if (L->hookmask & LUA_MASKCALL) + luaD_callhook(L, LUA_HOOKCALL, -1); + lua_unlock(L); + n = (*curr_func(L)->c.f)(L); /* do the actual call */ + lua_lock(L); + if (n < 0) /* yielding? */ + return PCRYIELD; + else { + luaD_poscall(L, L->top - n); + return PCRC; + } + } +} + + +static StkId callrethooks (lua_State *L, StkId firstResult) { + ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ + luaD_callhook(L, LUA_HOOKRET, -1); + if (f_isLua(L->ci)) { /* Lua function? */ + while ((L->hookmask & LUA_MASKRET) && L->ci->tailcalls--) /* tail calls */ + luaD_callhook(L, LUA_HOOKTAILRET, -1); + } + return restorestack(L, fr); +} + + +int luaD_poscall (lua_State *L, StkId firstResult) { + StkId res; + int wanted, i; + CallInfo *ci; + if (L->hookmask & LUA_MASKRET) + firstResult = callrethooks(L, firstResult); + ci = L->ci--; + res = ci->func; /* res == final position of 1st result */ + wanted = ci->nresults; + L->base = (ci - 1)->base; /* restore base */ + L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ + /* move results to correct place */ + for (i = wanted; i != 0 && firstResult < L->top; i--) + setobjs2s(L, res++, firstResult++); + while (i-- > 0) + setnilvalue(res++); + L->top = res; + return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ +} + + +/* +** Call a function (C or Lua). The function to be called is at *func. +** The arguments are on the stack, right after the function. +** When returns, all the results are on the stack, starting at the original +** function position. +*/ +void luaD_call (lua_State *L, StkId func, int nResults) { + if (++L->nCcalls >= LUAI_MAXCCALLS) { + if (L->nCcalls == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ + } + if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ + luaV_execute(L, 1); /* call it */ + L->nCcalls--; + luaC_checkGC(L); +} + + +static void resume (lua_State *L, void *ud) { + StkId firstArg = cast(StkId, ud); + CallInfo *ci = L->ci; + if (L->status == 0) { /* start coroutine? */ + lua_assert(ci == L->base_ci && firstArg > L->base); + if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) + return; + } + else { /* resuming from previous yield */ + lua_assert(L->status == LUA_YIELD); + L->status = 0; + if (!f_isLua(ci)) { /* `common' yield? */ + /* finish interrupted execution of `OP_CALL' */ + lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || + GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); + if (luaD_poscall(L, firstArg)) /* complete it... */ + L->top = L->ci->top; /* and correct top if not multiple results */ + } + else /* yielded inside a hook: just continue its execution */ + L->base = L->ci->base; + } + luaV_execute(L, cast_int(L->ci - L->base_ci)); +} + + +static int resume_error (lua_State *L, const char *msg) { + L->top = L->ci->base; + setsvalue2s(L, L->top, luaS_new(L, msg)); + incr_top(L); + lua_unlock(L); + return LUA_ERRRUN; +} + + +LUA_API int lua_resume (lua_State *L, int nargs) { + int status; + lua_lock(L); + if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci)) + return resume_error(L, "cannot resume non-suspended coroutine"); + if (L->nCcalls >= LUAI_MAXCCALLS) + return resume_error(L, "C stack overflow"); + luai_userstateresume(L, nargs); + lua_assert(L->errfunc == 0); + L->baseCcalls = ++L->nCcalls; + status = luaD_rawrunprotected(L, resume, L->top - nargs); + if (status != 0) { /* error? */ + L->status = cast_byte(status); /* mark thread as `dead' */ + luaD_seterrorobj(L, status, L->top); + L->ci->top = L->top; + } + else { + lua_assert(L->nCcalls == L->baseCcalls); + status = L->status; + } + --L->nCcalls; + lua_unlock(L); + return status; +} + + +LUA_API int lua_yield (lua_State *L, int nresults) { + luai_userstateyield(L, nresults); + lua_lock(L); + if (L->nCcalls > L->baseCcalls) + luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); + L->base = L->top - nresults; /* protect stack slots below */ + L->status = LUA_YIELD; + lua_unlock(L); + return -1; +} + + +int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t old_top, ptrdiff_t ef) { + int status; + unsigned short oldnCcalls = L->nCcalls; + ptrdiff_t old_ci = saveci(L, L->ci); + lu_byte old_allowhooks = L->allowhook; + ptrdiff_t old_errfunc = L->errfunc; + L->errfunc = ef; + status = luaD_rawrunprotected(L, func, u); + if (status != 0) { /* an error occurred? */ + StkId oldtop = restorestack(L, old_top); + luaF_close(L, oldtop); /* close eventual pending closures */ + luaD_seterrorobj(L, status, oldtop); + L->nCcalls = oldnCcalls; + L->ci = restoreci(L, old_ci); + L->base = L->ci->base; + L->savedpc = L->ci->savedpc; + L->allowhook = old_allowhooks; + restore_stack_limit(L); + } + L->errfunc = old_errfunc; + return status; +} + + + +/* +** Execute a protected parser. +*/ +struct SParser { /* data to `f_parser' */ + ZIO *z; + Mbuffer buff; /* buffer to be used by the scanner */ + const char *name; +}; + +static void f_parser (lua_State *L, void *ud) { + int i; + Proto *tf; + Closure *cl; + struct SParser *p = cast(struct SParser *, ud); + int c = luaZ_lookahead(p->z); + luaC_checkGC(L); + tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, + &p->buff, p->name); + cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); + cl->l.p = tf; + for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ + cl->l.upvals[i] = luaF_newupval(L); + setclvalue(L, L->top, cl); + incr_top(L); +} + + +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { + struct SParser p; + int status; + p.z = z; p.name = name; + luaZ_initbuffer(L, &p.buff); + status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); + luaZ_freebuffer(L, &p.buff); + return status; +} + + diff --git a/lua/src/ldo.h b/lua/src/ldo.h new file mode 100644 index 0000000000..98fddac59f --- /dev/null +++ b/lua/src/ldo.h @@ -0,0 +1,57 @@ +/* +** $Id: ldo.h,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#ifndef ldo_h +#define ldo_h + + +#include "lobject.h" +#include "lstate.h" +#include "lzio.h" + + +#define luaD_checkstack(L,n) \ + if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ + luaD_growstack(L, n); \ + else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); + + +#define incr_top(L) {luaD_checkstack(L,1); L->top++;} + +#define savestack(L,p) ((char *)(p) - (char *)L->stack) +#define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) + +#define saveci(L,p) ((char *)(p) - (char *)L->base_ci) +#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) + + +/* results from luaD_precall */ +#define PCRLUA 0 /* initiated a call to a Lua function */ +#define PCRC 1 /* did a call to a C function */ +#define PCRYIELD 2 /* C funtion yielded */ + + +/* type of protected functions, to be ran by `runprotected' */ +typedef void (*Pfunc) (lua_State *L, void *ud); + +LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); +LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); +LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); +LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t oldtop, ptrdiff_t ef); +LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); +LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize); +LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); +LUAI_FUNC void luaD_growstack (lua_State *L, int n); + +LUAI_FUNC void luaD_throw (lua_State *L, int errcode); +LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); + +LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); + +#endif + diff --git a/lua/src/ldump.c b/lua/src/ldump.c new file mode 100644 index 0000000000..c9d3d4870f --- /dev/null +++ b/lua/src/ldump.c @@ -0,0 +1,164 @@ +/* +** $Id: ldump.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ +** save precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#include + +#define ldump_c +#define LUA_CORE + +#include "lua.h" + +#include "lobject.h" +#include "lstate.h" +#include "lundump.h" + +typedef struct { + lua_State* L; + lua_Writer writer; + void* data; + int strip; + int status; +} DumpState; + +#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) +#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) + +static void DumpBlock(const void* b, size_t size, DumpState* D) +{ + if (D->status==0) + { + lua_unlock(D->L); + D->status=(*D->writer)(D->L,b,size,D->data); + lua_lock(D->L); + } +} + +static void DumpChar(int y, DumpState* D) +{ + char x=(char)y; + DumpVar(x,D); +} + +static void DumpInt(int x, DumpState* D) +{ + DumpVar(x,D); +} + +static void DumpNumber(lua_Number x, DumpState* D) +{ + DumpVar(x,D); +} + +static void DumpVector(const void* b, int n, size_t size, DumpState* D) +{ + DumpInt(n,D); + DumpMem(b,n,size,D); +} + +static void DumpString(const TString* s, DumpState* D) +{ + if (s==NULL || getstr(s)==NULL) + { + size_t size=0; + DumpVar(size,D); + } + else + { + size_t size=s->tsv.len+1; /* include trailing '\0' */ + DumpVar(size,D); + DumpBlock(getstr(s),size,D); + } +} + +#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) + +static void DumpFunction(const Proto* f, const TString* p, DumpState* D); + +static void DumpConstants(const Proto* f, DumpState* D) +{ + int i,n=f->sizek; + DumpInt(n,D); + for (i=0; ik[i]; + DumpChar(ttype(o),D); + switch (ttype(o)) + { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpChar(bvalue(o),D); + break; + case LUA_TNUMBER: + DumpNumber(nvalue(o),D); + break; + case LUA_TSTRING: + DumpString(rawtsvalue(o),D); + break; + default: + lua_assert(0); /* cannot happen */ + break; + } + } + n=f->sizep; + DumpInt(n,D); + for (i=0; ip[i],f->source,D); +} + +static void DumpDebug(const Proto* f, DumpState* D) +{ + int i,n; + n= (D->strip) ? 0 : f->sizelineinfo; + DumpVector(f->lineinfo,n,sizeof(int),D); + n= (D->strip) ? 0 : f->sizelocvars; + DumpInt(n,D); + for (i=0; ilocvars[i].varname,D); + DumpInt(f->locvars[i].startpc,D); + DumpInt(f->locvars[i].endpc,D); + } + n= (D->strip) ? 0 : f->sizeupvalues; + DumpInt(n,D); + for (i=0; iupvalues[i],D); +} + +static void DumpFunction(const Proto* f, const TString* p, DumpState* D) +{ + DumpString((f->source==p || D->strip) ? NULL : f->source,D); + DumpInt(f->linedefined,D); + DumpInt(f->lastlinedefined,D); + DumpChar(f->nups,D); + DumpChar(f->numparams,D); + DumpChar(f->is_vararg,D); + DumpChar(f->maxstacksize,D); + DumpCode(f,D); + DumpConstants(f,D); + DumpDebug(f,D); +} + +static void DumpHeader(DumpState* D) +{ + char h[LUAC_HEADERSIZE]; + luaU_header(h); + DumpBlock(h,LUAC_HEADERSIZE,D); +} + +/* +** dump Lua function as precompiled chunk +*/ +int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) +{ + DumpState D; + D.L=L; + D.writer=w; + D.data=data; + D.strip=strip; + D.status=0; + DumpHeader(&D); + DumpFunction(f,NULL,&D); + return D.status; +} diff --git a/lua/src/lfunc.c b/lua/src/lfunc.c new file mode 100644 index 0000000000..813e88f583 --- /dev/null +++ b/lua/src/lfunc.c @@ -0,0 +1,174 @@ +/* +** $Id: lfunc.c,v 2.12.1.2 2007/12/28 14:58:43 roberto Exp $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + + +#include + +#define lfunc_c +#define LUA_CORE + +#include "lua.h" + +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { + Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); + c->c.isC = 1; + c->c.env = e; + c->c.nupvalues = cast_byte(nelems); + return c; +} + + +Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) { + Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); + c->l.isC = 0; + c->l.env = e; + c->l.nupvalues = cast_byte(nelems); + while (nelems--) c->l.upvals[nelems] = NULL; + return c; +} + + +UpVal *luaF_newupval (lua_State *L) { + UpVal *uv = luaM_new(L, UpVal); + luaC_link(L, obj2gco(uv), LUA_TUPVAL); + uv->v = &uv->u.value; + setnilvalue(uv->v); + return uv; +} + + +UpVal *luaF_findupval (lua_State *L, StkId level) { + global_State *g = G(L); + GCObject **pp = &L->openupval; + UpVal *p; + UpVal *uv; + while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) { + lua_assert(p->v != &p->u.value); + if (p->v == level) { /* found a corresponding upvalue? */ + if (isdead(g, obj2gco(p))) /* is it dead? */ + changewhite(obj2gco(p)); /* ressurect it */ + return p; + } + pp = &p->next; + } + uv = luaM_new(L, UpVal); /* not found: create a new one */ + uv->tt = LUA_TUPVAL; + uv->marked = luaC_white(g); + uv->v = level; /* current value lives in the stack */ + uv->next = *pp; /* chain it in the proper position */ + *pp = obj2gco(uv); + uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ + uv->u.l.next = g->uvhead.u.l.next; + uv->u.l.next->u.l.prev = uv; + g->uvhead.u.l.next = uv; + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + return uv; +} + + +static void unlinkupval (UpVal *uv) { + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */ + uv->u.l.prev->u.l.next = uv->u.l.next; +} + + +void luaF_freeupval (lua_State *L, UpVal *uv) { + if (uv->v != &uv->u.value) /* is it open? */ + unlinkupval(uv); /* remove from open list */ + luaM_free(L, uv); /* free upvalue */ +} + + +void luaF_close (lua_State *L, StkId level) { + UpVal *uv; + global_State *g = G(L); + while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) { + GCObject *o = obj2gco(uv); + lua_assert(!isblack(o) && uv->v != &uv->u.value); + L->openupval = uv->next; /* remove from `open' list */ + if (isdead(g, o)) + luaF_freeupval(L, uv); /* free upvalue */ + else { + unlinkupval(uv); + setobj(L, &uv->u.value, uv->v); + uv->v = &uv->u.value; /* now current value lives here */ + luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ + } + } +} + + +Proto *luaF_newproto (lua_State *L) { + Proto *f = luaM_new(L, Proto); + luaC_link(L, obj2gco(f), LUA_TPROTO); + f->k = NULL; + f->sizek = 0; + f->p = NULL; + f->sizep = 0; + f->code = NULL; + f->sizecode = 0; + f->sizelineinfo = 0; + f->sizeupvalues = 0; + f->nups = 0; + f->upvalues = NULL; + f->numparams = 0; + f->is_vararg = 0; + f->maxstacksize = 0; + f->lineinfo = NULL; + f->sizelocvars = 0; + f->locvars = NULL; + f->linedefined = 0; + f->lastlinedefined = 0; + f->source = NULL; + return f; +} + + +void luaF_freeproto (lua_State *L, Proto *f) { + luaM_freearray(L, f->code, f->sizecode, Instruction); + luaM_freearray(L, f->p, f->sizep, Proto *); + luaM_freearray(L, f->k, f->sizek, TValue); + luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); + luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); + luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); + luaM_free(L, f); +} + + +void luaF_freeclosure (lua_State *L, Closure *c) { + int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : + sizeLclosure(c->l.nupvalues); + luaM_freemem(L, c, size); +} + + +/* +** Look for n-th local variable at line `line' in function `func'. +** Returns NULL if not found. +*/ +const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { + int i; + for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { + if (pc < f->locvars[i].endpc) { /* is variable active? */ + local_number--; + if (local_number == 0) + return getstr(f->locvars[i].varname); + } + } + return NULL; /* not found */ +} + diff --git a/lua/src/lfunc.h b/lua/src/lfunc.h new file mode 100644 index 0000000000..a68cf5151c --- /dev/null +++ b/lua/src/lfunc.h @@ -0,0 +1,34 @@ +/* +** $Id: lfunc.h,v 2.4.1.1 2007/12/27 13:02:25 roberto Exp $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + +#ifndef lfunc_h +#define lfunc_h + + +#include "lobject.h" + + +#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ + cast(int, sizeof(TValue)*((n)-1))) + +#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ + cast(int, sizeof(TValue *)*((n)-1))) + + +LUAI_FUNC Proto *luaF_newproto (lua_State *L); +LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); +LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); +LUAI_FUNC UpVal *luaF_newupval (lua_State *L); +LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); +LUAI_FUNC void luaF_close (lua_State *L, StkId level); +LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); +LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c); +LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); +LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, + int pc); + + +#endif diff --git a/lua/src/lgc.c b/lua/src/lgc.c new file mode 100644 index 0000000000..d9e0b78294 --- /dev/null +++ b/lua/src/lgc.c @@ -0,0 +1,711 @@ +/* +** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#include + +#define lgc_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +#define GCSTEPSIZE 1024u +#define GCSWEEPMAX 40 +#define GCSWEEPCOST 10 +#define GCFINALIZECOST 100 + + +#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) + +#define makewhite(g,x) \ + ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) + +#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) + +#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) + + +#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) +#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) + + +#define KEYWEAK bitmask(KEYWEAKBIT) +#define VALUEWEAK bitmask(VALUEWEAKBIT) + + + +#define markvalue(g,o) { checkconsistency(o); \ + if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } + +#define markobject(g,t) { if (iswhite(obj2gco(t))) \ + reallymarkobject(g, obj2gco(t)); } + + +#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) + + +static void removeentry (Node *n) { + lua_assert(ttisnil(gval(n))); + if (iscollectable(gkey(n))) + setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ +} + + +static void reallymarkobject (global_State *g, GCObject *o) { + lua_assert(iswhite(o) && !isdead(g, o)); + white2gray(o); + switch (o->gch.tt) { + case LUA_TSTRING: { + return; + } + case LUA_TUSERDATA: { + Table *mt = gco2u(o)->metatable; + gray2black(o); /* udata are never gray */ + if (mt) markobject(g, mt); + markobject(g, gco2u(o)->env); + return; + } + case LUA_TUPVAL: { + UpVal *uv = gco2uv(o); + markvalue(g, uv->v); + if (uv->v == &uv->u.value) /* closed? */ + gray2black(o); /* open upvalues are never black */ + return; + } + case LUA_TFUNCTION: { + gco2cl(o)->c.gclist = g->gray; + g->gray = o; + break; + } + case LUA_TTABLE: { + gco2h(o)->gclist = g->gray; + g->gray = o; + break; + } + case LUA_TTHREAD: { + gco2th(o)->gclist = g->gray; + g->gray = o; + break; + } + case LUA_TPROTO: { + gco2p(o)->gclist = g->gray; + g->gray = o; + break; + } + default: lua_assert(0); + } +} + + +static void marktmu (global_State *g) { + GCObject *u = g->tmudata; + if (u) { + do { + u = u->gch.next; + makewhite(g, u); /* may be marked, if left from previous GC */ + reallymarkobject(g, u); + } while (u != g->tmudata); + } +} + + +/* move `dead' udata that need finalization to list `tmudata' */ +size_t luaC_separateudata (lua_State *L, int all) { + global_State *g = G(L); + size_t deadmem = 0; + GCObject **p = &g->mainthread->next; + GCObject *curr; + while ((curr = *p) != NULL) { + if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) + p = &curr->gch.next; /* don't bother with them */ + else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { + markfinalized(gco2u(curr)); /* don't need finalization */ + p = &curr->gch.next; + } + else { /* must call its gc method */ + deadmem += sizeudata(gco2u(curr)); + markfinalized(gco2u(curr)); + *p = curr->gch.next; + /* link `curr' at the end of `tmudata' list */ + if (g->tmudata == NULL) /* list is empty? */ + g->tmudata = curr->gch.next = curr; /* creates a circular list */ + else { + curr->gch.next = g->tmudata->gch.next; + g->tmudata->gch.next = curr; + g->tmudata = curr; + } + } + } + return deadmem; +} + + +static int traversetable (global_State *g, Table *h) { + int i; + int weakkey = 0; + int weakvalue = 0; + const TValue *mode; + if (h->metatable) + markobject(g, h->metatable); + mode = gfasttm(g, h->metatable, TM_MODE); + if (mode && ttisstring(mode)) { /* is there a weak mode? */ + weakkey = (strchr(svalue(mode), 'k') != NULL); + weakvalue = (strchr(svalue(mode), 'v') != NULL); + if (weakkey || weakvalue) { /* is really weak? */ + h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ + h->marked |= cast_byte((weakkey << KEYWEAKBIT) | + (weakvalue << VALUEWEAKBIT)); + h->gclist = g->weak; /* must be cleared after GC, ... */ + g->weak = obj2gco(h); /* ... so put in the appropriate list */ + } + } + if (weakkey && weakvalue) return 1; + if (!weakvalue) { + i = h->sizearray; + while (i--) + markvalue(g, &h->array[i]); + } + i = sizenode(h); + while (i--) { + Node *n = gnode(h, i); + lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); + if (ttisnil(gval(n))) + removeentry(n); /* remove empty entries */ + else { + lua_assert(!ttisnil(gkey(n))); + if (!weakkey) markvalue(g, gkey(n)); + if (!weakvalue) markvalue(g, gval(n)); + } + } + return weakkey || weakvalue; +} + + +/* +** All marks are conditional because a GC may happen while the +** prototype is still being created +*/ +static void traverseproto (global_State *g, Proto *f) { + int i; + if (f->source) stringmark(f->source); + for (i=0; isizek; i++) /* mark literals */ + markvalue(g, &f->k[i]); + for (i=0; isizeupvalues; i++) { /* mark upvalue names */ + if (f->upvalues[i]) + stringmark(f->upvalues[i]); + } + for (i=0; isizep; i++) { /* mark nested protos */ + if (f->p[i]) + markobject(g, f->p[i]); + } + for (i=0; isizelocvars; i++) { /* mark local-variable names */ + if (f->locvars[i].varname) + stringmark(f->locvars[i].varname); + } +} + + + +static void traverseclosure (global_State *g, Closure *cl) { + markobject(g, cl->c.env); + if (cl->c.isC) { + int i; + for (i=0; ic.nupvalues; i++) /* mark its upvalues */ + markvalue(g, &cl->c.upvalue[i]); + } + else { + int i; + lua_assert(cl->l.nupvalues == cl->l.p->nups); + markobject(g, cl->l.p); + for (i=0; il.nupvalues; i++) /* mark its upvalues */ + markobject(g, cl->l.upvals[i]); + } +} + + +static void checkstacksizes (lua_State *L, StkId max) { + int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */ + int s_used = cast_int(max - L->stack); /* part of stack in use */ + if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ + return; /* do not touch the stacks */ + if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) + luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ + condhardstacktests(luaD_reallocCI(L, ci_used + 1)); + if (4*s_used < L->stacksize && + 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) + luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ + condhardstacktests(luaD_reallocstack(L, s_used)); +} + + +static void traversestack (global_State *g, lua_State *l) { + StkId o, lim; + CallInfo *ci; + markvalue(g, gt(l)); + lim = l->top; + for (ci = l->base_ci; ci <= l->ci; ci++) { + lua_assert(ci->top <= l->stack_last); + if (lim < ci->top) lim = ci->top; + } + for (o = l->stack; o < l->top; o++) + markvalue(g, o); + for (; o <= lim; o++) + setnilvalue(o); + checkstacksizes(l, lim); +} + + +/* +** traverse one gray object, turning it to black. +** Returns `quantity' traversed. +*/ +static l_mem propagatemark (global_State *g) { + GCObject *o = g->gray; + lua_assert(isgray(o)); + gray2black(o); + switch (o->gch.tt) { + case LUA_TTABLE: { + Table *h = gco2h(o); + g->gray = h->gclist; + if (traversetable(g, h)) /* table is weak? */ + black2gray(o); /* keep it gray */ + return sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * sizenode(h); + } + case LUA_TFUNCTION: { + Closure *cl = gco2cl(o); + g->gray = cl->c.gclist; + traverseclosure(g, cl); + return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : + sizeLclosure(cl->l.nupvalues); + } + case LUA_TTHREAD: { + lua_State *th = gco2th(o); + g->gray = th->gclist; + th->gclist = g->grayagain; + g->grayagain = o; + black2gray(o); + traversestack(g, th); + return sizeof(lua_State) + sizeof(TValue) * th->stacksize + + sizeof(CallInfo) * th->size_ci; + } + case LUA_TPROTO: { + Proto *p = gco2p(o); + g->gray = p->gclist; + traverseproto(g, p); + return sizeof(Proto) + sizeof(Instruction) * p->sizecode + + sizeof(Proto *) * p->sizep + + sizeof(TValue) * p->sizek + + sizeof(int) * p->sizelineinfo + + sizeof(LocVar) * p->sizelocvars + + sizeof(TString *) * p->sizeupvalues; + } + default: lua_assert(0); return 0; + } +} + + +static size_t propagateall (global_State *g) { + size_t m = 0; + while (g->gray) m += propagatemark(g); + return m; +} + + +/* +** The next function tells whether a key or value can be cleared from +** a weak table. Non-collectable objects are never removed from weak +** tables. Strings behave as `values', so are never removed too. for +** other objects: if really collected, cannot keep them; for userdata +** being finalized, keep them in keys, but not in values +*/ +static int iscleared (const TValue *o, int iskey) { + if (!iscollectable(o)) return 0; + if (ttisstring(o)) { + stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ + return 0; + } + return iswhite(gcvalue(o)) || + (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); +} + + +/* +** clear collected entries from weaktables +*/ +static void cleartable (GCObject *l) { + while (l) { + Table *h = gco2h(l); + int i = h->sizearray; + lua_assert(testbit(h->marked, VALUEWEAKBIT) || + testbit(h->marked, KEYWEAKBIT)); + if (testbit(h->marked, VALUEWEAKBIT)) { + while (i--) { + TValue *o = &h->array[i]; + if (iscleared(o, 0)) /* value was collected? */ + setnilvalue(o); /* remove value */ + } + } + i = sizenode(h); + while (i--) { + Node *n = gnode(h, i); + if (!ttisnil(gval(n)) && /* non-empty entry? */ + (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* remove entry from table */ + } + } + l = h->gclist; + } +} + + +static void freeobj (lua_State *L, GCObject *o) { + switch (o->gch.tt) { + case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; + case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; + case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; + case LUA_TTABLE: luaH_free(L, gco2h(o)); break; + case LUA_TTHREAD: { + lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); + luaE_freethread(L, gco2th(o)); + break; + } + case LUA_TSTRING: { + G(L)->strt.nuse--; + luaM_freemem(L, o, sizestring(gco2ts(o))); + break; + } + case LUA_TUSERDATA: { + luaM_freemem(L, o, sizeudata(gco2u(o))); + break; + } + default: lua_assert(0); + } +} + + + +#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) + + +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { + GCObject *curr; + global_State *g = G(L); + int deadmask = otherwhite(g); + while ((curr = *p) != NULL && count-- > 0) { + if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ + sweepwholelist(L, &gco2th(curr)->openupval); + if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ + lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); + makewhite(g, curr); /* make it white (for next cycle) */ + p = &curr->gch.next; + } + else { /* must erase `curr' */ + lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); + *p = curr->gch.next; + if (curr == g->rootgc) /* is the first element of the list? */ + g->rootgc = curr->gch.next; /* adjust first */ + freeobj(L, curr); + } + } + return p; +} + + +static void checkSizes (lua_State *L) { + global_State *g = G(L); + /* check size of string hash */ + if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && + g->strt.size > MINSTRTABSIZE*2) + luaS_resize(L, g->strt.size/2); /* table is too big */ + /* check size of buffer */ + if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ + size_t newsize = luaZ_sizebuffer(&g->buff) / 2; + luaZ_resizebuffer(L, &g->buff, newsize); + } +} + + +static void GCTM (lua_State *L) { + global_State *g = G(L); + GCObject *o = g->tmudata->gch.next; /* get first element */ + Udata *udata = rawgco2u(o); + const TValue *tm; + /* remove udata from `tmudata' */ + if (o == g->tmudata) /* last element? */ + g->tmudata = NULL; + else + g->tmudata->gch.next = udata->uv.next; + udata->uv.next = g->mainthread->next; /* return it to `root' list */ + g->mainthread->next = o; + makewhite(g, o); + tm = fasttm(L, udata->uv.metatable, TM_GC); + if (tm != NULL) { + lu_byte oldah = L->allowhook; + lu_mem oldt = g->GCthreshold; + L->allowhook = 0; /* stop debug hooks during GC tag method */ + g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ + setobj2s(L, L->top, tm); + setuvalue(L, L->top+1, udata); + L->top += 2; + luaD_call(L, L->top - 2, 0); + L->allowhook = oldah; /* restore hooks */ + g->GCthreshold = oldt; /* restore threshold */ + } +} + + +/* +** Call all GC tag methods +*/ +void luaC_callGCTM (lua_State *L) { + while (G(L)->tmudata) + GCTM(L); +} + + +void luaC_freeall (lua_State *L) { + global_State *g = G(L); + int i; + g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */ + sweepwholelist(L, &g->rootgc); + for (i = 0; i < g->strt.size; i++) /* free all string lists */ + sweepwholelist(L, &g->strt.hash[i]); +} + + +static void markmt (global_State *g) { + int i; + for (i=0; imt[i]) markobject(g, g->mt[i]); +} + + +/* mark root set */ +static void markroot (lua_State *L) { + global_State *g = G(L); + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + markobject(g, g->mainthread); + /* make global table be traversed before main stack */ + markvalue(g, gt(g->mainthread)); + markvalue(g, registry(L)); + markmt(g); + g->gcstate = GCSpropagate; +} + + +static void remarkupvals (global_State *g) { + UpVal *uv; + for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + if (isgray(obj2gco(uv))) + markvalue(g, uv->v); + } +} + + +static void atomic (lua_State *L) { + global_State *g = G(L); + size_t udsize; /* total size of userdata to be finalized */ + /* remark occasional upvalues of (maybe) dead threads */ + remarkupvals(g); + /* traverse objects cautch by write barrier and by 'remarkupvals' */ + propagateall(g); + /* remark weak tables */ + g->gray = g->weak; + g->weak = NULL; + lua_assert(!iswhite(obj2gco(g->mainthread))); + markobject(g, L); /* mark running thread */ + markmt(g); /* mark basic metatables (again) */ + propagateall(g); + /* remark gray again */ + g->gray = g->grayagain; + g->grayagain = NULL; + propagateall(g); + udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ + marktmu(g); /* mark `preserved' userdata */ + udsize += propagateall(g); /* remark, to propagate `preserveness' */ + cleartable(g->weak); /* remove collected objects from weak tables */ + /* flip current white */ + g->currentwhite = cast_byte(otherwhite(g)); + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + g->gcstate = GCSsweepstring; + g->estimate = g->totalbytes - udsize; /* first estimate */ +} + + +static l_mem singlestep (lua_State *L) { + global_State *g = G(L); + /*lua_checkmemory(L);*/ + switch (g->gcstate) { + case GCSpause: { + markroot(L); /* start a new collection */ + return 0; + } + case GCSpropagate: { + if (g->gray) + return propagatemark(g); + else { /* no more `gray' objects */ + atomic(L); /* finish mark phase */ + return 0; + } + } + case GCSsweepstring: { + lu_mem old = g->totalbytes; + sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); + if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ + g->gcstate = GCSsweep; /* end sweep-string phase */ + lua_assert(old >= g->totalbytes); + g->estimate -= old - g->totalbytes; + return GCSWEEPCOST; + } + case GCSsweep: { + lu_mem old = g->totalbytes; + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + if (*g->sweepgc == NULL) { /* nothing more to sweep? */ + checkSizes(L); + g->gcstate = GCSfinalize; /* end sweep phase */ + } + lua_assert(old >= g->totalbytes); + g->estimate -= old - g->totalbytes; + return GCSWEEPMAX*GCSWEEPCOST; + } + case GCSfinalize: { + if (g->tmudata) { + GCTM(L); + if (g->estimate > GCFINALIZECOST) + g->estimate -= GCFINALIZECOST; + return GCFINALIZECOST; + } + else { + g->gcstate = GCSpause; /* end collection */ + g->gcdept = 0; + return 0; + } + } + default: lua_assert(0); return 0; + } +} + + +void luaC_step (lua_State *L) { + global_State *g = G(L); + l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; + if (lim == 0) + lim = (MAX_LUMEM-1)/2; /* no limit */ + g->gcdept += g->totalbytes - g->GCthreshold; + do { + lim -= singlestep(L); + if (g->gcstate == GCSpause) + break; + } while (lim > 0); + if (g->gcstate != GCSpause) { + if (g->gcdept < GCSTEPSIZE) + g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/ + else { + g->gcdept -= GCSTEPSIZE; + g->GCthreshold = g->totalbytes; + } + } + else { + lua_assert(g->totalbytes >= g->estimate); + setthreshold(g); + } +} + + +void luaC_fullgc (lua_State *L) { + global_State *g = G(L); + if (g->gcstate <= GCSpropagate) { + /* reset sweep marks to sweep all elements (returning them to white) */ + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + /* reset other collector lists */ + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + g->gcstate = GCSsweepstring; + } + lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); + /* finish any pending sweep phase */ + while (g->gcstate != GCSfinalize) { + lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); + singlestep(L); + } + markroot(L); + while (g->gcstate != GCSpause) { + singlestep(L); + } + setthreshold(g); +} + + +void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { + global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + lua_assert(ttype(&o->gch) != LUA_TTABLE); + /* must keep invariant? */ + if (g->gcstate == GCSpropagate) + reallymarkobject(g, v); /* restore invariant */ + else /* don't mind */ + makewhite(g, o); /* mark as white just to avoid other barriers */ +} + + +void luaC_barrierback (lua_State *L, Table *t) { + global_State *g = G(L); + GCObject *o = obj2gco(t); + lua_assert(isblack(o) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + black2gray(o); /* make table gray (again) */ + t->gclist = g->grayagain; + g->grayagain = o; +} + + +void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { + global_State *g = G(L); + o->gch.next = g->rootgc; + g->rootgc = o; + o->gch.marked = luaC_white(g); + o->gch.tt = tt; +} + + +void luaC_linkupval (lua_State *L, UpVal *uv) { + global_State *g = G(L); + GCObject *o = obj2gco(uv); + o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ + g->rootgc = o; + if (isgray(o)) { + if (g->gcstate == GCSpropagate) { + gray2black(o); /* closed upvalues need barrier */ + luaC_barrier(L, uv, uv->v); + } + else { /* sweep phase: sweep it (turning it into white) */ + makewhite(g, o); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + } + } +} + diff --git a/lua/src/lgc.h b/lua/src/lgc.h new file mode 100644 index 0000000000..5a8dc605b3 --- /dev/null +++ b/lua/src/lgc.h @@ -0,0 +1,110 @@ +/* +** $Id: lgc.h,v 2.15.1.1 2007/12/27 13:02:25 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#ifndef lgc_h +#define lgc_h + + +#include "lobject.h" + + +/* +** Possible states of the Garbage Collector +*/ +#define GCSpause 0 +#define GCSpropagate 1 +#define GCSsweepstring 2 +#define GCSsweep 3 +#define GCSfinalize 4 + + +/* +** some userful bit tricks +*/ +#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) +#define setbits(x,m) ((x) |= (m)) +#define testbits(x,m) ((x) & (m)) +#define bitmask(b) (1<<(b)) +#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) +#define l_setbit(x,b) setbits(x, bitmask(b)) +#define resetbit(x,b) resetbits(x, bitmask(b)) +#define testbit(x,b) testbits(x, bitmask(b)) +#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) +#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) +#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2))) + + + +/* +** Layout for bit use in `marked' field: +** bit 0 - object is white (type 0) +** bit 1 - object is white (type 1) +** bit 2 - object is black +** bit 3 - for userdata: has been finalized +** bit 3 - for tables: has weak keys +** bit 4 - for tables: has weak values +** bit 5 - object is fixed (should not be collected) +** bit 6 - object is "super" fixed (only the main thread) +*/ + + +#define WHITE0BIT 0 +#define WHITE1BIT 1 +#define BLACKBIT 2 +#define FINALIZEDBIT 3 +#define KEYWEAKBIT 3 +#define VALUEWEAKBIT 4 +#define FIXEDBIT 5 +#define SFIXEDBIT 6 +#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) + + +#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define isblack(x) testbit((x)->gch.marked, BLACKBIT) +#define isgray(x) (!isblack(x) && !iswhite(x)) + +#define otherwhite(g) (g->currentwhite ^ WHITEBITS) +#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS) + +#define changewhite(x) ((x)->gch.marked ^= WHITEBITS) +#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) + +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) + +#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) + + +#define luaC_checkGC(L) { \ + condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ + if (G(L)->totalbytes >= G(L)->GCthreshold) \ + luaC_step(L); } + + +#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ + luaC_barrierf(L,obj2gco(p),gcvalue(v)); } + +#define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) \ + luaC_barrierback(L,t); } + +#define luaC_objbarrier(L,p,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ + luaC_barrierf(L,obj2gco(p),obj2gco(o)); } + +#define luaC_objbarriert(L,t,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } + +LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); +LUAI_FUNC void luaC_callGCTM (lua_State *L); +LUAI_FUNC void luaC_freeall (lua_State *L); +LUAI_FUNC void luaC_step (lua_State *L); +LUAI_FUNC void luaC_fullgc (lua_State *L); +LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt); +LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); +LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); +LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); + + +#endif diff --git a/lua/src/linit.c b/lua/src/linit.c new file mode 100644 index 0000000000..c1f90dfab7 --- /dev/null +++ b/lua/src/linit.c @@ -0,0 +1,38 @@ +/* +** $Id: linit.c,v 1.14.1.1 2007/12/27 13:02:25 roberto Exp $ +** Initialization of libraries for lua.c +** See Copyright Notice in lua.h +*/ + + +#define linit_c +#define LUA_LIB + +#include "lua.h" + +#include "lualib.h" +#include "lauxlib.h" + + +static const luaL_Reg lualibs[] = { + {"", luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_DBLIBNAME, luaopen_debug}, + {NULL, NULL} +}; + + +LUALIB_API void luaL_openlibs (lua_State *L) { + const luaL_Reg *lib = lualibs; + for (; lib->func; lib++) { + lua_pushcfunction(L, lib->func); + lua_pushstring(L, lib->name); + lua_call(L, 1, 0); + } +} + diff --git a/lua/src/liolib.c b/lua/src/liolib.c new file mode 100644 index 0000000000..e79ed1cb2e --- /dev/null +++ b/lua/src/liolib.c @@ -0,0 +1,553 @@ +/* +** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $ +** Standard I/O (and system) library +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define liolib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + +#define IO_INPUT 1 +#define IO_OUTPUT 2 + + +static const char *const fnames[] = {"input", "output"}; + + +static int pushresult (lua_State *L, int i, const char *filename) { + int en = errno; /* calls to Lua API may change this value */ + if (i) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + if (filename) + lua_pushfstring(L, "%s: %s", filename, strerror(en)); + else + lua_pushfstring(L, "%s", strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +static void fileerror (lua_State *L, int arg, const char *filename) { + lua_pushfstring(L, "%s: %s", filename, strerror(errno)); + luaL_argerror(L, arg, lua_tostring(L, -1)); +} + + +#define tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + + +static int io_type (lua_State *L) { + void *ud; + luaL_checkany(L, 1); + ud = lua_touserdata(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); + if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) + lua_pushnil(L); /* not a file */ + else if (*((FILE **)ud) == NULL) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; +} + + +static FILE *tofile (lua_State *L) { + FILE **f = tofilep(L); + if (*f == NULL) + luaL_error(L, "attempt to use a closed file"); + return *f; +} + + + +/* +** When creating file handles, always creates a `closed' file handle +** before opening the actual file; so, if there is a memory error, the +** file is not left opened. +*/ +static FILE **newfile (lua_State *L) { + FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); + *pf = NULL; /* file handle is currently `closed' */ + luaL_getmetatable(L, LUA_FILEHANDLE); + lua_setmetatable(L, -2); + return pf; +} + + +/* +** function to (not) close the standard files stdin, stdout, and stderr +*/ +static int io_noclose (lua_State *L) { + lua_pushnil(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; +} + + +/* +** function to close 'popen' files +*/ +static int io_pclose (lua_State *L) { + FILE **p = tofilep(L); + int ok = lua_pclose(L, *p); + *p = NULL; + return pushresult(L, ok, NULL); +} + + +/* +** function to close regular files +*/ +static int io_fclose (lua_State *L) { + FILE **p = tofilep(L); + int ok = (fclose(*p) == 0); + *p = NULL; + return pushresult(L, ok, NULL); +} + + +static int aux_close (lua_State *L) { + lua_getfenv(L, 1); + lua_getfield(L, -1, "__close"); + return (lua_tocfunction(L, -1))(L); +} + + +static int io_close (lua_State *L) { + if (lua_isnone(L, 1)) + lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); + tofile(L); /* make sure argument is a file */ + return aux_close(L); +} + + +static int io_gc (lua_State *L) { + FILE *f = *tofilep(L); + /* ignore closed files */ + if (f != NULL) + aux_close(L); + return 0; +} + + +static int io_tostring (lua_State *L) { + FILE *f = *tofilep(L); + if (f == NULL) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", f); + return 1; +} + + +static int io_open (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + FILE **pf = newfile(L); + *pf = fopen(filename, mode); + return (*pf == NULL) ? pushresult(L, 0, filename) : 1; +} + + +/* +** this function has a separated environment, which defines the +** correct __close for 'popen' files +*/ +static int io_popen (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + FILE **pf = newfile(L); + *pf = lua_popen(L, filename, mode); + return (*pf == NULL) ? pushresult(L, 0, filename) : 1; +} + + +static int io_tmpfile (lua_State *L) { + FILE **pf = newfile(L); + *pf = tmpfile(); + return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; +} + + +static FILE *getiofile (lua_State *L, int findex) { + FILE *f; + lua_rawgeti(L, LUA_ENVIRONINDEX, findex); + f = *(FILE **)lua_touserdata(L, -1); + if (f == NULL) + luaL_error(L, "standard %s file is closed", fnames[findex - 1]); + return f; +} + + +static int g_iofile (lua_State *L, int f, const char *mode) { + if (!lua_isnoneornil(L, 1)) { + const char *filename = lua_tostring(L, 1); + if (filename) { + FILE **pf = newfile(L); + *pf = fopen(filename, mode); + if (*pf == NULL) + fileerror(L, 1, filename); + } + else { + tofile(L); /* check that it's a valid file handle */ + lua_pushvalue(L, 1); + } + lua_rawseti(L, LUA_ENVIRONINDEX, f); + } + /* return current value */ + lua_rawgeti(L, LUA_ENVIRONINDEX, f); + return 1; +} + + +static int io_input (lua_State *L) { + return g_iofile(L, IO_INPUT, "r"); +} + + +static int io_output (lua_State *L) { + return g_iofile(L, IO_OUTPUT, "w"); +} + + +static int io_readline (lua_State *L); + + +static void aux_lines (lua_State *L, int idx, int toclose) { + lua_pushvalue(L, idx); + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_pushcclosure(L, io_readline, 2); +} + + +static int f_lines (lua_State *L) { + tofile(L); /* check that it's a valid file handle */ + aux_lines(L, 1, 0); + return 1; +} + + +static int io_lines (lua_State *L) { + if (lua_isnoneornil(L, 1)) { /* no arguments? */ + /* will iterate over default input */ + lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); + return f_lines(L); + } + else { + const char *filename = luaL_checkstring(L, 1); + FILE **pf = newfile(L); + *pf = fopen(filename, "r"); + if (*pf == NULL) + fileerror(L, 1, filename); + aux_lines(L, lua_gettop(L), 1); + return 1; + } +} + + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +static int read_number (lua_State *L, FILE *f) { + lua_Number d; + if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { + lua_pushnumber(L, d); + return 1; + } + else return 0; /* read fails */ +} + + +static int test_eof (lua_State *L, FILE *f) { + int c = getc(f); + ungetc(c, f); + lua_pushlstring(L, NULL, 0); + return (c != EOF); +} + + +static int read_line (lua_State *L, FILE *f) { + luaL_Buffer b; + luaL_buffinit(L, &b); + for (;;) { + size_t l; + char *p = luaL_prepbuffer(&b); + if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ + luaL_pushresult(&b); /* close buffer */ + return (lua_objlen(L, -1) > 0); /* check whether read something */ + } + l = strlen(p); + if (l == 0 || p[l-1] != '\n') + luaL_addsize(&b, l); + else { + luaL_addsize(&b, l - 1); /* do not include `eol' */ + luaL_pushresult(&b); /* close buffer */ + return 1; /* read at least an `eol' */ + } + } +} + + +static int read_chars (lua_State *L, FILE *f, size_t n) { + size_t rlen; /* how much to read */ + size_t nr; /* number of chars actually read */ + luaL_Buffer b; + luaL_buffinit(L, &b); + rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ + do { + char *p = luaL_prepbuffer(&b); + if (rlen > n) rlen = n; /* cannot read more than asked */ + nr = fread(p, sizeof(char), rlen, f); + luaL_addsize(&b, nr); + n -= nr; /* still have to read `n' chars */ + } while (n > 0 && nr == rlen); /* until end of count or eof */ + luaL_pushresult(&b); /* close buffer */ + return (n == 0 || lua_objlen(L, -1) > 0); +} + + +static int g_read (lua_State *L, FILE *f, int first) { + int nargs = lua_gettop(L) - 1; + int success; + int n; + clearerr(f); + if (nargs == 0) { /* no arguments? */ + success = read_line(L, f); + n = first+1; /* to return 1 result */ + } + else { /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = first; nargs-- && success; n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + size_t l = (size_t)lua_tointeger(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); + } + else { + const char *p = lua_tostring(L, n); + luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); + switch (p[1]) { + case 'n': /* number */ + success = read_number(L, f); + break; + case 'l': /* line */ + success = read_line(L, f); + break; + case 'a': /* file */ + read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)) + return pushresult(L, 0, NULL); + if (!success) { + lua_pop(L, 1); /* remove last result */ + lua_pushnil(L); /* push nil instead */ + } + return n - first; +} + + +static int io_read (lua_State *L) { + return g_read(L, getiofile(L, IO_INPUT), 1); +} + + +static int f_read (lua_State *L) { + return g_read(L, tofile(L), 2); +} + + +static int io_readline (lua_State *L) { + FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); + int sucess; + if (f == NULL) /* file is already closed? */ + luaL_error(L, "file is already closed"); + sucess = read_line(L, f); + if (ferror(f)) + return luaL_error(L, "%s", strerror(errno)); + if (sucess) return 1; + else { /* EOF */ + if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ + lua_settop(L, 0); + lua_pushvalue(L, lua_upvalueindex(1)); + aux_close(L); /* close it */ + } + return 0; + } +} + +/* }====================================================== */ + + +static int g_write (lua_State *L, FILE *f, int arg) { + int nargs = lua_gettop(L) - 1; + int status = 1; + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + status = status && + fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; + } + else { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + return pushresult(L, status, NULL); +} + + +static int io_write (lua_State *L) { + return g_write(L, getiofile(L, IO_OUTPUT), 1); +} + + +static int f_write (lua_State *L) { + return g_write(L, tofile(L), 2); +} + + +static int f_seek (lua_State *L) { + static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static const char *const modenames[] = {"set", "cur", "end", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, "cur", modenames); + long offset = luaL_optlong(L, 3, 0); + op = fseek(f, offset, mode[op]); + if (op) + return pushresult(L, 0, NULL); /* error */ + else { + lua_pushinteger(L, ftell(f)); + return 1; + } +} + + +static int f_setvbuf (lua_State *L) { + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char *const modenames[] = {"no", "full", "line", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, NULL, modenames); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + int res = setvbuf(f, NULL, mode[op], sz); + return pushresult(L, res == 0, NULL); +} + + + +static int io_flush (lua_State *L) { + return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); +} + + +static int f_flush (lua_State *L) { + return pushresult(L, fflush(tofile(L)) == 0, NULL); +} + + +static const luaL_Reg iolib[] = { + {"close", io_close}, + {"flush", io_flush}, + {"input", io_input}, + {"lines", io_lines}, + {"open", io_open}, + {"output", io_output}, + {"popen", io_popen}, + {"read", io_read}, + {"tmpfile", io_tmpfile}, + {"type", io_type}, + {"write", io_write}, + {NULL, NULL} +}; + + +static const luaL_Reg flib[] = { + {"close", io_close}, + {"flush", f_flush}, + {"lines", f_lines}, + {"read", f_read}, + {"seek", f_seek}, + {"setvbuf", f_setvbuf}, + {"write", f_write}, + {"__gc", io_gc}, + {"__tostring", io_tostring}, + {NULL, NULL} +}; + + +static void createmeta (lua_State *L) { + luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_register(L, NULL, flib); /* file methods */ +} + + +static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { + *newfile(L) = f; + if (k > 0) { + lua_pushvalue(L, -1); + lua_rawseti(L, LUA_ENVIRONINDEX, k); + } + lua_pushvalue(L, -2); /* copy environment */ + lua_setfenv(L, -2); /* set it */ + lua_setfield(L, -3, fname); +} + + +static void newfenv (lua_State *L, lua_CFunction cls) { + lua_createtable(L, 0, 1); + lua_pushcfunction(L, cls); + lua_setfield(L, -2, "__close"); +} + + +LUALIB_API int luaopen_io (lua_State *L) { + createmeta(L); + /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ + newfenv(L, io_fclose); + lua_replace(L, LUA_ENVIRONINDEX); + /* open library */ + luaL_register(L, LUA_IOLIBNAME, iolib); + /* create (and set) default files */ + newfenv(L, io_noclose); /* close function for default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, 0, "stderr"); + lua_pop(L, 1); /* pop environment for default files */ + lua_getfield(L, -1, "popen"); + newfenv(L, io_pclose); /* create environment for 'popen' */ + lua_setfenv(L, -2); /* set fenv for 'popen' */ + lua_pop(L, 1); /* pop 'popen' */ + return 1; +} + diff --git a/lua/src/llex.c b/lua/src/llex.c new file mode 100644 index 0000000000..f2c00d26e6 --- /dev/null +++ b/lua/src/llex.c @@ -0,0 +1,466 @@ +/* +** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +#define llex_c +#define LUA_CORE + +#include "lua.h" + +#include "ldo.h" +#include "llex.h" +#include "lobject.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "lzio.h" + + + +#define next(ls) (ls->current = zgetc(ls->z)) + + + + +#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') + + +/* ORDER RESERVED */ +const char *const luaX_tokens [] = { + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "if", + "in", "local", "nil", "not", "or", "repeat", + "return", "then", "true", "until", "while", + "..", "...", "==", ">=", "<=", "~=", + "", "", "", "", + NULL +}; + + +#define save_and_next(ls) (save(ls, ls->current), next(ls)) + + +static void save (LexState *ls, int c) { + Mbuffer *b = ls->buff; + if (b->n + 1 > b->buffsize) { + size_t newsize; + if (b->buffsize >= MAX_SIZET/2) + luaX_lexerror(ls, "lexical element too long", 0); + newsize = b->buffsize * 2; + luaZ_resizebuffer(ls->L, b, newsize); + } + b->buffer[b->n++] = cast(char, c); +} + + +void luaX_init (lua_State *L) { + int i; + for (i=0; itsv.reserved = cast_byte(i+1); /* reserved word */ + } +} + + +#define MAXSRC 80 + + +const char *luaX_token2str (LexState *ls, int token) { + if (token < FIRST_RESERVED) { + lua_assert(token == cast(unsigned char, token)); + return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : + luaO_pushfstring(ls->L, "%c", token); + } + else + return luaX_tokens[token-FIRST_RESERVED]; +} + + +static const char *txtToken (LexState *ls, int token) { + switch (token) { + case TK_NAME: + case TK_STRING: + case TK_NUMBER: + save(ls, '\0'); + return luaZ_buffer(ls->buff); + default: + return luaX_token2str(ls, token); + } +} + + +void luaX_lexerror (LexState *ls, const char *msg, int token) { + char buff[MAXSRC]; + luaO_chunkid(buff, getstr(ls->source), MAXSRC); + msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); + if (token) + luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); + luaD_throw(ls->L, LUA_ERRSYNTAX); +} + + +void luaX_syntaxerror (LexState *ls, const char *msg) { + luaX_lexerror(ls, msg, ls->t.token); +} + + +TString *luaX_newstring (LexState *ls, const char *str, size_t l) { + lua_State *L = ls->L; + TString *ts = luaS_newlstr(L, str, l); + TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ + if (ttisnil(o)) + setbvalue(o, 1); /* make sure `str' will not be collected */ + return ts; +} + + +static void inclinenumber (LexState *ls) { + int old = ls->current; + lua_assert(currIsNewline(ls)); + next(ls); /* skip `\n' or `\r' */ + if (currIsNewline(ls) && ls->current != old) + next(ls); /* skip `\n\r' or `\r\n' */ + if (++ls->linenumber >= MAX_INT) + luaX_syntaxerror(ls, "chunk has too many lines"); +} + + +void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { + ls->decpoint = '.'; + ls->L = L; + ls->lookahead.token = TK_EOS; /* no look-ahead token */ + ls->z = z; + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = source; + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ + next(ls); /* read first char */ +} + + + +/* +** ======================================================= +** LEXICAL ANALYZER +** ======================================================= +*/ + + + +static int check_next (LexState *ls, const char *set) { + if (!strchr(set, ls->current)) + return 0; + save_and_next(ls); + return 1; +} + + +static void buffreplace (LexState *ls, char from, char to) { + size_t n = luaZ_bufflen(ls->buff); + char *p = luaZ_buffer(ls->buff); + while (n--) + if (p[n] == from) p[n] = to; +} + + +static void trydecpoint (LexState *ls, SemInfo *seminfo) { + /* format error: try to update decimal point separator */ +#ifdef ANDROID + char old = ls->decpoint; + ls->decpoint = '.'; +#else + struct lconv *cv = localeconv(); + char old = ls->decpoint; + ls->decpoint = (cv ? cv->decimal_point[0] : '.'); +#endif + buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ + if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { + /* format error with correct decimal point: no more options */ + buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ + luaX_lexerror(ls, "malformed number", TK_NUMBER); + } +} + + +/* LUA_NUMBER */ +static void read_numeral (LexState *ls, SemInfo *seminfo) { + lua_assert(isdigit(ls->current)); + do { + save_and_next(ls); + } while (isdigit(ls->current) || ls->current == '.'); + if (check_next(ls, "Ee")) /* `E'? */ + check_next(ls, "+-"); /* optional exponent sign */ + while (isalnum(ls->current) || ls->current == '_') + save_and_next(ls); + save(ls, '\0'); + buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ + if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */ + trydecpoint(ls, seminfo); /* try to update decimal point separator */ +} + + +static int skip_sep (LexState *ls) { + int count = 0; + int s = ls->current; + lua_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls->current == '=') { + save_and_next(ls); + count++; + } + return (ls->current == s) ? count : (-count) - 1; +} + + +static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { + int cont = 0; + (void)(cont); /* avoid warnings when `cont' is not used */ + save_and_next(ls); /* skip 2nd `[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ + for (;;) { + switch (ls->current) { + case EOZ: + luaX_lexerror(ls, (seminfo) ? "unfinished long string" : + "unfinished long comment", TK_EOS); + break; /* to avoid warnings */ +#if defined(LUA_COMPAT_LSTR) + case '[': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd `[' */ + cont++; +#if LUA_COMPAT_LSTR == 1 + if (sep == 0) + luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); +#endif + } + break; + } +#endif + case ']': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd `]' */ +#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 + cont--; + if (sep == 0 && cont >= 0) break; +#endif + goto endloop; + } + break; + } + case '\n': + case '\r': { + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ + break; + } + default: { + if (seminfo) save_and_next(ls); + else next(ls); + } + } + } endloop: + if (seminfo) + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), + luaZ_bufflen(ls->buff) - 2*(2 + sep)); +} + + +static void read_string (LexState *ls, int del, SemInfo *seminfo) { + save_and_next(ls); + while (ls->current != del) { + switch (ls->current) { + case EOZ: + luaX_lexerror(ls, "unfinished string", TK_EOS); + continue; /* to avoid warnings */ + case '\n': + case '\r': + luaX_lexerror(ls, "unfinished string", TK_STRING); + continue; /* to avoid warnings */ + case '\\': { + int c; + next(ls); /* do not save the `\' */ + switch (ls->current) { + case 'a': c = '\a'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case '\n': /* go through */ + case '\r': save(ls, '\n'); inclinenumber(ls); continue; + case EOZ: continue; /* will raise an error next loop */ + default: { + if (!isdigit(ls->current)) + save_and_next(ls); /* handles \\, \", \', and \? */ + else { /* \xxx */ + int i = 0; + c = 0; + do { + c = 10*c + (ls->current-'0'); + next(ls); + } while (++i<3 && isdigit(ls->current)); + if (c > UCHAR_MAX) + luaX_lexerror(ls, "escape sequence too large", TK_STRING); + save(ls, c); + } + continue; + } + } + save(ls, c); + next(ls); + continue; + } + default: + save_and_next(ls); + } + } + save_and_next(ls); /* skip delimiter */ + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, + luaZ_bufflen(ls->buff) - 2); +} + + +static int llex (LexState *ls, SemInfo *seminfo) { + luaZ_resetbuffer(ls->buff); + for (;;) { + switch (ls->current) { + case '\n': + case '\r': { + inclinenumber(ls); + continue; + } + case '-': { + next(ls); + if (ls->current != '-') return '-'; + /* else is a comment */ + next(ls); + if (ls->current == '[') { + int sep = skip_sep(ls); + luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ + if (sep >= 0) { + read_long_string(ls, NULL, sep); /* long comment */ + luaZ_resetbuffer(ls->buff); + continue; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); + continue; + } + case '[': { + int sep = skip_sep(ls); + if (sep >= 0) { + read_long_string(ls, seminfo, sep); + return TK_STRING; + } + else if (sep == -1) return '['; + else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); + } + case '=': { + next(ls); + if (ls->current != '=') return '='; + else { next(ls); return TK_EQ; } + } + case '<': { + next(ls); + if (ls->current != '=') return '<'; + else { next(ls); return TK_LE; } + } + case '>': { + next(ls); + if (ls->current != '=') return '>'; + else { next(ls); return TK_GE; } + } + case '~': { + next(ls); + if (ls->current != '=') return '~'; + else { next(ls); return TK_NE; } + } + case '"': + case '\'': { + read_string(ls, ls->current, seminfo); + return TK_STRING; + } + case '.': { + save_and_next(ls); + if (check_next(ls, ".")) { + if (check_next(ls, ".")) + return TK_DOTS; /* ... */ + else return TK_CONCAT; /* .. */ + } + else if (!isdigit(ls->current)) return '.'; + else { + read_numeral(ls, seminfo); + return TK_NUMBER; + } + } + case EOZ: { + return TK_EOS; + } + default: { + if (isspace(ls->current)) { + lua_assert(!currIsNewline(ls)); + next(ls); + continue; + } + else if (isdigit(ls->current)) { + read_numeral(ls, seminfo); + return TK_NUMBER; + } + else if (isalpha(ls->current) || ls->current == '_') { + /* identifier or reserved word */ + TString *ts; + do { + save_and_next(ls); + } while (isalnum(ls->current) || ls->current == '_'); + ts = luaX_newstring(ls, luaZ_buffer(ls->buff), + luaZ_bufflen(ls->buff)); + if (ts->tsv.reserved > 0) /* reserved word? */ + return ts->tsv.reserved - 1 + FIRST_RESERVED; + else { + seminfo->ts = ts; + return TK_NAME; + } + } + else { + int c = ls->current; + next(ls); + return c; /* single-char tokens (+ - / ...) */ + } + } + } + } +} + + +void luaX_next (LexState *ls) { + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ + } + else + ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ +} + + +void luaX_lookahead (LexState *ls) { + lua_assert(ls->lookahead.token == TK_EOS); + ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); +} + diff --git a/lua/src/llex.h b/lua/src/llex.h new file mode 100644 index 0000000000..a9201cee48 --- /dev/null +++ b/lua/src/llex.h @@ -0,0 +1,81 @@ +/* +** $Id: llex.h,v 1.58.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +#ifndef llex_h +#define llex_h + +#include "lobject.h" +#include "lzio.h" + + +#define FIRST_RESERVED 257 + +/* maximum length of a reserved word */ +#define TOKEN_LEN (sizeof("function")/sizeof(char)) + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER RESERVED" +*/ +enum RESERVED { + /* terminal symbols denoted by reserved words */ + TK_AND = FIRST_RESERVED, TK_BREAK, + TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, + TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, + TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, + /* other terminal symbols */ + TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, + TK_NAME, TK_STRING, TK_EOS +}; + +/* number of reserved words */ +#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) + + +/* array with token `names' */ +LUAI_DATA const char *const luaX_tokens []; + + +typedef union { + lua_Number r; + TString *ts; +} SemInfo; /* semantics information */ + + +typedef struct Token { + int token; + SemInfo seminfo; +} Token; + + +typedef struct LexState { + int current; /* current character (charint) */ + int linenumber; /* input line counter */ + int lastline; /* line of last token `consumed' */ + Token t; /* current token */ + Token lookahead; /* look ahead token */ + struct FuncState *fs; /* `FuncState' is private to the parser */ + struct lua_State *L; + ZIO *z; /* input stream */ + Mbuffer *buff; /* buffer for tokens */ + TString *source; /* current source name */ + char decpoint; /* locale decimal point */ +} LexState; + + +LUAI_FUNC void luaX_init (lua_State *L); +LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, + TString *source); +LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); +LUAI_FUNC void luaX_next (LexState *ls); +LUAI_FUNC void luaX_lookahead (LexState *ls); +LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token); +LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s); +LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); + + +#endif diff --git a/lua/src/llimits.h b/lua/src/llimits.h new file mode 100644 index 0000000000..ca8dcb7224 --- /dev/null +++ b/lua/src/llimits.h @@ -0,0 +1,128 @@ +/* +** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $ +** Limits, basic types, and some other `installation-dependent' definitions +** See Copyright Notice in lua.h +*/ + +#ifndef llimits_h +#define llimits_h + + +#include +#include + + +#include "lua.h" + + +typedef LUAI_UINT32 lu_int32; + +typedef LUAI_UMEM lu_mem; + +typedef LUAI_MEM l_mem; + + + +/* chars used as small naturals (so that `char' is reserved for characters) */ +typedef unsigned char lu_byte; + + +#define MAX_SIZET ((size_t)(~(size_t)0)-2) + +#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) + + +#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ + +/* +** conversion of pointer to integer +** this is for hashing only; there is no problem if the integer +** cannot hold the whole pointer value +*/ +#define IntPoint(p) ((unsigned int)(lu_mem)(p)) + + + +/* type to ensure maximum alignment */ +typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; + + +/* result of a `usual argument conversion' over lua_Number */ +typedef LUAI_UACNUMBER l_uacNumber; + + +/* internal assertions for in-house debugging */ +#ifdef lua_assert + +#define check_exp(c,e) (lua_assert(c), (e)) +#define api_check(l,e) lua_assert(e) + +#else + +#define lua_assert(c) ((void)0) +#define check_exp(c,e) (e) +#define api_check luai_apicheck + +#endif + + +#ifndef UNUSED +#define UNUSED(x) ((void)(x)) /* to avoid warnings */ +#endif + + +#ifndef cast +#define cast(t, exp) ((t)(exp)) +#endif + +#define cast_byte(i) cast(lu_byte, (i)) +#define cast_num(i) cast(lua_Number, (i)) +#define cast_int(i) cast(int, (i)) + + + +/* +** type for virtual-machine instructions +** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) +*/ +typedef lu_int32 Instruction; + + + +/* maximum stack for a Lua function */ +#define MAXSTACK 250 + + + +/* minimum size for the string table (must be power of 2) */ +#ifndef MINSTRTABSIZE +#define MINSTRTABSIZE 32 +#endif + + +/* minimum size for string buffer */ +#ifndef LUA_MINBUFFER +#define LUA_MINBUFFER 32 +#endif + + +#ifndef lua_lock +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) +#endif + +#ifndef luai_threadyield +#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} +#endif + + +/* +** macro to control inclusion of some hard tests on stack reallocation +*/ +#ifndef HARDSTACKTESTS +#define condhardstacktests(x) ((void)0) +#else +#define condhardstacktests(x) x +#endif + +#endif diff --git a/lua/src/lmathlib.c b/lua/src/lmathlib.c new file mode 100644 index 0000000000..441fbf736c --- /dev/null +++ b/lua/src/lmathlib.c @@ -0,0 +1,263 @@ +/* +** $Id: lmathlib.c,v 1.67.1.1 2007/12/27 13:02:25 roberto Exp $ +** Standard mathematical library +** See Copyright Notice in lua.h +*/ + + +#include +#include + +#define lmathlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#undef PI +#define PI (3.14159265358979323846) +#define RADIANS_PER_DEGREE (PI/180.0) + + + +static int math_abs (lua_State *L) { + lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sin (lua_State *L) { + lua_pushnumber(L, sin(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sinh (lua_State *L) { + lua_pushnumber(L, sinh(luaL_checknumber(L, 1))); + return 1; +} + +static int math_cos (lua_State *L) { + lua_pushnumber(L, cos(luaL_checknumber(L, 1))); + return 1; +} + +static int math_cosh (lua_State *L) { + lua_pushnumber(L, cosh(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tan (lua_State *L) { + lua_pushnumber(L, tan(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tanh (lua_State *L) { + lua_pushnumber(L, tanh(luaL_checknumber(L, 1))); + return 1; +} + +static int math_asin (lua_State *L) { + lua_pushnumber(L, asin(luaL_checknumber(L, 1))); + return 1; +} + +static int math_acos (lua_State *L) { + lua_pushnumber(L, acos(luaL_checknumber(L, 1))); + return 1; +} + +static int math_atan (lua_State *L) { + lua_pushnumber(L, atan(luaL_checknumber(L, 1))); + return 1; +} + +static int math_atan2 (lua_State *L) { + lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + return 1; +} + +static int math_ceil (lua_State *L) { + lua_pushnumber(L, ceil(luaL_checknumber(L, 1))); + return 1; +} + +static int math_floor (lua_State *L) { + lua_pushnumber(L, floor(luaL_checknumber(L, 1))); + return 1; +} + +static int math_fmod (lua_State *L) { + lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + return 1; +} + +static int math_modf (lua_State *L) { + double ip; + double fp = modf(luaL_checknumber(L, 1), &ip); + lua_pushnumber(L, ip); + lua_pushnumber(L, fp); + return 2; +} + +static int math_sqrt (lua_State *L) { + lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); + return 1; +} + +static int math_pow (lua_State *L) { + lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + return 1; +} + +static int math_log (lua_State *L) { + lua_pushnumber(L, log(luaL_checknumber(L, 1))); + return 1; +} + +static int math_log10 (lua_State *L) { + lua_pushnumber(L, log10(luaL_checknumber(L, 1))); + return 1; +} + +static int math_exp (lua_State *L) { + lua_pushnumber(L, exp(luaL_checknumber(L, 1))); + return 1; +} + +static int math_deg (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); + return 1; +} + +static int math_rad (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); + return 1; +} + +static int math_frexp (lua_State *L) { + int e; + lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); + lua_pushinteger(L, e); + return 2; +} + +static int math_ldexp (lua_State *L) { + lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); + return 1; +} + + + +static int math_min (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + lua_Number dmin = luaL_checknumber(L, 1); + int i; + for (i=2; i<=n; i++) { + lua_Number d = luaL_checknumber(L, i); + if (d < dmin) + dmin = d; + } + lua_pushnumber(L, dmin); + return 1; +} + + +static int math_max (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + lua_Number dmax = luaL_checknumber(L, 1); + int i; + for (i=2; i<=n; i++) { + lua_Number d = luaL_checknumber(L, i); + if (d > dmax) + dmax = d; + } + lua_pushnumber(L, dmax); + return 1; +} + + +static int math_random (lua_State *L) { + /* the `%' avoids the (rare) case of r==1, and is needed also because on + some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ + lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; + switch (lua_gettop(L)) { /* check number of arguments */ + case 0: { /* no arguments */ + lua_pushnumber(L, r); /* Number between 0 and 1 */ + break; + } + case 1: { /* only upper limit */ + int u = luaL_checkint(L, 1); + luaL_argcheck(L, 1<=u, 1, "interval is empty"); + lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */ + break; + } + case 2: { /* lower and upper limits */ + int l = luaL_checkint(L, 1); + int u = luaL_checkint(L, 2); + luaL_argcheck(L, l<=u, 2, "interval is empty"); + lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */ + break; + } + default: return luaL_error(L, "wrong number of arguments"); + } + return 1; +} + + +static int math_randomseed (lua_State *L) { + srand(luaL_checkint(L, 1)); + return 0; +} + + +static const luaL_Reg mathlib[] = { + {"abs", math_abs}, + {"acos", math_acos}, + {"asin", math_asin}, + {"atan2", math_atan2}, + {"atan", math_atan}, + {"ceil", math_ceil}, + {"cosh", math_cosh}, + {"cos", math_cos}, + {"deg", math_deg}, + {"exp", math_exp}, + {"floor", math_floor}, + {"fmod", math_fmod}, + {"frexp", math_frexp}, + {"ldexp", math_ldexp}, + {"log10", math_log10}, + {"log", math_log}, + {"max", math_max}, + {"min", math_min}, + {"modf", math_modf}, + {"pow", math_pow}, + {"rad", math_rad}, + {"random", math_random}, + {"randomseed", math_randomseed}, + {"sinh", math_sinh}, + {"sin", math_sin}, + {"sqrt", math_sqrt}, + {"tanh", math_tanh}, + {"tan", math_tan}, + {NULL, NULL} +}; + + +/* +** Open math library +*/ +LUALIB_API int luaopen_math (lua_State *L) { + luaL_register(L, LUA_MATHLIBNAME, mathlib); + lua_pushnumber(L, PI); + lua_setfield(L, -2, "pi"); + lua_pushnumber(L, HUGE_VAL); + lua_setfield(L, -2, "huge"); +#if defined(LUA_COMPAT_MOD) + lua_getfield(L, -1, "fmod"); + lua_setfield(L, -2, "mod"); +#endif + return 1; +} + diff --git a/lua/src/lmem.c b/lua/src/lmem.c new file mode 100644 index 0000000000..ae7d8c965f --- /dev/null +++ b/lua/src/lmem.c @@ -0,0 +1,86 @@ +/* +** $Id: lmem.c,v 1.70.1.1 2007/12/27 13:02:25 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + + +#include + +#define lmem_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +/* +** About the realloc function: +** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); +** (`osize' is the old size, `nsize' is the new size) +** +** Lua ensures that (ptr == NULL) iff (osize == 0). +** +** * frealloc(ud, NULL, 0, x) creates a new block of size `x' +** +** * frealloc(ud, p, x, 0) frees the block `p' +** (in this specific case, frealloc must return NULL). +** particularly, frealloc(ud, NULL, 0, 0) does nothing +** (which is equivalent to free(NULL) in ANSI C) +** +** frealloc returns NULL if it cannot create or reallocate the area +** (any reallocation to an equal or smaller size cannot fail!) +*/ + + + +#define MINSIZEARRAY 4 + + +void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, + int limit, const char *errormsg) { + void *newblock; + int newsize; + if (*size >= limit/2) { /* cannot double it? */ + if (*size >= limit) /* cannot grow even a little? */ + luaG_runerror(L, errormsg); + newsize = limit; /* still have at least one free place */ + } + else { + newsize = (*size)*2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ + } + newblock = luaM_reallocv(L, block, *size, newsize, size_elems); + *size = newsize; /* update only when everything else is OK */ + return newblock; +} + + +void *luaM_toobig (lua_State *L) { + luaG_runerror(L, "memory allocation error: block too big"); + return NULL; /* to avoid warnings */ +} + + + +/* +** generic allocation routine. +*/ +void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { + global_State *g = G(L); + lua_assert((osize == 0) == (block == NULL)); + block = (*g->frealloc)(g->ud, block, osize, nsize); + if (block == NULL && nsize > 0) + luaD_throw(L, LUA_ERRMEM); + lua_assert((nsize == 0) == (block == NULL)); + g->totalbytes = (g->totalbytes - osize) + nsize; + return block; +} + diff --git a/lua/src/lmem.h b/lua/src/lmem.h new file mode 100644 index 0000000000..7c2dcb3220 --- /dev/null +++ b/lua/src/lmem.h @@ -0,0 +1,49 @@ +/* +** $Id: lmem.h,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#ifndef lmem_h +#define lmem_h + + +#include + +#include "llimits.h" +#include "lua.h" + +#define MEMERRMSG "not enough memory" + + +#define luaM_reallocv(L,b,on,n,e) \ + ((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ + luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \ + luaM_toobig(L)) + +#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) +#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) +#define luaM_freearray(L, b, n, t) luaM_reallocv(L, (b), n, 0, sizeof(t)) + +#define luaM_malloc(L,t) luaM_realloc_(L, NULL, 0, (t)) +#define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) +#define luaM_newvector(L,n,t) \ + cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) + +#define luaM_growvector(L,v,nelems,size,t,limit,e) \ + if ((nelems)+1 > (size)) \ + ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) + +#define luaM_reallocvector(L, v,oldn,n,t) \ + ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) + + +LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, + size_t size); +LUAI_FUNC void *luaM_toobig (lua_State *L); +LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, + size_t size_elem, int limit, + const char *errormsg); + +#endif + diff --git a/lua/src/loadlib.c b/lua/src/loadlib.c new file mode 100644 index 0000000000..0d401eba1c --- /dev/null +++ b/lua/src/loadlib.c @@ -0,0 +1,666 @@ +/* +** $Id: loadlib.c,v 1.52.1.3 2008/08/06 13:29:28 roberto Exp $ +** Dynamic library loader for Lua +** See Copyright Notice in lua.h +** +** This module contains an implementation of loadlib for Unix systems +** that have dlfcn, an implementation for Darwin (Mac OS X), an +** implementation for Windows, and a stub for other systems. +*/ + + +#include +#include + + +#define loadlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* prefix for open functions in C libraries */ +#define LUA_POF "luaopen_" + +/* separator for open functions in C libraries */ +#define LUA_OFSEP "_" + + +#define LIBPREFIX "LOADLIB: " + +#define POF LUA_POF +#define LIB_FAIL "open" + + +/* error codes for ll_loadfunc */ +#define ERRLIB 1 +#define ERRFUNC 2 + +#define setprogdir(L) ((void)0) + + +static void ll_unloadlib (void *lib); +static void *ll_load (lua_State *L, const char *path); +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); + + + +#if defined(LUA_DL_DLOPEN) +/* +** {======================================================================== +** This is an implementation of loadlib based on the dlfcn interface. +** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, +** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least +** as an emulation layer on top of native functions. +** ========================================================================= +*/ + +#include + +static void ll_unloadlib (void *lib) { + dlclose(lib); +} + + +static void *ll_load (lua_State *L, const char *path) { + void *lib = dlopen(path, RTLD_NOW); + if (lib == NULL) lua_pushstring(L, dlerror()); + return lib; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)dlsym(lib, sym); + if (f == NULL) lua_pushstring(L, dlerror()); + return f; +} + +/* }====================================================== */ + + + +#elif defined(LUA_DL_DLL) +/* +** {====================================================================== +** This is an implementation of loadlib for Windows using native functions. +** ======================================================================= +*/ + +#include + + +#undef setprogdir + +static void setprogdir (lua_State *L) { + char buff[MAX_PATH + 1]; + char *lb; + DWORD nsize = sizeof(buff)/sizeof(char); + DWORD n = GetModuleFileNameA(NULL, buff, nsize); + if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) + luaL_error(L, "unable to get ModuleFileName"); + else { + *lb = '\0'; + luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); + lua_remove(L, -2); /* remove original string */ + } +} + + +static void pusherror (lua_State *L) { + int error = GetLastError(); + char buffer[128]; + if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, 0, buffer, sizeof(buffer), NULL)) + lua_pushstring(L, buffer); + else + lua_pushfstring(L, "system error %d\n", error); +} + +static void ll_unloadlib (void *lib) { + FreeLibrary((HINSTANCE)lib); +} + + +static void *ll_load (lua_State *L, const char *path) { + HINSTANCE lib = LoadLibraryA(path); + if (lib == NULL) pusherror(L); + return lib; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); + if (f == NULL) pusherror(L); + return f; +} + +/* }====================================================== */ + + + +#elif defined(LUA_DL_DYLD) +/* +** {====================================================================== +** Native Mac OS X / Darwin Implementation +** ======================================================================= +*/ + +#include + + +/* Mac appends a `_' before C function names */ +#undef POF +#define POF "_" LUA_POF + + +static void pusherror (lua_State *L) { + const char *err_str; + const char *err_file; + NSLinkEditErrors err; + int err_num; + NSLinkEditError(&err, &err_num, &err_file, &err_str); + lua_pushstring(L, err_str); +} + + +static const char *errorfromcode (NSObjectFileImageReturnCode ret) { + switch (ret) { + case NSObjectFileImageInappropriateFile: + return "file is not a bundle"; + case NSObjectFileImageArch: + return "library is for wrong CPU type"; + case NSObjectFileImageFormat: + return "bad format"; + case NSObjectFileImageAccess: + return "cannot access file"; + case NSObjectFileImageFailure: + default: + return "unable to load library"; + } +} + + +static void ll_unloadlib (void *lib) { + NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); +} + + +static void *ll_load (lua_State *L, const char *path) { + NSObjectFileImage img; + NSObjectFileImageReturnCode ret; + /* this would be a rare case, but prevents crashing if it happens */ + if(!_dyld_present()) { + lua_pushliteral(L, "dyld not present"); + return NULL; + } + ret = NSCreateObjectFileImageFromFile(path, &img); + if (ret == NSObjectFileImageSuccess) { + NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | + NSLINKMODULE_OPTION_RETURN_ON_ERROR); + NSDestroyObjectFileImage(img); + if (mod == NULL) pusherror(L); + return mod; + } + lua_pushstring(L, errorfromcode(ret)); + return NULL; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); + if (nss == NULL) { + lua_pushfstring(L, "symbol " LUA_QS " not found", sym); + return NULL; + } + return (lua_CFunction)NSAddressOfSymbol(nss); +} + +/* }====================================================== */ + + + +#else +/* +** {====================================================== +** Fallback for other systems +** ======================================================= +*/ + +#undef LIB_FAIL +#define LIB_FAIL "absent" + + +#define DLMSG "dynamic libraries not enabled; check your Lua installation" + + +static void ll_unloadlib (void *lib) { + (void)lib; /* to avoid warnings */ +} + + +static void *ll_load (lua_State *L, const char *path) { + (void)path; /* to avoid warnings */ + lua_pushliteral(L, DLMSG); + return NULL; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + (void)lib; (void)sym; /* to avoid warnings */ + lua_pushliteral(L, DLMSG); + return NULL; +} + +/* }====================================================== */ +#endif + + + +static void **ll_register (lua_State *L, const char *path) { + void **plib; + lua_pushfstring(L, "%s%s", LIBPREFIX, path); + lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ + if (!lua_isnil(L, -1)) /* is there an entry? */ + plib = (void **)lua_touserdata(L, -1); + else { /* no entry yet; create one */ + lua_pop(L, 1); + plib = (void **)lua_newuserdata(L, sizeof(const void *)); + *plib = NULL; + luaL_getmetatable(L, "_LOADLIB"); + lua_setmetatable(L, -2); + lua_pushfstring(L, "%s%s", LIBPREFIX, path); + lua_pushvalue(L, -2); + lua_settable(L, LUA_REGISTRYINDEX); + } + return plib; +} + + +/* +** __gc tag method: calls library's `ll_unloadlib' function with the lib +** handle +*/ +static int gctm (lua_State *L) { + void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); + if (*lib) ll_unloadlib(*lib); + *lib = NULL; /* mark library as closed */ + return 0; +} + + +static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { + void **reg = ll_register(L, path); + if (*reg == NULL) *reg = ll_load(L, path); + if (*reg == NULL) + return ERRLIB; /* unable to load library */ + else { + lua_CFunction f = ll_sym(L, *reg, sym); + if (f == NULL) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); + return 0; /* return function */ + } +} + + +static int ll_loadlib (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + const char *init = luaL_checkstring(L, 2); + int stat = ll_loadfunc(L, path, init); + if (stat == 0) /* no errors? */ + return 1; /* return the loaded function */ + else { /* error; error message is on stack top */ + lua_pushnil(L); + lua_insert(L, -2); + lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); + return 3; /* return nil, error message, and where */ + } +} + + + +/* +** {====================================================== +** 'require' function +** ======================================================= +*/ + + +static int readable (const char *filename) { + FILE *f = fopen(filename, "r"); /* try to open file */ + if (f == NULL) return 0; /* open failed */ + fclose(f); + return 1; +} + + +static const char *pushnexttemplate (lua_State *L, const char *path) { + const char *l; + while (*path == *LUA_PATHSEP) path++; /* skip separators */ + if (*path == '\0') return NULL; /* no more templates */ + l = strchr(path, *LUA_PATHSEP); /* find next separator */ + if (l == NULL) l = path + strlen(path); + lua_pushlstring(L, path, l - path); /* template */ + return l; +} + + +static const char *findfile (lua_State *L, const char *name, + const char *pname) { + const char *path; + name = luaL_gsub(L, name, ".", LUA_DIRSEP); + lua_getfield(L, LUA_ENVIRONINDEX, pname); + path = lua_tostring(L, -1); + if (path == NULL) + luaL_error(L, LUA_QL("package.%s") " must be a string", pname); + lua_pushliteral(L, ""); /* error accumulator */ + while ((path = pushnexttemplate(L, path)) != NULL) { + const char *filename; + filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); + lua_remove(L, -2); /* remove path template */ + if (readable(filename)) /* does file exist and is readable? */ + return filename; /* return that file name */ + lua_pushfstring(L, "\n\tno file " LUA_QS, filename); + lua_remove(L, -2); /* remove file name */ + lua_concat(L, 2); /* add entry to possible error message */ + } + return NULL; /* not found */ +} + + +static void loaderror (lua_State *L, const char *filename) { + luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); +} + + +static int loader_Lua (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path"); + if (filename == NULL) return 1; /* library not found in this path */ + if (luaL_loadfile(L, filename) != 0) + loaderror(L, filename); + return 1; /* library loaded successfully */ +} + + +static const char *mkfuncname (lua_State *L, const char *modname) { + const char *funcname; + const char *mark = strchr(modname, *LUA_IGMARK); + if (mark) modname = mark + 1; + funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); + funcname = lua_pushfstring(L, POF"%s", funcname); + lua_remove(L, -2); /* remove 'gsub' result */ + return funcname; +} + + +static int loader_C (lua_State *L) { + const char *funcname; + const char *name = luaL_checkstring(L, 1); + const char *filename = findfile(L, name, "cpath"); + if (filename == NULL) return 1; /* library not found in this path */ + funcname = mkfuncname(L, name); + if (ll_loadfunc(L, filename, funcname) != 0) + loaderror(L, filename); + return 1; /* library loaded successfully */ +} + + +static int loader_Croot (lua_State *L) { + const char *funcname; + const char *filename; + const char *name = luaL_checkstring(L, 1); + const char *p = strchr(name, '.'); + int stat; + if (p == NULL) return 0; /* is root */ + lua_pushlstring(L, name, p - name); + filename = findfile(L, lua_tostring(L, -1), "cpath"); + if (filename == NULL) return 1; /* root not found */ + funcname = mkfuncname(L, name); + if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { + if (stat != ERRFUNC) loaderror(L, filename); /* real error */ + lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, + name, filename); + return 1; /* function not found */ + } + return 1; +} + + +static int loader_preload (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_getfield(L, LUA_ENVIRONINDEX, "preload"); + if (!lua_istable(L, -1)) + luaL_error(L, LUA_QL("package.preload") " must be a table"); + lua_getfield(L, -1, name); + if (lua_isnil(L, -1)) /* not found? */ + lua_pushfstring(L, "\n\tno field package.preload['%s']", name); + return 1; +} + + +static const int sentinel_ = 0; +#define sentinel ((void *)&sentinel_) + + +static int ll_require (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + int i; + lua_settop(L, 1); /* _LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, 2, name); + if (lua_toboolean(L, -1)) { /* is it there? */ + if (lua_touserdata(L, -1) == sentinel) /* check loops */ + luaL_error(L, "loop or previous error loading module " LUA_QS, name); + return 1; /* package is already loaded */ + } + /* else must load it; iterate over available loaders */ + lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); + if (!lua_istable(L, -1)) + luaL_error(L, LUA_QL("package.loaders") " must be a table"); + lua_pushliteral(L, ""); /* error message accumulator */ + for (i=1; ; i++) { + lua_rawgeti(L, -2, i); /* get a loader */ + if (lua_isnil(L, -1)) + luaL_error(L, "module " LUA_QS " not found:%s", + name, lua_tostring(L, -2)); + lua_pushstring(L, name); + lua_call(L, 1, 1); /* call it */ + if (lua_isfunction(L, -1)) /* did it find module? */ + break; /* module loaded successfully */ + else if (lua_isstring(L, -1)) /* loader returned error message? */ + lua_concat(L, 2); /* accumulate it */ + else + lua_pop(L, 1); + } + lua_pushlightuserdata(L, sentinel); + lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ + lua_pushstring(L, name); /* pass name as argument to module */ + lua_call(L, 1, 1); /* run loaded module */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ + lua_getfield(L, 2, name); + if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_pushvalue(L, -1); /* extra copy to be returned */ + lua_setfield(L, 2, name); /* _LOADED[name] = true */ + } + return 1; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** 'module' function +** ======================================================= +*/ + + +static void setfenv (lua_State *L) { + lua_Debug ar; + if (lua_getstack(L, 1, &ar) == 0 || + lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ + lua_iscfunction(L, -1)) + luaL_error(L, LUA_QL("module") " not called from a Lua function"); + lua_pushvalue(L, -2); + lua_setfenv(L, -2); + lua_pop(L, 1); +} + + +static void dooptions (lua_State *L, int n) { + int i; + for (i = 2; i <= n; i++) { + lua_pushvalue(L, i); /* get option (a function) */ + lua_pushvalue(L, -2); /* module */ + lua_call(L, 1, 0); + } +} + + +static void modinit (lua_State *L, const char *modname) { + const char *dot; + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_M"); /* module._M = module */ + lua_pushstring(L, modname); + lua_setfield(L, -2, "_NAME"); + dot = strrchr(modname, '.'); /* look for last dot in module name */ + if (dot == NULL) dot = modname; + else dot++; + /* set _PACKAGE as package name (full module name minus last part) */ + lua_pushlstring(L, modname, dot - modname); + lua_setfield(L, -2, "_PACKAGE"); +} + + +static int ll_module (lua_State *L) { + const char *modname = luaL_checkstring(L, 1); + int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ + if (!lua_istable(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) + return luaL_error(L, "name conflict for module " LUA_QS, modname); + lua_pushvalue(L, -1); + lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ + } + /* check whether table already has a _NAME field */ + lua_getfield(L, -1, "_NAME"); + if (!lua_isnil(L, -1)) /* is table an initialized module? */ + lua_pop(L, 1); + else { /* no; initialize it */ + lua_pop(L, 1); + modinit(L, modname); + } + lua_pushvalue(L, -1); + setfenv(L); + dooptions(L, loaded - 1); + return 0; +} + + +static int ll_seeall (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + if (!lua_getmetatable(L, 1)) { + lua_createtable(L, 0, 1); /* create new metatable */ + lua_pushvalue(L, -1); + lua_setmetatable(L, 1); + } + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setfield(L, -2, "__index"); /* mt.__index = _G */ + return 0; +} + + +/* }====================================================== */ + + + +/* auxiliary mark (for internal use) */ +#define AUXMARK "\1" + +static void setpath (lua_State *L, const char *fieldname, const char *envname, + const char *def) { + const char *path = getenv(envname); + if (path == NULL) /* no environment variable? */ + lua_pushstring(L, def); /* use default */ + else { + /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ + path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, + LUA_PATHSEP AUXMARK LUA_PATHSEP); + luaL_gsub(L, path, AUXMARK, def); + lua_remove(L, -2); + } + setprogdir(L); + lua_setfield(L, -2, fieldname); +} + + +static const luaL_Reg pk_funcs[] = { + {"loadlib", ll_loadlib}, + {"seeall", ll_seeall}, + {NULL, NULL} +}; + + +static const luaL_Reg ll_funcs[] = { + {"module", ll_module}, + {"require", ll_require}, + {NULL, NULL} +}; + + +static const lua_CFunction loaders[] = + {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; + + +LUALIB_API int luaopen_package (lua_State *L) { + int i; + /* create new type _LOADLIB */ + luaL_newmetatable(L, "_LOADLIB"); + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); + /* create `package' table */ + luaL_register(L, LUA_LOADLIBNAME, pk_funcs); +#if defined(LUA_COMPAT_LOADLIB) + lua_getfield(L, -1, "loadlib"); + lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); +#endif + lua_pushvalue(L, -1); + lua_replace(L, LUA_ENVIRONINDEX); + /* create `loaders' table */ + lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); + /* fill it with pre-defined loaders */ + for (i=0; loaders[i] != NULL; i++) { + lua_pushcfunction(L, loaders[i]); + lua_rawseti(L, -2, i+1); + } + lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ + setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ + setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ + /* store config information */ + lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" + LUA_EXECDIR "\n" LUA_IGMARK); + lua_setfield(L, -2, "config"); + /* set field `loaded' */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); + lua_setfield(L, -2, "loaded"); + /* set field `preload' */ + lua_newtable(L); + lua_setfield(L, -2, "preload"); + lua_pushvalue(L, LUA_GLOBALSINDEX); + luaL_register(L, NULL, ll_funcs); /* open lib into global table */ + lua_pop(L, 1); + return 1; /* return 'package' table */ +} + diff --git a/lua/src/lobject.c b/lua/src/lobject.c new file mode 100644 index 0000000000..4ff50732a4 --- /dev/null +++ b/lua/src/lobject.c @@ -0,0 +1,214 @@ +/* +** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $ +** Some generic functions over Lua objects +** See Copyright Notice in lua.h +*/ + +#include +#include +#include +#include +#include + +#define lobject_c +#define LUA_CORE + +#include "lua.h" + +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "lvm.h" + + + +const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; + + +/* +** converts an integer to a "floating point byte", represented as +** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if +** eeeee != 0 and (xxx) otherwise. +*/ +int luaO_int2fb (unsigned int x) { + int e = 0; /* expoent */ + while (x >= 16) { + x = (x+1) >> 1; + e++; + } + if (x < 8) return x; + else return ((e+1) << 3) | (cast_int(x) - 8); +} + + +/* converts back */ +int luaO_fb2int (int x) { + int e = (x >> 3) & 31; + if (e == 0) return x; + else return ((x & 7)+8) << (e - 1); +} + + +int luaO_log2 (unsigned int x) { + static const lu_byte log_2[256] = { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + int l = -1; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; + +} + + +int luaO_rawequalObj (const TValue *t1, const TValue *t2) { + if (ttype(t1) != ttype(t2)) return 0; + else switch (ttype(t1)) { + case LUA_TNIL: + return 1; + case LUA_TNUMBER: + return luai_numeq(nvalue(t1), nvalue(t2)); + case LUA_TBOOLEAN: + return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ + case LUA_TLIGHTUSERDATA: + return pvalue(t1) == pvalue(t2); + default: + lua_assert(iscollectable(t1)); + return gcvalue(t1) == gcvalue(t2); + } +} + + +int luaO_str2d (const char *s, lua_Number *result) { + char *endptr; + *result = lua_str2number(s, &endptr); + if (endptr == s) return 0; /* conversion failed */ + if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */ + *result = cast_num(strtoul(s, &endptr, 16)); + if (*endptr == '\0') return 1; /* most common case */ + while (isspace(cast(unsigned char, *endptr))) endptr++; + if (*endptr != '\0') return 0; /* invalid trailing characters? */ + return 1; +} + + + +static void pushstr (lua_State *L, const char *str) { + setsvalue2s(L, L->top, luaS_new(L, str)); + incr_top(L); +} + + +/* this function handles only `%d', `%c', %f, %p, and `%s' formats */ +const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { + int n = 1; + pushstr(L, ""); + for (;;) { + const char *e = strchr(fmt, '%'); + if (e == NULL) break; + setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); + incr_top(L); + switch (*(e+1)) { + case 's': { + const char *s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + pushstr(L, s); + break; + } + case 'c': { + char buff[2]; + buff[0] = cast(char, va_arg(argp, int)); + buff[1] = '\0'; + pushstr(L, buff); + break; + } + case 'd': { + setnvalue(L->top, cast_num(va_arg(argp, int))); + incr_top(L); + break; + } + case 'f': { + setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); + incr_top(L); + break; + } + case 'p': { + char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ + sprintf(buff, "%p", va_arg(argp, void *)); + pushstr(L, buff); + break; + } + case '%': { + pushstr(L, "%"); + break; + } + default: { + char buff[3]; + buff[0] = '%'; + buff[1] = *(e+1); + buff[2] = '\0'; + pushstr(L, buff); + break; + } + } + n += 2; + fmt = e+2; + } + pushstr(L, fmt); + luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); + L->top -= n; + return svalue(L->top - 1); +} + + +const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { + const char *msg; + va_list argp; + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + return msg; +} + + +void luaO_chunkid (char *out, const char *source, size_t bufflen) { + if (*source == '=') { + strncpy(out, source+1, bufflen); /* remove first char */ + out[bufflen-1] = '\0'; /* ensures null termination */ + } + else { /* out = "source", or "...source" */ + if (*source == '@') { + size_t l; + source++; /* skip the `@' */ + bufflen -= sizeof(" '...' "); + l = strlen(source); + strcpy(out, ""); + if (l > bufflen) { + source += (l-bufflen); /* get last part of file name */ + strcat(out, "..."); + } + strcat(out, source); + } + else { /* out = [string "string"] */ + size_t len = strcspn(source, "\n\r"); /* stop at first newline */ + bufflen -= sizeof(" [string \"...\"] "); + if (len > bufflen) len = bufflen; + strcpy(out, "[string \""); + if (source[len] != '\0') { /* must truncate? */ + strncat(out, source, len); + strcat(out, "..."); + } + else + strcat(out, source); + strcat(out, "\"]"); + } + } +} diff --git a/lua/src/lobject.h b/lua/src/lobject.h new file mode 100644 index 0000000000..f1e447ef3b --- /dev/null +++ b/lua/src/lobject.h @@ -0,0 +1,381 @@ +/* +** $Id: lobject.h,v 2.20.1.2 2008/08/06 13:29:48 roberto Exp $ +** Type definitions for Lua objects +** See Copyright Notice in lua.h +*/ + + +#ifndef lobject_h +#define lobject_h + + +#include + + +#include "llimits.h" +#include "lua.h" + + +/* tags for values visible from Lua */ +#define LAST_TAG LUA_TTHREAD + +#define NUM_TAGS (LAST_TAG+1) + + +/* +** Extra tags for non-values +*/ +#define LUA_TPROTO (LAST_TAG+1) +#define LUA_TUPVAL (LAST_TAG+2) +#define LUA_TDEADKEY (LAST_TAG+3) + + +/* +** Union of all collectable objects +*/ +typedef union GCObject GCObject; + + +/* +** Common Header for all collectable objects (in macro form, to be +** included in other objects) +*/ +#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked + + +/* +** Common header in struct form +*/ +typedef struct GCheader { + CommonHeader; +} GCheader; + + + + +/* +** Union of all Lua values +*/ +typedef union { + GCObject *gc; + void *p; + lua_Number n; + int b; +} Value; + + +/* +** Tagged Values +*/ + +#define TValuefields Value value; int tt + +typedef struct lua_TValue { + TValuefields; +} TValue; + + +/* Macros to test type */ +#define ttisnil(o) (ttype(o) == LUA_TNIL) +#define ttisnumber(o) (ttype(o) == LUA_TNUMBER) +#define ttisstring(o) (ttype(o) == LUA_TSTRING) +#define ttistable(o) (ttype(o) == LUA_TTABLE) +#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION) +#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN) +#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) +#define ttisthread(o) (ttype(o) == LUA_TTHREAD) +#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) + +/* Macros to access values */ +#define ttype(o) ((o)->tt) +#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc) +#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p) +#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n) +#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) +#define tsvalue(o) (&rawtsvalue(o)->tsv) +#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u) +#define uvalue(o) (&rawuvalue(o)->uv) +#define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl) +#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) +#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) +#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th) + +#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) + +/* +** for internal debug only +*/ +#define checkconsistency(obj) \ + lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) + +#define checkliveness(g,obj) \ + lua_assert(!iscollectable(obj) || \ + ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) + + +/* Macros to set values */ +#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) + +#define setnvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } + +#define setpvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } + +#define setbvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } + +#define setsvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ + checkliveness(G(L),i_o); } + +#define setuvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ + checkliveness(G(L),i_o); } + +#define setthvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ + checkliveness(G(L),i_o); } + +#define setclvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ + checkliveness(G(L),i_o); } + +#define sethvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ + checkliveness(G(L),i_o); } + +#define setptvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ + checkliveness(G(L),i_o); } + + + + +#define setobj(L,obj1,obj2) \ + { const TValue *o2=(obj2); TValue *o1=(obj1); \ + o1->value = o2->value; o1->tt=o2->tt; \ + checkliveness(G(L),o1); } + + +/* +** different types of sets, according to destination +*/ + +/* from stack to (same) stack */ +#define setobjs2s setobj +/* to stack (not from same stack) */ +#define setobj2s setobj +#define setsvalue2s setsvalue +#define sethvalue2s sethvalue +#define setptvalue2s setptvalue +/* from table to same table */ +#define setobjt2t setobj +/* to table */ +#define setobj2t setobj +/* to new object */ +#define setobj2n setobj +#define setsvalue2n setsvalue + +#define setttype(obj, tt) (ttype(obj) = (tt)) + + +#define iscollectable(o) (ttype(o) >= LUA_TSTRING) + + + +typedef TValue *StkId; /* index to stack elements */ + + +/* +** String headers for string table +*/ +typedef union TString { + L_Umaxalign dummy; /* ensures maximum alignment for strings */ + struct { + CommonHeader; + lu_byte reserved; + unsigned int hash; + size_t len; + } tsv; +} TString; + + +#define getstr(ts) cast(const char *, (ts) + 1) +#define svalue(o) getstr(rawtsvalue(o)) + + + +typedef union Udata { + L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ + struct { + CommonHeader; + struct Table *metatable; + struct Table *env; + size_t len; + } uv; +} Udata; + + + + +/* +** Function Prototypes +*/ +typedef struct Proto { + CommonHeader; + TValue *k; /* constants used by the function */ + Instruction *code; + struct Proto **p; /* functions defined inside the function */ + int *lineinfo; /* map from opcodes to source lines */ + struct LocVar *locvars; /* information about local variables */ + TString **upvalues; /* upvalue names */ + TString *source; + int sizeupvalues; + int sizek; /* size of `k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of `p' */ + int sizelocvars; + int linedefined; + int lastlinedefined; + GCObject *gclist; + lu_byte nups; /* number of upvalues */ + lu_byte numparams; + lu_byte is_vararg; + lu_byte maxstacksize; +} Proto; + + +/* masks for new-style vararg */ +#define VARARG_HASARG 1 +#define VARARG_ISVARARG 2 +#define VARARG_NEEDSARG 4 + + +typedef struct LocVar { + TString *varname; + int startpc; /* first point where variable is active */ + int endpc; /* first point where variable is dead */ +} LocVar; + + + +/* +** Upvalues +*/ + +typedef struct UpVal { + CommonHeader; + TValue *v; /* points to stack or to its own value */ + union { + TValue value; /* the value (when closed) */ + struct { /* double linked list (when open) */ + struct UpVal *prev; + struct UpVal *next; + } l; + } u; +} UpVal; + + +/* +** Closures +*/ + +#define ClosureHeader \ + CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \ + struct Table *env + +typedef struct CClosure { + ClosureHeader; + lua_CFunction f; + TValue upvalue[1]; +} CClosure; + + +typedef struct LClosure { + ClosureHeader; + struct Proto *p; + UpVal *upvals[1]; +} LClosure; + + +typedef union Closure { + CClosure c; + LClosure l; +} Closure; + + +#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC) +#define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC) + + +/* +** Tables +*/ + +typedef union TKey { + struct { + TValuefields; + struct Node *next; /* for chaining */ + } nk; + TValue tvk; +} TKey; + + +typedef struct Node { + TValue i_val; + TKey i_key; +} Node; + + +typedef struct Table { + CommonHeader; + lu_byte flags; /* 1<

lsizenode)) + + +#define luaO_nilobject (&luaO_nilobject_) + +LUAI_DATA const TValue luaO_nilobject_; + +#define ceillog2(x) (luaO_log2((x)-1) + 1) + +LUAI_FUNC int luaO_log2 (unsigned int x); +LUAI_FUNC int luaO_int2fb (unsigned int x); +LUAI_FUNC int luaO_fb2int (int x); +LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2); +LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result); +LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, + va_list argp); +LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); +LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); + + +#endif + diff --git a/lua/src/lopcodes.c b/lua/src/lopcodes.c new file mode 100644 index 0000000000..4cc745230b --- /dev/null +++ b/lua/src/lopcodes.c @@ -0,0 +1,102 @@ +/* +** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $ +** See Copyright Notice in lua.h +*/ + + +#define lopcodes_c +#define LUA_CORE + + +#include "lopcodes.h" + + +/* ORDER OP */ + +const char *const luaP_opnames[NUM_OPCODES+1] = { + "MOVE", + "LOADK", + "LOADBOOL", + "LOADNIL", + "GETUPVAL", + "GETGLOBAL", + "GETTABLE", + "SETGLOBAL", + "SETUPVAL", + "SETTABLE", + "NEWTABLE", + "SELF", + "ADD", + "SUB", + "MUL", + "DIV", + "MOD", + "POW", + "UNM", + "NOT", + "LEN", + "CONCAT", + "JMP", + "EQ", + "LT", + "LE", + "TEST", + "TESTSET", + "CALL", + "TAILCALL", + "RETURN", + "FORLOOP", + "FORPREP", + "TFORLOOP", + "SETLIST", + "CLOSE", + "CLOSURE", + "VARARG", + NULL +}; + + +#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) + +const lu_byte luaP_opmodes[NUM_OPCODES] = { +/* T A B C mode opcode */ + opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ + ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ + ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_GETGLOBAL */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ + ,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETGLOBAL */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ + ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ + ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ + ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TFORLOOP */ + ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ + ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ + ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ +}; + diff --git a/lua/src/lopcodes.h b/lua/src/lopcodes.h new file mode 100644 index 0000000000..41224d6ee1 --- /dev/null +++ b/lua/src/lopcodes.h @@ -0,0 +1,268 @@ +/* +** $Id: lopcodes.h,v 1.125.1.1 2007/12/27 13:02:25 roberto Exp $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lopcodes_h +#define lopcodes_h + +#include "llimits.h" + + +/*=========================================================================== + We assume that instructions are unsigned numbers. + All instructions have an opcode in the first 6 bits. + Instructions can have the following fields: + `A' : 8 bits + `B' : 9 bits + `C' : 9 bits + `Bx' : 18 bits (`B' and `C' together) + `sBx' : signed Bx + + A signed argument is represented in excess K; that is, the number + value is the unsigned value minus K. K is exactly the maximum value + for that argument (so that -max is represented by 0, and +max is + represented by 2*max), which is half the maximum for the corresponding + unsigned argument. +===========================================================================*/ + + +enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ + + +/* +** size and position of opcode arguments. +*/ +#define SIZE_C 9 +#define SIZE_B 9 +#define SIZE_Bx (SIZE_C + SIZE_B) +#define SIZE_A 8 + +#define SIZE_OP 6 + +#define POS_OP 0 +#define POS_A (POS_OP + SIZE_OP) +#define POS_C (POS_A + SIZE_A) +#define POS_B (POS_C + SIZE_C) +#define POS_Bx POS_C + + +/* +** limits for opcode arguments. +** we use (signed) int to manipulate most arguments, +** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) +*/ +#if SIZE_Bx < LUAI_BITSINT-1 +#define MAXARG_Bx ((1<>1) /* `sBx' is signed */ +#else +#define MAXARG_Bx MAX_INT +#define MAXARG_sBx MAX_INT +#endif + + +#define MAXARG_A ((1<>POS_OP) & MASK1(SIZE_OP,0))) +#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ + ((cast(Instruction, o)<>POS_A) & MASK1(SIZE_A,0))) +#define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ + ((cast(Instruction, u)<>POS_B) & MASK1(SIZE_B,0))) +#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ + ((cast(Instruction, b)<>POS_C) & MASK1(SIZE_C,0))) +#define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \ + ((cast(Instruction, b)<>POS_Bx) & MASK1(SIZE_Bx,0))) +#define SETARG_Bx(i,b) ((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \ + ((cast(Instruction, b)< C) then pc++ */ +OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ + +OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ + +OP_FORLOOP,/* A sBx R(A)+=R(A+2); + if R(A) =) R(A)*/ +OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ + +OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ +} OpCode; + + +#define NUM_OPCODES (cast(int, OP_VARARG) + 1) + + + +/*=========================================================================== + Notes: + (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, + and can be 0: OP_CALL then sets `top' to last_result+1, so + next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. + + (*) In OP_VARARG, if (B == 0) then use actual number of varargs and + set top (like in OP_CALL with C == 0). + + (*) In OP_RETURN, if (B == 0) then return up to `top' + + (*) In OP_SETLIST, if (B == 0) then B = `top'; + if (C == 0) then next `instruction' is real C + + (*) For comparisons, A specifies what condition the test should accept + (true or false). + + (*) All `skips' (pc++) assume that next instruction is a jump +===========================================================================*/ + + +/* +** masks for instruction properties. The format is: +** bits 0-1: op mode +** bits 2-3: C arg mode +** bits 4-5: B arg mode +** bit 6: instruction set register A +** bit 7: operator is a test +*/ + +enum OpArgMask { + OpArgN, /* argument is not used */ + OpArgU, /* argument is used */ + OpArgR, /* argument is a register or a jump offset */ + OpArgK /* argument is a constant or register/constant */ +}; + +LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; + +#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) +#define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3)) +#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) +#define testAMode(m) (luaP_opmodes[m] & (1 << 6)) +#define testTMode(m) (luaP_opmodes[m] & (1 << 7)) + + +LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ + + +/* number of list items to accumulate before a SETLIST instruction */ +#define LFIELDS_PER_FLUSH 50 + + +#endif diff --git a/lua/src/loslib.c b/lua/src/loslib.c new file mode 100644 index 0000000000..da06a572ac --- /dev/null +++ b/lua/src/loslib.c @@ -0,0 +1,243 @@ +/* +** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $ +** Standard Operating System library +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include +#include + +#define loslib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static int os_pushresult (lua_State *L, int i, const char *filename) { + int en = errno; /* calls to Lua API may change this value */ + if (i) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + lua_pushfstring(L, "%s: %s", filename, strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +static int os_execute (lua_State *L) { + lua_pushinteger(L, system(luaL_optstring(L, 1, NULL))); + return 1; +} + + +static int os_remove (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + return os_pushresult(L, remove(filename) == 0, filename); +} + + +static int os_rename (lua_State *L) { + const char *fromname = luaL_checkstring(L, 1); + const char *toname = luaL_checkstring(L, 2); + return os_pushresult(L, rename(fromname, toname) == 0, fromname); +} + + +static int os_tmpname (lua_State *L) { + char buff[LUA_TMPNAMBUFSIZE]; + int err; + lua_tmpnam(buff, err); + if (err) + return luaL_error(L, "unable to generate a unique filename"); + lua_pushstring(L, buff); + return 1; +} + + +static int os_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ + return 1; +} + + +static int os_clock (lua_State *L) { + lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); + return 1; +} + + +/* +** {====================================================== +** Time/Date operations +** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, +** wday=%w+1, yday=%j, isdst=? } +** ======================================================= +*/ + +static void setfield (lua_State *L, const char *key, int value) { + lua_pushinteger(L, value); + lua_setfield(L, -2, key); +} + +static void setboolfield (lua_State *L, const char *key, int value) { + if (value < 0) /* undefined? */ + return; /* does not set field */ + lua_pushboolean(L, value); + lua_setfield(L, -2, key); +} + +static int getboolfield (lua_State *L, const char *key) { + int res; + lua_getfield(L, -1, key); + res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; +} + + +static int getfield (lua_State *L, const char *key, int d) { + int res; + lua_getfield(L, -1, key); + if (lua_isnumber(L, -1)) + res = (int)lua_tointeger(L, -1); + else { + if (d < 0) + return luaL_error(L, "field " LUA_QS " missing in date table", key); + res = d; + } + lua_pop(L, 1); + return res; +} + + +static int os_date (lua_State *L) { + const char *s = luaL_optstring(L, 1, "%c"); + time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); + struct tm *stm; + if (*s == '!') { /* UTC? */ + stm = gmtime(&t); + s++; /* skip `!' */ + } + else + stm = localtime(&t); + if (stm == NULL) /* invalid date? */ + lua_pushnil(L); + else if (strcmp(s, "*t") == 0) { + lua_createtable(L, 0, 9); /* 9 = number of fields */ + setfield(L, "sec", stm->tm_sec); + setfield(L, "min", stm->tm_min); + setfield(L, "hour", stm->tm_hour); + setfield(L, "day", stm->tm_mday); + setfield(L, "month", stm->tm_mon+1); + setfield(L, "year", stm->tm_year+1900); + setfield(L, "wday", stm->tm_wday+1); + setfield(L, "yday", stm->tm_yday+1); + setboolfield(L, "isdst", stm->tm_isdst); + } + else { + char cc[3]; + luaL_Buffer b; + cc[0] = '%'; cc[2] = '\0'; + luaL_buffinit(L, &b); + for (; *s; s++) { + if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ + luaL_addchar(&b, *s); + else { + size_t reslen; + char buff[200]; /* should be big enough for any conversion result */ + cc[1] = *(++s); + reslen = strftime(buff, sizeof(buff), cc, stm); + luaL_addlstring(&b, buff, reslen); + } + } + luaL_pushresult(&b); + } + return 1; +} + + +static int os_time (lua_State *L) { + time_t t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = time(NULL); /* get current time */ + else { + struct tm ts; + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + ts.tm_sec = getfield(L, "sec", 0); + ts.tm_min = getfield(L, "min", 0); + ts.tm_hour = getfield(L, "hour", 12); + ts.tm_mday = getfield(L, "day", -1); + ts.tm_mon = getfield(L, "month", -1) - 1; + ts.tm_year = getfield(L, "year", -1) - 1900; + ts.tm_isdst = getboolfield(L, "isdst"); + t = mktime(&ts); + } + if (t == (time_t)(-1)) + lua_pushnil(L); + else + lua_pushnumber(L, (lua_Number)t); + return 1; +} + + +static int os_difftime (lua_State *L) { + lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), + (time_t)(luaL_optnumber(L, 2, 0)))); + return 1; +} + +/* }====================================================== */ + + +static int os_setlocale (lua_State *L) { + static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME}; + static const char *const catnames[] = {"all", "collate", "ctype", "monetary", + "numeric", "time", NULL}; + const char *l = luaL_optstring(L, 1, NULL); + int op = luaL_checkoption(L, 2, "all", catnames); + lua_pushstring(L, setlocale(cat[op], l)); + return 1; +} + + +static int os_exit (lua_State *L) { + exit(luaL_optint(L, 1, EXIT_SUCCESS)); +} + +static const luaL_Reg syslib[] = { + {"clock", os_clock}, + {"date", os_date}, + {"difftime", os_difftime}, + {"execute", os_execute}, + {"exit", os_exit}, + {"getenv", os_getenv}, + {"remove", os_remove}, + {"rename", os_rename}, + {"setlocale", os_setlocale}, + {"time", os_time}, + {"tmpname", os_tmpname}, + {NULL, NULL} +}; + +/* }====================================================== */ + + + +LUALIB_API int luaopen_os (lua_State *L) { + luaL_register(L, LUA_OSLIBNAME, syslib); + return 1; +} + diff --git a/lua/src/lparser.c b/lua/src/lparser.c new file mode 100644 index 0000000000..1e2a9a88b7 --- /dev/null +++ b/lua/src/lparser.c @@ -0,0 +1,1339 @@ +/* +** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + + +#include + +#define lparser_c +#define LUA_CORE + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" + + + +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) + +#define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) + +#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m) + + +/* +** nodes for block list (list of active blocks) +*/ +typedef struct BlockCnt { + struct BlockCnt *previous; /* chain */ + int breaklist; /* list of jumps out of this loop */ + lu_byte nactvar; /* # active locals outside the breakable structure */ + lu_byte upval; /* true if some variable in the block is an upvalue */ + lu_byte isbreakable; /* true if `block' is a loop */ +} BlockCnt; + + + +/* +** prototypes for recursive non-terminal functions +*/ +static void chunk (LexState *ls); +static void expr (LexState *ls, expdesc *v); + + +static void anchor_token (LexState *ls) { + if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { + TString *ts = ls->t.seminfo.ts; + luaX_newstring(ls, getstr(ts), ts->tsv.len); + } +} + + +static void error_expected (LexState *ls, int token) { + luaX_syntaxerror(ls, + luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token))); +} + + +static void errorlimit (FuncState *fs, int limit, const char *what) { + const char *msg = (fs->f->linedefined == 0) ? + luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : + luaO_pushfstring(fs->L, "function at line %d has more than %d %s", + fs->f->linedefined, limit, what); + luaX_lexerror(fs->ls, msg, 0); +} + + +static int testnext (LexState *ls, int c) { + if (ls->t.token == c) { + luaX_next(ls); + return 1; + } + else return 0; +} + + +static void check (LexState *ls, int c) { + if (ls->t.token != c) + error_expected(ls, c); +} + +static void checknext (LexState *ls, int c) { + check(ls, c); + luaX_next(ls); +} + + +#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } + + + +static void check_match (LexState *ls, int what, int who, int where) { + if (!testnext(ls, what)) { + if (where == ls->linenumber) + error_expected(ls, what); + else { + luaX_syntaxerror(ls, luaO_pushfstring(ls->L, + LUA_QS " expected (to close " LUA_QS " at line %d)", + luaX_token2str(ls, what), luaX_token2str(ls, who), where)); + } + } +} + + +static TString *str_checkname (LexState *ls) { + TString *ts; + check(ls, TK_NAME); + ts = ls->t.seminfo.ts; + luaX_next(ls); + return ts; +} + + +static void init_exp (expdesc *e, expkind k, int i) { + e->f = e->t = NO_JUMP; + e->k = k; + e->u.s.info = i; +} + + +static void codestring (LexState *ls, expdesc *e, TString *s) { + init_exp(e, VK, luaK_stringK(ls->fs, s)); +} + + +static void checkname(LexState *ls, expdesc *e) { + codestring(ls, e, str_checkname(ls)); +} + + +static int registerlocalvar (LexState *ls, TString *varname) { + FuncState *fs = ls->fs; + Proto *f = fs->f; + int oldsize = f->sizelocvars; + luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, + LocVar, SHRT_MAX, "too many local variables"); + while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; + f->locvars[fs->nlocvars].varname = varname; + luaC_objbarrier(ls->L, f, varname); + return fs->nlocvars++; +} + + +#define new_localvarliteral(ls,v,n) \ + new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n) + + +static void new_localvar (LexState *ls, TString *name, int n) { + FuncState *fs = ls->fs; + luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables"); + fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); +} + + +static void adjustlocalvars (LexState *ls, int nvars) { + FuncState *fs = ls->fs; + fs->nactvar = cast_byte(fs->nactvar + nvars); + for (; nvars; nvars--) { + getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; + } +} + + +static void removevars (LexState *ls, int tolevel) { + FuncState *fs = ls->fs; + while (fs->nactvar > tolevel) + getlocvar(fs, --fs->nactvar).endpc = fs->pc; +} + + +static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { + int i; + Proto *f = fs->f; + int oldsize = f->sizeupvalues; + for (i=0; inups; i++) { + if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) { + lua_assert(f->upvalues[i] == name); + return i; + } + } + /* new one */ + luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues"); + luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, + TString *, MAX_INT, ""); + while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; + f->upvalues[f->nups] = name; + luaC_objbarrier(fs->L, f, name); + lua_assert(v->k == VLOCAL || v->k == VUPVAL); + fs->upvalues[f->nups].k = cast_byte(v->k); + fs->upvalues[f->nups].info = cast_byte(v->u.s.info); + return f->nups++; +} + + +static int searchvar (FuncState *fs, TString *n) { + int i; + for (i=fs->nactvar-1; i >= 0; i--) { + if (n == getlocvar(fs, i).varname) + return i; + } + return -1; /* not found */ +} + + +static void markupval (FuncState *fs, int level) { + BlockCnt *bl = fs->bl; + while (bl && bl->nactvar > level) bl = bl->previous; + if (bl) bl->upval = 1; +} + + +static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { + if (fs == NULL) { /* no more levels? */ + init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ + return VGLOBAL; + } + else { + int v = searchvar(fs, n); /* look up at current level */ + if (v >= 0) { + init_exp(var, VLOCAL, v); + if (!base) + markupval(fs, v); /* local will be used as an upval */ + return VLOCAL; + } + else { /* not found at current level; try upper one */ + if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) + return VGLOBAL; + var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ + var->k = VUPVAL; /* upvalue in this level */ + return VUPVAL; + } + } +} + + +static void singlevar (LexState *ls, expdesc *var) { + TString *varname = str_checkname(ls); + FuncState *fs = ls->fs; + if (singlevaraux(fs, varname, var, 1) == VGLOBAL) + var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ +} + + +static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { + FuncState *fs = ls->fs; + int extra = nvars - nexps; + if (hasmultret(e->k)) { + extra++; /* includes call itself */ + if (extra < 0) extra = 0; + luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ + if (extra > 1) luaK_reserveregs(fs, extra-1); + } + else { + if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ + if (extra > 0) { + int reg = fs->freereg; + luaK_reserveregs(fs, extra); + luaK_nil(fs, reg, extra); + } + } +} + + +static void enterlevel (LexState *ls) { + if (++ls->L->nCcalls > LUAI_MAXCCALLS) + luaX_lexerror(ls, "chunk has too many syntax levels", 0); +} + + +#define leavelevel(ls) ((ls)->L->nCcalls--) + + +static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { + bl->breaklist = NO_JUMP; + bl->isbreakable = isbreakable; + bl->nactvar = fs->nactvar; + bl->upval = 0; + bl->previous = fs->bl; + fs->bl = bl; + lua_assert(fs->freereg == fs->nactvar); +} + + +static void leaveblock (FuncState *fs) { + BlockCnt *bl = fs->bl; + fs->bl = bl->previous; + removevars(fs->ls, bl->nactvar); + if (bl->upval) + luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); + /* a block either controls scope or breaks (never both) */ + lua_assert(!bl->isbreakable || !bl->upval); + lua_assert(bl->nactvar == fs->nactvar); + fs->freereg = fs->nactvar; /* free registers */ + luaK_patchtohere(fs, bl->breaklist); +} + + +static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { + FuncState *fs = ls->fs; + Proto *f = fs->f; + int oldsize = f->sizep; + int i; + luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, + MAXARG_Bx, "constant table overflow"); + while (oldsize < f->sizep) f->p[oldsize++] = NULL; + f->p[fs->np++] = func->f; + luaC_objbarrier(ls->L, f, func->f); + init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); + for (i=0; if->nups; i++) { + OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; + luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0); + } +} + + +static void open_func (LexState *ls, FuncState *fs) { + lua_State *L = ls->L; + Proto *f = luaF_newproto(L); + fs->f = f; + fs->prev = ls->fs; /* linked list of funcstates */ + fs->ls = ls; + fs->L = L; + ls->fs = fs; + fs->pc = 0; + fs->lasttarget = -1; + fs->jpc = NO_JUMP; + fs->freereg = 0; + fs->nk = 0; + fs->np = 0; + fs->nlocvars = 0; + fs->nactvar = 0; + fs->bl = NULL; + f->source = ls->source; + f->maxstacksize = 2; /* registers 0/1 are always valid */ + fs->h = luaH_new(L, 0, 0); + /* anchor table of constants and prototype (to avoid being collected) */ + sethvalue2s(L, L->top, fs->h); + incr_top(L); + setptvalue2s(L, L->top, f); + incr_top(L); +} + + +static void close_func (LexState *ls) { + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; + removevars(ls, 0); + luaK_ret(fs, 0, 0); /* final return */ + luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); + f->sizecode = fs->pc; + luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); + f->sizelineinfo = fs->pc; + luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); + f->sizek = fs->nk; + luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); + f->sizep = fs->np; + luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); + f->sizelocvars = fs->nlocvars; + luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *); + f->sizeupvalues = f->nups; + lua_assert(luaG_checkcode(f)); + lua_assert(fs->bl == NULL); + ls->fs = fs->prev; + L->top -= 2; /* remove table and prototype from the stack */ + /* last token read was anchored in defunct function; must reanchor it */ + if (fs) anchor_token(ls); +} + + +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { + struct LexState lexstate; + struct FuncState funcstate; + lexstate.buff = buff; + luaX_setinput(L, &lexstate, z, luaS_new(L, name)); + open_func(&lexstate, &funcstate); + funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ + luaX_next(&lexstate); /* read first token */ + chunk(&lexstate); + check(&lexstate, TK_EOS); + close_func(&lexstate); + lua_assert(funcstate.prev == NULL); + lua_assert(funcstate.f->nups == 0); + lua_assert(lexstate.fs == NULL); + return funcstate.f; +} + + + +/*============================================================*/ +/* GRAMMAR RULES */ +/*============================================================*/ + + +static void field (LexState *ls, expdesc *v) { + /* field -> ['.' | ':'] NAME */ + FuncState *fs = ls->fs; + expdesc key; + luaK_exp2anyreg(fs, v); + luaX_next(ls); /* skip the dot or colon */ + checkname(ls, &key); + luaK_indexed(fs, v, &key); +} + + +static void yindex (LexState *ls, expdesc *v) { + /* index -> '[' expr ']' */ + luaX_next(ls); /* skip the '[' */ + expr(ls, v); + luaK_exp2val(ls->fs, v); + checknext(ls, ']'); +} + + +/* +** {====================================================================== +** Rules for Constructors +** ======================================================================= +*/ + + +struct ConsControl { + expdesc v; /* last list item read */ + expdesc *t; /* table descriptor */ + int nh; /* total number of `record' elements */ + int na; /* total number of array elements */ + int tostore; /* number of array elements pending to be stored */ +}; + + +static void recfield (LexState *ls, struct ConsControl *cc) { + /* recfield -> (NAME | `['exp1`]') = exp1 */ + FuncState *fs = ls->fs; + int reg = ls->fs->freereg; + expdesc key, val; + int rkkey; + if (ls->t.token == TK_NAME) { + luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + checkname(ls, &key); + } + else /* ls->t.token == '[' */ + yindex(ls, &key); + cc->nh++; + checknext(ls, '='); + rkkey = luaK_exp2RK(fs, &key); + expr(ls, &val); + luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val)); + fs->freereg = reg; /* free registers */ +} + + +static void closelistfield (FuncState *fs, struct ConsControl *cc) { + if (cc->v.k == VVOID) return; /* there is no list item */ + luaK_exp2nextreg(fs, &cc->v); + cc->v.k = VVOID; + if (cc->tostore == LFIELDS_PER_FLUSH) { + luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); /* flush */ + cc->tostore = 0; /* no more items pending */ + } +} + + +static void lastlistfield (FuncState *fs, struct ConsControl *cc) { + if (cc->tostore == 0) return; + if (hasmultret(cc->v.k)) { + luaK_setmultret(fs, &cc->v); + luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET); + cc->na--; /* do not count last expression (unknown number of elements) */ + } + else { + if (cc->v.k != VVOID) + luaK_exp2nextreg(fs, &cc->v); + luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); + } +} + + +static void listfield (LexState *ls, struct ConsControl *cc) { + expr(ls, &cc->v); + luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); + cc->na++; + cc->tostore++; +} + + +static void constructor (LexState *ls, expdesc *t) { + /* constructor -> ?? */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); + struct ConsControl cc; + cc.na = cc.nh = cc.tostore = 0; + cc.t = t; + init_exp(t, VRELOCABLE, pc); + init_exp(&cc.v, VVOID, 0); /* no value (yet) */ + luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */ + checknext(ls, '{'); + do { + lua_assert(cc.v.k == VVOID || cc.tostore > 0); + if (ls->t.token == '}') break; + closelistfield(fs, &cc); + switch(ls->t.token) { + case TK_NAME: { /* may be listfields or recfields */ + luaX_lookahead(ls); + if (ls->lookahead.token != '=') /* expression? */ + listfield(ls, &cc); + else + recfield(ls, &cc); + break; + } + case '[': { /* constructor_item -> recfield */ + recfield(ls, &cc); + break; + } + default: { /* constructor_part -> listfield */ + listfield(ls, &cc); + break; + } + } + } while (testnext(ls, ',') || testnext(ls, ';')); + check_match(ls, '}', '{', line); + lastlistfield(fs, &cc); + SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ + SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ +} + +/* }====================================================================== */ + + + +static void parlist (LexState *ls) { + /* parlist -> [ param { `,' param } ] */ + FuncState *fs = ls->fs; + Proto *f = fs->f; + int nparams = 0; + f->is_vararg = 0; + if (ls->t.token != ')') { /* is `parlist' not empty? */ + do { + switch (ls->t.token) { + case TK_NAME: { /* param -> NAME */ + new_localvar(ls, str_checkname(ls), nparams++); + break; + } + case TK_DOTS: { /* param -> `...' */ + luaX_next(ls); +#if defined(LUA_COMPAT_VARARG) + /* use `arg' as default name */ + new_localvarliteral(ls, "arg", nparams++); + f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG; +#endif + f->is_vararg |= VARARG_ISVARARG; + break; + } + default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); + } + } while (!f->is_vararg && testnext(ls, ',')); + } + adjustlocalvars(ls, nparams); + f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG)); + luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ +} + + +static void body (LexState *ls, expdesc *e, int needself, int line) { + /* body -> `(' parlist `)' chunk END */ + FuncState new_fs; + open_func(ls, &new_fs); + new_fs.f->linedefined = line; + checknext(ls, '('); + if (needself) { + new_localvarliteral(ls, "self", 0); + adjustlocalvars(ls, 1); + } + parlist(ls); + checknext(ls, ')'); + chunk(ls); + new_fs.f->lastlinedefined = ls->linenumber; + check_match(ls, TK_END, TK_FUNCTION, line); + close_func(ls); + pushclosure(ls, &new_fs, e); +} + + +static int explist1 (LexState *ls, expdesc *v) { + /* explist1 -> expr { `,' expr } */ + int n = 1; /* at least one expression */ + expr(ls, v); + while (testnext(ls, ',')) { + luaK_exp2nextreg(ls->fs, v); + expr(ls, v); + n++; + } + return n; +} + + +static void funcargs (LexState *ls, expdesc *f) { + FuncState *fs = ls->fs; + expdesc args; + int base, nparams; + int line = ls->linenumber; + switch (ls->t.token) { + case '(': { /* funcargs -> `(' [ explist1 ] `)' */ + if (line != ls->lastline) + luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); + luaX_next(ls); + if (ls->t.token == ')') /* arg list is empty? */ + args.k = VVOID; + else { + explist1(ls, &args); + luaK_setmultret(fs, &args); + } + check_match(ls, ')', '(', line); + break; + } + case '{': { /* funcargs -> constructor */ + constructor(ls, &args); + break; + } + case TK_STRING: { /* funcargs -> STRING */ + codestring(ls, &args, ls->t.seminfo.ts); + luaX_next(ls); /* must use `seminfo' before `next' */ + break; + } + default: { + luaX_syntaxerror(ls, "function arguments expected"); + return; + } + } + lua_assert(f->k == VNONRELOC); + base = f->u.s.info; /* base register for call */ + if (hasmultret(args.k)) + nparams = LUA_MULTRET; /* open call */ + else { + if (args.k != VVOID) + luaK_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base+1); + } + init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); + luaK_fixline(fs, line); + fs->freereg = base+1; /* call remove function and arguments and leaves + (unless changed) one result */ +} + + + + +/* +** {====================================================================== +** Expression parsing +** ======================================================================= +*/ + + +static void prefixexp (LexState *ls, expdesc *v) { + /* prefixexp -> NAME | '(' expr ')' */ + switch (ls->t.token) { + case '(': { + int line = ls->linenumber; + luaX_next(ls); + expr(ls, v); + check_match(ls, ')', '(', line); + luaK_dischargevars(ls->fs, v); + return; + } + case TK_NAME: { + singlevar(ls, v); + return; + } + default: { + luaX_syntaxerror(ls, "unexpected symbol"); + return; + } + } +} + + +static void primaryexp (LexState *ls, expdesc *v) { + /* primaryexp -> + prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ + FuncState *fs = ls->fs; + prefixexp(ls, v); + for (;;) { + switch (ls->t.token) { + case '.': { /* field */ + field(ls, v); + break; + } + case '[': { /* `[' exp1 `]' */ + expdesc key; + luaK_exp2anyreg(fs, v); + yindex(ls, &key); + luaK_indexed(fs, v, &key); + break; + } + case ':': { /* `:' NAME funcargs */ + expdesc key; + luaX_next(ls); + checkname(ls, &key); + luaK_self(fs, v, &key); + funcargs(ls, v); + break; + } + case '(': case TK_STRING: case '{': { /* funcargs */ + luaK_exp2nextreg(fs, v); + funcargs(ls, v); + break; + } + default: return; + } + } +} + + +static void simpleexp (LexState *ls, expdesc *v) { + /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | + constructor | FUNCTION body | primaryexp */ + switch (ls->t.token) { + case TK_NUMBER: { + init_exp(v, VKNUM, 0); + v->u.nval = ls->t.seminfo.r; + break; + } + case TK_STRING: { + codestring(ls, v, ls->t.seminfo.ts); + break; + } + case TK_NIL: { + init_exp(v, VNIL, 0); + break; + } + case TK_TRUE: { + init_exp(v, VTRUE, 0); + break; + } + case TK_FALSE: { + init_exp(v, VFALSE, 0); + break; + } + case TK_DOTS: { /* vararg */ + FuncState *fs = ls->fs; + check_condition(ls, fs->f->is_vararg, + "cannot use " LUA_QL("...") " outside a vararg function"); + fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */ + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); + break; + } + case '{': { /* constructor */ + constructor(ls, v); + return; + } + case TK_FUNCTION: { + luaX_next(ls); + body(ls, v, 0, ls->linenumber); + return; + } + default: { + primaryexp(ls, v); + return; + } + } + luaX_next(ls); +} + + +static UnOpr getunopr (int op) { + switch (op) { + case TK_NOT: return OPR_NOT; + case '-': return OPR_MINUS; + case '#': return OPR_LEN; + default: return OPR_NOUNOPR; + } +} + + +static BinOpr getbinopr (int op) { + switch (op) { + case '+': return OPR_ADD; + case '-': return OPR_SUB; + case '*': return OPR_MUL; + case '/': return OPR_DIV; + case '%': return OPR_MOD; + case '^': return OPR_POW; + case TK_CONCAT: return OPR_CONCAT; + case TK_NE: return OPR_NE; + case TK_EQ: return OPR_EQ; + case '<': return OPR_LT; + case TK_LE: return OPR_LE; + case '>': return OPR_GT; + case TK_GE: return OPR_GE; + case TK_AND: return OPR_AND; + case TK_OR: return OPR_OR; + default: return OPR_NOBINOPR; + } +} + + +static const struct { + lu_byte left; /* left priority for each binary operator */ + lu_byte right; /* right priority */ +} priority[] = { /* ORDER OPR */ + {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ + {10, 9}, {5, 4}, /* power and concat (right associative) */ + {3, 3}, {3, 3}, /* equality and inequality */ + {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ + {2, 2}, {1, 1} /* logical (and/or) */ +}; + +#define UNARY_PRIORITY 8 /* priority for unary operators */ + + +/* +** subexpr -> (simpleexp | unop subexpr) { binop subexpr } +** where `binop' is any binary operator with a priority higher than `limit' +*/ +static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { + BinOpr op; + UnOpr uop; + enterlevel(ls); + uop = getunopr(ls->t.token); + if (uop != OPR_NOUNOPR) { + luaX_next(ls); + subexpr(ls, v, UNARY_PRIORITY); + luaK_prefix(ls->fs, uop, v); + } + else simpleexp(ls, v); + /* expand while operators have priorities higher than `limit' */ + op = getbinopr(ls->t.token); + while (op != OPR_NOBINOPR && priority[op].left > limit) { + expdesc v2; + BinOpr nextop; + luaX_next(ls); + luaK_infix(ls->fs, op, v); + /* read sub-expression with higher priority */ + nextop = subexpr(ls, &v2, priority[op].right); + luaK_posfix(ls->fs, op, v, &v2); + op = nextop; + } + leavelevel(ls); + return op; /* return first untreated operator */ +} + + +static void expr (LexState *ls, expdesc *v) { + subexpr(ls, v, 0); +} + +/* }==================================================================== */ + + + +/* +** {====================================================================== +** Rules for Statements +** ======================================================================= +*/ + + +static int block_follow (int token) { + switch (token) { + case TK_ELSE: case TK_ELSEIF: case TK_END: + case TK_UNTIL: case TK_EOS: + return 1; + default: return 0; + } +} + + +static void block (LexState *ls) { + /* block -> chunk */ + FuncState *fs = ls->fs; + BlockCnt bl; + enterblock(fs, &bl, 0); + chunk(ls); + lua_assert(bl.breaklist == NO_JUMP); + leaveblock(fs); +} + + +/* +** structure to chain all variables in the left-hand side of an +** assignment +*/ +struct LHS_assign { + struct LHS_assign *prev; + expdesc v; /* variable (global, local, upvalue, or indexed) */ +}; + + +/* +** check whether, in an assignment to a local variable, the local variable +** is needed in a previous assignment (to a table). If so, save original +** local value in a safe place and use this safe copy in the previous +** assignment. +*/ +static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { + FuncState *fs = ls->fs; + int extra = fs->freereg; /* eventual position to save local variable */ + int conflict = 0; + for (; lh; lh = lh->prev) { + if (lh->v.k == VINDEXED) { + if (lh->v.u.s.info == v->u.s.info) { /* conflict? */ + conflict = 1; + lh->v.u.s.info = extra; /* previous assignment will use safe copy */ + } + if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */ + conflict = 1; + lh->v.u.s.aux = extra; /* previous assignment will use safe copy */ + } + } + } + if (conflict) { + luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */ + luaK_reserveregs(fs, 1); + } +} + + +static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { + expdesc e; + check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, + "syntax error"); + if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ + struct LHS_assign nv; + nv.prev = lh; + primaryexp(ls, &nv.v); + if (nv.v.k == VLOCAL) + check_conflict(ls, lh, &nv.v); + luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls, + "variables in assignment"); + assignment(ls, &nv, nvars+1); + } + else { /* assignment -> `=' explist1 */ + int nexps; + checknext(ls, '='); + nexps = explist1(ls, &e); + if (nexps != nvars) { + adjust_assign(ls, nvars, nexps, &e); + if (nexps > nvars) + ls->fs->freereg -= nexps - nvars; /* remove extra values */ + } + else { + luaK_setoneret(ls->fs, &e); /* close last expression */ + luaK_storevar(ls->fs, &lh->v, &e); + return; /* avoid default */ + } + } + init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ + luaK_storevar(ls->fs, &lh->v, &e); +} + + +static int cond (LexState *ls) { + /* cond -> exp */ + expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ + luaK_goiftrue(ls->fs, &v); + return v.f; +} + + +static void breakstat (LexState *ls) { + FuncState *fs = ls->fs; + BlockCnt *bl = fs->bl; + int upval = 0; + while (bl && !bl->isbreakable) { + upval |= bl->upval; + bl = bl->previous; + } + if (!bl) + luaX_syntaxerror(ls, "no loop to break"); + if (upval) + luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); + luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); +} + + +static void whilestat (LexState *ls, int line) { + /* whilestat -> WHILE cond DO block END */ + FuncState *fs = ls->fs; + int whileinit; + int condexit; + BlockCnt bl; + luaX_next(ls); /* skip WHILE */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); + enterblock(fs, &bl, 1); + checknext(ls, TK_DO); + block(ls); + luaK_patchlist(fs, luaK_jump(fs), whileinit); + check_match(ls, TK_END, TK_WHILE, line); + leaveblock(fs); + luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ +} + + +static void repeatstat (LexState *ls, int line) { + /* repeatstat -> REPEAT block UNTIL cond */ + int condexit; + FuncState *fs = ls->fs; + int repeat_init = luaK_getlabel(fs); + BlockCnt bl1, bl2; + enterblock(fs, &bl1, 1); /* loop block */ + enterblock(fs, &bl2, 0); /* scope block */ + luaX_next(ls); /* skip REPEAT */ + chunk(ls); + check_match(ls, TK_UNTIL, TK_REPEAT, line); + condexit = cond(ls); /* read condition (inside scope block) */ + if (!bl2.upval) { /* no upvalues? */ + leaveblock(fs); /* finish scope */ + luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ + } + else { /* complete semantics when there are upvalues */ + breakstat(ls); /* if condition then break */ + luaK_patchtohere(ls->fs, condexit); /* else... */ + leaveblock(fs); /* finish scope... */ + luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ + } + leaveblock(fs); /* finish loop */ +} + + +static int exp1 (LexState *ls) { + expdesc e; + int k; + expr(ls, &e); + k = e.k; + luaK_exp2nextreg(ls->fs, &e); + return k; +} + + +static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { + /* forbody -> DO block */ + BlockCnt bl; + FuncState *fs = ls->fs; + int prep, endfor; + adjustlocalvars(ls, 3); /* control variables */ + checknext(ls, TK_DO); + prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); + enterblock(fs, &bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + luaK_reserveregs(fs, nvars); + block(ls); + leaveblock(fs); /* end of scope for declared variables */ + luaK_patchtohere(fs, prep); + endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : + luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); + luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ + luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); +} + + +static void fornum (LexState *ls, TString *varname, int line) { + /* fornum -> NAME = exp1,exp1[,exp1] forbody */ + FuncState *fs = ls->fs; + int base = fs->freereg; + new_localvarliteral(ls, "(for index)", 0); + new_localvarliteral(ls, "(for limit)", 1); + new_localvarliteral(ls, "(for step)", 2); + new_localvar(ls, varname, 3); + checknext(ls, '='); + exp1(ls); /* initial value */ + checknext(ls, ','); + exp1(ls); /* limit */ + if (testnext(ls, ',')) + exp1(ls); /* optional step */ + else { /* default step = 1 */ + luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); + luaK_reserveregs(fs, 1); + } + forbody(ls, base, line, 1, 1); +} + + +static void forlist (LexState *ls, TString *indexname) { + /* forlist -> NAME {,NAME} IN explist1 forbody */ + FuncState *fs = ls->fs; + expdesc e; + int nvars = 0; + int line; + int base = fs->freereg; + /* create control variables */ + new_localvarliteral(ls, "(for generator)", nvars++); + new_localvarliteral(ls, "(for state)", nvars++); + new_localvarliteral(ls, "(for control)", nvars++); + /* create declared variables */ + new_localvar(ls, indexname, nvars++); + while (testnext(ls, ',')) + new_localvar(ls, str_checkname(ls), nvars++); + checknext(ls, TK_IN); + line = ls->linenumber; + adjust_assign(ls, 3, explist1(ls, &e), &e); + luaK_checkstack(fs, 3); /* extra space to call generator */ + forbody(ls, base, line, nvars - 3, 0); +} + + +static void forstat (LexState *ls, int line) { + /* forstat -> FOR (fornum | forlist) END */ + FuncState *fs = ls->fs; + TString *varname; + BlockCnt bl; + enterblock(fs, &bl, 1); /* scope for loop and control variables */ + luaX_next(ls); /* skip `for' */ + varname = str_checkname(ls); /* first variable name */ + switch (ls->t.token) { + case '=': fornum(ls, varname, line); break; + case ',': case TK_IN: forlist(ls, varname); break; + default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); + } + check_match(ls, TK_END, TK_FOR, line); + leaveblock(fs); /* loop scope (`break' jumps to this point) */ +} + + +static int test_then_block (LexState *ls) { + /* test_then_block -> [IF | ELSEIF] cond THEN block */ + int condexit; + luaX_next(ls); /* skip IF or ELSEIF */ + condexit = cond(ls); + checknext(ls, TK_THEN); + block(ls); /* `then' part */ + return condexit; +} + + +static void ifstat (LexState *ls, int line) { + /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + FuncState *fs = ls->fs; + int flist; + int escapelist = NO_JUMP; + flist = test_then_block(ls); /* IF cond THEN block */ + while (ls->t.token == TK_ELSEIF) { + luaK_concat(fs, &escapelist, luaK_jump(fs)); + luaK_patchtohere(fs, flist); + flist = test_then_block(ls); /* ELSEIF cond THEN block */ + } + if (ls->t.token == TK_ELSE) { + luaK_concat(fs, &escapelist, luaK_jump(fs)); + luaK_patchtohere(fs, flist); + luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ + block(ls); /* `else' part */ + } + else + luaK_concat(fs, &escapelist, flist); + luaK_patchtohere(fs, escapelist); + check_match(ls, TK_END, TK_IF, line); +} + + +static void localfunc (LexState *ls) { + expdesc v, b; + FuncState *fs = ls->fs; + new_localvar(ls, str_checkname(ls), 0); + init_exp(&v, VLOCAL, fs->freereg); + luaK_reserveregs(fs, 1); + adjustlocalvars(ls, 1); + body(ls, &b, 0, ls->linenumber); + luaK_storevar(fs, &v, &b); + /* debug information will only see the variable after this point! */ + getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; +} + + +static void localstat (LexState *ls) { + /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */ + int nvars = 0; + int nexps; + expdesc e; + do { + new_localvar(ls, str_checkname(ls), nvars++); + } while (testnext(ls, ',')); + if (testnext(ls, '=')) + nexps = explist1(ls, &e); + else { + e.k = VVOID; + nexps = 0; + } + adjust_assign(ls, nvars, nexps, &e); + adjustlocalvars(ls, nvars); +} + + +static int funcname (LexState *ls, expdesc *v) { + /* funcname -> NAME {field} [`:' NAME] */ + int needself = 0; + singlevar(ls, v); + while (ls->t.token == '.') + field(ls, v); + if (ls->t.token == ':') { + needself = 1; + field(ls, v); + } + return needself; +} + + +static void funcstat (LexState *ls, int line) { + /* funcstat -> FUNCTION funcname body */ + int needself; + expdesc v, b; + luaX_next(ls); /* skip FUNCTION */ + needself = funcname(ls, &v); + body(ls, &b, needself, line); + luaK_storevar(ls->fs, &v, &b); + luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ +} + + +static void exprstat (LexState *ls) { + /* stat -> func | assignment */ + FuncState *fs = ls->fs; + struct LHS_assign v; + primaryexp(ls, &v.v); + if (v.v.k == VCALL) /* stat -> func */ + SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ + else { /* stat -> assignment */ + v.prev = NULL; + assignment(ls, &v, 1); + } +} + + +static void retstat (LexState *ls) { + /* stat -> RETURN explist */ + FuncState *fs = ls->fs; + expdesc e; + int first, nret; /* registers with returned values */ + luaX_next(ls); /* skip RETURN */ + if (block_follow(ls->t.token) || ls->t.token == ';') + first = nret = 0; /* return no values */ + else { + nret = explist1(ls, &e); /* optional return values */ + if (hasmultret(e.k)) { + luaK_setmultret(fs, &e); + if (e.k == VCALL && nret == 1) { /* tail call? */ + SET_OPCODE(getcode(fs,&e), OP_TAILCALL); + lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); + } + first = fs->nactvar; + nret = LUA_MULTRET; /* return all values */ + } + else { + if (nret == 1) /* only one single value? */ + first = luaK_exp2anyreg(fs, &e); + else { + luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ + first = fs->nactvar; /* return all `active' values */ + lua_assert(nret == fs->freereg - first); + } + } + } + luaK_ret(fs, first, nret); +} + + +static int statement (LexState *ls) { + int line = ls->linenumber; /* may be needed for error messages */ + switch (ls->t.token) { + case TK_IF: { /* stat -> ifstat */ + ifstat(ls, line); + return 0; + } + case TK_WHILE: { /* stat -> whilestat */ + whilestat(ls, line); + return 0; + } + case TK_DO: { /* stat -> DO block END */ + luaX_next(ls); /* skip DO */ + block(ls); + check_match(ls, TK_END, TK_DO, line); + return 0; + } + case TK_FOR: { /* stat -> forstat */ + forstat(ls, line); + return 0; + } + case TK_REPEAT: { /* stat -> repeatstat */ + repeatstat(ls, line); + return 0; + } + case TK_FUNCTION: { + funcstat(ls, line); /* stat -> funcstat */ + return 0; + } + case TK_LOCAL: { /* stat -> localstat */ + luaX_next(ls); /* skip LOCAL */ + if (testnext(ls, TK_FUNCTION)) /* local function? */ + localfunc(ls); + else + localstat(ls); + return 0; + } + case TK_RETURN: { /* stat -> retstat */ + retstat(ls); + return 1; /* must be last statement */ + } + case TK_BREAK: { /* stat -> breakstat */ + luaX_next(ls); /* skip BREAK */ + breakstat(ls); + return 1; /* must be last statement */ + } + default: { + exprstat(ls); + return 0; /* to avoid warnings */ + } + } +} + + +static void chunk (LexState *ls) { + /* chunk -> { stat [`;'] } */ + int islast = 0; + enterlevel(ls); + while (!islast && !block_follow(ls->t.token)) { + islast = statement(ls); + testnext(ls, ';'); + lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + ls->fs->freereg >= ls->fs->nactvar); + ls->fs->freereg = ls->fs->nactvar; /* free registers */ + } + leavelevel(ls); +} + +/* }====================================================================== */ diff --git a/lua/src/lparser.h b/lua/src/lparser.h new file mode 100644 index 0000000000..18836afd1c --- /dev/null +++ b/lua/src/lparser.h @@ -0,0 +1,82 @@ +/* +** $Id: lparser.h,v 1.57.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +#ifndef lparser_h +#define lparser_h + +#include "llimits.h" +#include "lobject.h" +#include "lzio.h" + + +/* +** Expression descriptor +*/ + +typedef enum { + VVOID, /* no value */ + VNIL, + VTRUE, + VFALSE, + VK, /* info = index of constant in `k' */ + VKNUM, /* nval = numerical value */ + VLOCAL, /* info = local register */ + VUPVAL, /* info = index of upvalue in `upvalues' */ + VGLOBAL, /* info = index of table; aux = index of global name in `k' */ + VINDEXED, /* info = table register; aux = index register (or `k') */ + VJMP, /* info = instruction pc */ + VRELOCABLE, /* info = instruction pc */ + VNONRELOC, /* info = result register */ + VCALL, /* info = instruction pc */ + VVARARG /* info = instruction pc */ +} expkind; + +typedef struct expdesc { + expkind k; + union { + struct { int info, aux; } s; + lua_Number nval; + } u; + int t; /* patch list of `exit when true' */ + int f; /* patch list of `exit when false' */ +} expdesc; + + +typedef struct upvaldesc { + lu_byte k; + lu_byte info; +} upvaldesc; + + +struct BlockCnt; /* defined in lparser.c */ + + +/* state needed to generate code for a given function */ +typedef struct FuncState { + Proto *f; /* current function header */ + Table *h; /* table to find (and reuse) elements in `k' */ + struct FuncState *prev; /* enclosing function */ + struct LexState *ls; /* lexical state */ + struct lua_State *L; /* copy of the Lua state */ + struct BlockCnt *bl; /* chain of current blocks */ + int pc; /* next position to code (equivalent to `ncode') */ + int lasttarget; /* `pc' of last `jump target' */ + int jpc; /* list of pending jumps to `pc' */ + int freereg; /* first free register */ + int nk; /* number of elements in `k' */ + int np; /* number of elements in `p' */ + short nlocvars; /* number of elements in `locvars' */ + lu_byte nactvar; /* number of active local variables */ + upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */ + unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */ +} FuncState; + + +LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + const char *name); + + +#endif diff --git a/lua/src/lstate.c b/lua/src/lstate.c new file mode 100644 index 0000000000..4313b83a0c --- /dev/null +++ b/lua/src/lstate.c @@ -0,0 +1,214 @@ +/* +** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + + +#include + +#define lstate_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +#define state_size(x) (sizeof(x) + LUAI_EXTRASPACE) +#define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE) +#define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE)) + + +/* +** Main thread combines a thread state and the global state +*/ +typedef struct LG { + lua_State l; + global_State g; +} LG; + + + +static void stack_init (lua_State *L1, lua_State *L) { + /* initialize CallInfo array */ + L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); + L1->ci = L1->base_ci; + L1->size_ci = BASIC_CI_SIZE; + L1->end_ci = L1->base_ci + L1->size_ci - 1; + /* initialize stack array */ + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); + L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; + L1->top = L1->stack; + L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; + /* initialize first ci */ + L1->ci->func = L1->top; + setnilvalue(L1->top++); /* `function' entry for this `ci' */ + L1->base = L1->ci->base = L1->top; + L1->ci->top = L1->top + LUA_MINSTACK; +} + + +static void freestack (lua_State *L, lua_State *L1) { + luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); + luaM_freearray(L, L1->stack, L1->stacksize, TValue); +} + + +/* +** open parts that may cause memory-allocation errors +*/ +static void f_luaopen (lua_State *L, void *ud) { + global_State *g = G(L); + UNUSED(ud); + stack_init(L, L); /* init stack */ + sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ + sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ + luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + luaT_init(L); + luaX_init(L); + luaS_fix(luaS_newliteral(L, MEMERRMSG)); + g->GCthreshold = 4*g->totalbytes; +} + + +static void preinit_state (lua_State *L, global_State *g) { + G(L) = g; + L->stack = NULL; + L->stacksize = 0; + L->errorJmp = NULL; + L->hook = NULL; + L->hookmask = 0; + L->basehookcount = 0; + L->allowhook = 1; + resethookcount(L); + L->openupval = NULL; + L->size_ci = 0; + L->nCcalls = L->baseCcalls = 0; + L->status = 0; + L->base_ci = L->ci = NULL; + L->savedpc = NULL; + L->errfunc = 0; + setnilvalue(gt(L)); +} + + +static void close_state (lua_State *L) { + global_State *g = G(L); + luaF_close(L, L->stack); /* close all upvalues for this thread */ + luaC_freeall(L); /* collect all objects */ + lua_assert(g->rootgc == obj2gco(L)); + lua_assert(g->strt.nuse == 0); + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); + luaZ_freebuffer(L, &g->buff); + freestack(L, L); + lua_assert(g->totalbytes == sizeof(LG)); + (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); +} + + +lua_State *luaE_newthread (lua_State *L) { + lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); + luaC_link(L, obj2gco(L1), LUA_TTHREAD); + preinit_state(L1, G(L)); + stack_init(L1, L); /* init stack */ + setobj2n(L, gt(L1), gt(L)); /* share table of globals */ + L1->hookmask = L->hookmask; + L1->basehookcount = L->basehookcount; + L1->hook = L->hook; + resethookcount(L1); + lua_assert(iswhite(obj2gco(L1))); + return L1; +} + + +void luaE_freethread (lua_State *L, lua_State *L1) { + luaF_close(L1, L1->stack); /* close all upvalues for this thread */ + lua_assert(L1->openupval == NULL); + luai_userstatefree(L1); + freestack(L, L1); + luaM_freemem(L, fromstate(L1), state_size(lua_State)); +} + + +LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + int i; + lua_State *L; + global_State *g; + void *l = (*f)(ud, NULL, 0, state_size(LG)); + if (l == NULL) return NULL; + L = tostate(l); + g = &((LG *)L)->g; + L->next = NULL; + L->tt = LUA_TTHREAD; + g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); + L->marked = luaC_white(g); + set2bits(L->marked, FIXEDBIT, SFIXEDBIT); + preinit_state(L, g); + g->frealloc = f; + g->ud = ud; + g->mainthread = L; + g->uvhead.u.l.prev = &g->uvhead; + g->uvhead.u.l.next = &g->uvhead; + g->GCthreshold = 0; /* mark it as unfinished state */ + g->strt.size = 0; + g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(registry(L)); + luaZ_initbuffer(L, &g->buff); + g->panic = NULL; + g->gcstate = GCSpause; + g->rootgc = obj2gco(L); + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + g->tmudata = NULL; + g->totalbytes = sizeof(LG); + g->gcpause = LUAI_GCPAUSE; + g->gcstepmul = LUAI_GCMUL; + g->gcdept = 0; + for (i=0; imt[i] = NULL; + if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; + } + else + luai_userstateopen(L); + return L; +} + + +static void callallgcTM (lua_State *L, void *ud) { + UNUSED(ud); + luaC_callGCTM(L); /* call GC metamethods for all udata */ +} + + +LUA_API void lua_close (lua_State *L) { + L = G(L)->mainthread; /* only the main thread can be closed */ + lua_lock(L); + luaF_close(L, L->stack); /* close all upvalues for this thread */ + luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ + L->errfunc = 0; /* no error function during GC metamethods */ + do { /* repeat until no more errors */ + L->ci = L->base_ci; + L->base = L->top = L->ci->base; + L->nCcalls = L->baseCcalls = 0; + } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); + lua_assert(G(L)->tmudata == NULL); + luai_userstateclose(L); + close_state(L); +} + diff --git a/lua/src/lstate.h b/lua/src/lstate.h new file mode 100644 index 0000000000..3bc575b6bc --- /dev/null +++ b/lua/src/lstate.h @@ -0,0 +1,169 @@ +/* +** $Id: lstate.h,v 2.24.1.2 2008/01/03 15:20:39 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + +#ifndef lstate_h +#define lstate_h + +#include "lua.h" + +#include "lobject.h" +#include "ltm.h" +#include "lzio.h" + + + +struct lua_longjmp; /* defined in ldo.c */ + + +/* table of globals */ +#define gt(L) (&L->l_gt) + +/* registry */ +#define registry(L) (&G(L)->l_registry) + + +/* extra stack space to handle TM calls and some other extras */ +#define EXTRA_STACK 5 + + +#define BASIC_CI_SIZE 8 + +#define BASIC_STACK_SIZE (2*LUA_MINSTACK) + + + +typedef struct stringtable { + GCObject **hash; + lu_int32 nuse; /* number of elements */ + int size; +} stringtable; + + +/* +** informations about a call +*/ +typedef struct CallInfo { + StkId base; /* base for this function */ + StkId func; /* function index in the stack */ + StkId top; /* top for this function */ + const Instruction *savedpc; + int nresults; /* expected number of results from this function */ + int tailcalls; /* number of tail calls lost under this entry */ +} CallInfo; + + + +#define curr_func(L) (clvalue(L->ci->func)) +#define ci_func(ci) (clvalue((ci)->func)) +#define f_isLua(ci) (!ci_func(ci)->c.isC) +#define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci)) + + +/* +** `global state', shared by all threads of this state +*/ +typedef struct global_State { + stringtable strt; /* hash table for strings */ + lua_Alloc frealloc; /* function to reallocate memory */ + void *ud; /* auxiliary data to `frealloc' */ + lu_byte currentwhite; + lu_byte gcstate; /* state of garbage collector */ + int sweepstrgc; /* position of sweep in `strt' */ + GCObject *rootgc; /* list of all collectable objects */ + GCObject **sweepgc; /* position of sweep in `rootgc' */ + GCObject *gray; /* list of gray objects */ + GCObject *grayagain; /* list of objects to be traversed atomically */ + GCObject *weak; /* list of weak tables (to be cleared) */ + GCObject *tmudata; /* last element of list of userdata to be GC */ + Mbuffer buff; /* temporary buffer for string concatentation */ + lu_mem GCthreshold; + lu_mem totalbytes; /* number of bytes currently allocated */ + lu_mem estimate; /* an estimate of number of bytes actually in use */ + lu_mem gcdept; /* how much GC is `behind schedule' */ + int gcpause; /* size of pause between successive GCs */ + int gcstepmul; /* GC `granularity' */ + lua_CFunction panic; /* to be called in unprotected errors */ + TValue l_registry; + struct lua_State *mainthread; + UpVal uvhead; /* head of double-linked list of all open upvalues */ + struct Table *mt[NUM_TAGS]; /* metatables for basic types */ + TString *tmname[TM_N]; /* array with tag-method names */ +} global_State; + + +/* +** `per thread' state +*/ +struct lua_State { + CommonHeader; + lu_byte status; + StkId top; /* first free slot in the stack */ + StkId base; /* base of current function */ + global_State *l_G; + CallInfo *ci; /* call info for current function */ + const Instruction *savedpc; /* `savedpc' of current function */ + StkId stack_last; /* last free slot in the stack */ + StkId stack; /* stack base */ + CallInfo *end_ci; /* points after end of ci array*/ + CallInfo *base_ci; /* array of CallInfo's */ + int stacksize; + int size_ci; /* size of array `base_ci' */ + unsigned short nCcalls; /* number of nested C calls */ + unsigned short baseCcalls; /* nested C calls when resuming coroutine */ + lu_byte hookmask; + lu_byte allowhook; + int basehookcount; + int hookcount; + lua_Hook hook; + TValue l_gt; /* table of globals */ + TValue env; /* temporary place for environments */ + GCObject *openupval; /* list of open upvalues in this stack */ + GCObject *gclist; + struct lua_longjmp *errorJmp; /* current error recover point */ + ptrdiff_t errfunc; /* current error handling function (stack index) */ +}; + + +#define G(L) (L->l_G) + + +/* +** Union of all collectable objects +*/ +union GCObject { + GCheader gch; + union TString ts; + union Udata u; + union Closure cl; + struct Table h; + struct Proto p; + struct UpVal uv; + struct lua_State th; /* thread */ +}; + + +/* macros to convert a GCObject into a specific value */ +#define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) +#define gco2ts(o) (&rawgco2ts(o)->tsv) +#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) +#define gco2u(o) (&rawgco2u(o)->uv) +#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) +#define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) +#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) +#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) +#define ngcotouv(o) \ + check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv)) +#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) + +/* macro to convert any Lua object into a GCObject */ +#define obj2gco(v) (cast(GCObject *, (v))) + + +LUAI_FUNC lua_State *luaE_newthread (lua_State *L); +LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); + +#endif + diff --git a/lua/src/lstring.c b/lua/src/lstring.c new file mode 100644 index 0000000000..49113151cc --- /dev/null +++ b/lua/src/lstring.c @@ -0,0 +1,111 @@ +/* +** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ +** String table (keeps all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + + +#include + +#define lstring_c +#define LUA_CORE + +#include "lua.h" + +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" + + + +void luaS_resize (lua_State *L, int newsize) { + GCObject **newhash; + stringtable *tb; + int i; + if (G(L)->gcstate == GCSsweepstring) + return; /* cannot resize during GC traverse */ + newhash = luaM_newvector(L, newsize, GCObject *); + tb = &G(L)->strt; + for (i=0; isize; i++) { + GCObject *p = tb->hash[i]; + while (p) { /* for each node in the list */ + GCObject *next = p->gch.next; /* save next */ + unsigned int h = gco2ts(p)->hash; + int h1 = lmod(h, newsize); /* new position */ + lua_assert(cast_int(h%newsize) == lmod(h, newsize)); + p->gch.next = newhash[h1]; /* chain it */ + newhash[h1] = p; + p = next; + } + } + luaM_freearray(L, tb->hash, tb->size, TString *); + tb->size = newsize; + tb->hash = newhash; +} + + +static TString *newlstr (lua_State *L, const char *str, size_t l, + unsigned int h) { + TString *ts; + stringtable *tb; + if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) + luaM_toobig(L); + ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); + ts->tsv.len = l; + ts->tsv.hash = h; + ts->tsv.marked = luaC_white(G(L)); + ts->tsv.tt = LUA_TSTRING; + ts->tsv.reserved = 0; + memcpy(ts+1, str, l*sizeof(char)); + ((char *)(ts+1))[l] = '\0'; /* ending 0 */ + tb = &G(L)->strt; + h = lmod(h, tb->size); + ts->tsv.next = tb->hash[h]; /* chain new entry */ + tb->hash[h] = obj2gco(ts); + tb->nuse++; + if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) + luaS_resize(L, tb->size*2); /* too crowded */ + return ts; +} + + +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + GCObject *o; + unsigned int h = cast(unsigned int, l); /* seed */ + size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ + size_t l1; + for (l1=l; l1>=step; l1-=step) /* compute hash */ + h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); + for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; + o != NULL; + o = o->gch.next) { + TString *ts = rawgco2ts(o); + if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { + /* string may be dead */ + if (isdead(G(L), o)) changewhite(o); + return ts; + } + } + return newlstr(L, str, l, h); /* not found */ +} + + +Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { + Udata *u; + if (s > MAX_SIZET - sizeof(Udata)) + luaM_toobig(L); + u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); + u->uv.marked = luaC_white(G(L)); /* is not finalized */ + u->uv.tt = LUA_TUSERDATA; + u->uv.len = s; + u->uv.metatable = NULL; + u->uv.env = e; + /* chain it on udata list (after main thread) */ + u->uv.next = G(L)->mainthread->next; + G(L)->mainthread->next = obj2gco(u); + return u; +} + diff --git a/lua/src/lstring.h b/lua/src/lstring.h new file mode 100644 index 0000000000..73a2ff8b38 --- /dev/null +++ b/lua/src/lstring.h @@ -0,0 +1,31 @@ +/* +** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $ +** String table (keep all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#ifndef lstring_h +#define lstring_h + + +#include "lgc.h" +#include "lobject.h" +#include "lstate.h" + + +#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char)) + +#define sizeudata(u) (sizeof(union Udata)+(u)->len) + +#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s))) +#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ + (sizeof(s)/sizeof(char))-1)) + +#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) + +LUAI_FUNC void luaS_resize (lua_State *L, int newsize); +LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); +LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); + + +#endif diff --git a/lua/src/lstrlib.c b/lua/src/lstrlib.c new file mode 100644 index 0000000000..1b4763d4ee --- /dev/null +++ b/lua/src/lstrlib.c @@ -0,0 +1,869 @@ +/* +** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $ +** Standard library for string operations and pattern-matching +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include +#include + +#define lstrlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* macro to `unsign' a character */ +#define uchar(c) ((unsigned char)(c)) + + + +static int str_len (lua_State *L) { + size_t l; + luaL_checklstring(L, 1, &l); + lua_pushinteger(L, l); + return 1; +} + + +static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { + /* relative string position: negative means back from end */ + if (pos < 0) pos += (ptrdiff_t)len + 1; + return (pos >= 0) ? pos : 0; +} + + +static int str_sub (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); + ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); + if (start < 1) start = 1; + if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; + if (start <= end) + lua_pushlstring(L, s+start-1, end-start+1); + else lua_pushliteral(L, ""); + return 1; +} + + +static int str_reverse (lua_State *L) { + size_t l; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + luaL_buffinit(L, &b); + while (l--) luaL_addchar(&b, s[l]); + luaL_pushresult(&b); + return 1; +} + + +static int str_lower (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + luaL_buffinit(L, &b); + for (i=0; i 0) + luaL_addlstring(&b, s, l); + luaL_pushresult(&b); + return 1; +} + + +static int str_byte (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); + ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); + int n, i; + if (posi <= 0) posi = 1; + if ((size_t)pose > l) pose = l; + if (posi > pose) return 0; /* empty interval; return no values */ + n = (int)(pose - posi + 1); + if (posi + n <= pose) /* overflow? */ + luaL_error(L, "string slice too long"); + luaL_checkstack(L, n, "string slice too long"); + for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) + return luaL_error(ms->L, "invalid capture index"); + return l; +} + + +static int capture_to_close (MatchState *ms) { + int level = ms->level; + for (level--; level>=0; level--) + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms->L, "invalid pattern capture"); +} + + +static const char *classend (MatchState *ms, const char *p) { + switch (*p++) { + case L_ESC: { + if (*p == '\0') + luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); + return p+1; + } + case '[': { + if (*p == '^') p++; + do { /* look for a `]' */ + if (*p == '\0') + luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); + if (*(p++) == L_ESC && *p != '\0') + p++; /* skip escapes (e.g. `%]') */ + } while (*p != ']'); + return p+1; + } + default: { + return p; + } + } +} + + +static int match_class (int c, int cl) { + int res; + switch (tolower(cl)) { + case 'a' : res = isalpha(c); break; + case 'c' : res = iscntrl(c); break; + case 'd' : res = isdigit(c); break; + case 'l' : res = islower(c); break; + case 'p' : res = ispunct(c); break; + case 's' : res = isspace(c); break; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; + case 'z' : res = (c == 0); break; + default: return (cl == c); + } + return (islower(cl) ? res : !res); +} + + +static int matchbracketclass (int c, const char *p, const char *ec) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the `^' */ + } + while (++p < ec) { + if (*p == L_ESC) { + p++; + if (match_class(c, uchar(*p))) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < ec)) { + p+=2; + if (uchar(*(p-2)) <= c && c <= uchar(*p)) + return sig; + } + else if (uchar(*p) == c) return sig; + } + return !sig; +} + + +static int singlematch (int c, const char *p, const char *ep) { + switch (*p) { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); + } +} + + +static const char *match (MatchState *ms, const char *s, const char *p); + + +static const char *matchbalance (MatchState *ms, const char *s, + const char *p) { + if (*p == 0 || *(p+1) == 0) + luaL_error(ms->L, "unbalanced pattern"); + if (*s != *p) return NULL; + else { + int b = *p; + int e = *(p+1); + int cont = 1; + while (++s < ms->src_end) { + if (*s == e) { + if (--cont == 0) return s+1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ +} + + +static const char *max_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + ptrdiff_t i = 0; /* counts maximum expand for item */ + while ((s+i)src_end && singlematch(uchar(*(s+i)), p, ep)) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i>=0) { + const char *res = match(ms, (s+i), ep+1); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return NULL; +} + + +static const char *min_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + for (;;) { + const char *res = match(ms, s, ep+1); + if (res != NULL) + return res; + else if (ssrc_end && singlematch(uchar(*s), p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} + + +static const char *start_capture (MatchState *ms, const char *s, + const char *p, int what) { + const char *res; + int level = ms->level; + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); + ms->capture[level].init = s; + ms->capture[level].len = what; + ms->level = level+1; + if ((res=match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ + return res; +} + + +static const char *end_capture (MatchState *ms, const char *s, + const char *p) { + int l = capture_to_close(ms); + const char *res; + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ + return res; +} + + +static const char *match_capture (MatchState *ms, const char *s, int l) { + size_t len; + l = check_capture(ms, l); + len = ms->capture[l].len; + if ((size_t)(ms->src_end-s) >= len && + memcmp(ms->capture[l].init, s, len) == 0) + return s+len; + else return NULL; +} + + +static const char *match (MatchState *ms, const char *s, const char *p) { + init: /* using goto's to optimize tail recursion */ + switch (*p) { + case '(': { /* start capture */ + if (*(p+1) == ')') /* position capture? */ + return start_capture(ms, s, p+2, CAP_POSITION); + else + return start_capture(ms, s, p+1, CAP_UNFINISHED); + } + case ')': { /* end capture */ + return end_capture(ms, s, p+1); + } + case L_ESC: { + switch (*(p+1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p+2); + if (s == NULL) return NULL; + p+=4; goto init; /* else return match(ms, s, p+4); */ + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (*p != '[') + luaL_error(ms->L, "missing " LUA_QL("[") " after " + LUA_QL("%%f") " in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s-1); + if (matchbracketclass(uchar(previous), p, ep-1) || + !matchbracketclass(uchar(*s), p, ep-1)) return NULL; + p=ep; goto init; /* else return match(ms, s, ep); */ + } + default: { + if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p+1))); + if (s == NULL) return NULL; + p+=2; goto init; /* else return match(ms, s, p+2) */ + } + goto dflt; /* case default */ + } + } + } + case '\0': { /* end of pattern */ + return s; /* match succeeded */ + } + case '$': { + if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ + return (s == ms->src_end) ? s : NULL; /* check end of string */ + else goto dflt; + } + default: dflt: { /* it is a pattern item */ + const char *ep = classend(ms, p); /* points to what is next */ + int m = ssrc_end && singlematch(uchar(*s), p, ep); + switch (*ep) { + case '?': { /* optional */ + const char *res; + if (m && ((res=match(ms, s+1, ep+1)) != NULL)) + return res; + p=ep+1; goto init; /* else return match(ms, s, ep+1); */ + } + case '*': { /* 0 or more repetitions */ + return max_expand(ms, s, p, ep); + } + case '+': { /* 1 or more repetitions */ + return (m ? max_expand(ms, s+1, p, ep) : NULL); + } + case '-': { /* 0 or more repetitions (minimum) */ + return min_expand(ms, s, p, ep); + } + default: { + if (!m) return NULL; + s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ + } + } + } + } +} + + + +static const char *lmemfind (const char *s1, size_t l1, + const char *s2, size_t l2) { + if (l2 == 0) return s1; /* empty strings are everywhere */ + else if (l2 > l1) return NULL; /* avoids a negative `l1' */ + else { + const char *init; /* to search for a `*s2' inside `s1' */ + l2--; /* 1st char will be checked by `memchr' */ + l1 = l1-l2; /* `s2' cannot be found after that */ + while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { + init++; /* 1st char is already checked */ + if (memcmp(init, s2+1, l2) == 0) + return init-1; + else { /* correct `l1' and `s1' to try again */ + l1 -= init-s1; + s1 = init; + } + } + return NULL; /* not found */ + } +} + + +static void push_onecapture (MatchState *ms, int i, const char *s, + const char *e) { + if (i >= ms->level) { + if (i == 0) /* ms->level == 0, too */ + lua_pushlstring(ms->L, s, e - s); /* add whole match */ + else + luaL_error(ms->L, "invalid capture index"); + } + else { + ptrdiff_t l = ms->capture[i].len; + if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); + if (l == CAP_POSITION) + lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); + else + lua_pushlstring(ms->L, ms->capture[i].init, l); + } +} + + +static int push_captures (MatchState *ms, const char *s, const char *e) { + int i; + int nlevels = (ms->level == 0 && s) ? 1 : ms->level; + luaL_checkstack(ms->L, nlevels, "too many captures"); + for (i = 0; i < nlevels; i++) + push_onecapture(ms, i, s, e); + return nlevels; /* number of strings pushed */ +} + + +static int str_find_aux (lua_State *L, int find) { + size_t l1, l2; + const char *s = luaL_checklstring(L, 1, &l1); + const char *p = luaL_checklstring(L, 2, &l2); + ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; + if (init < 0) init = 0; + else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; + if (find && (lua_toboolean(L, 4) || /* explicit request? */ + strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ + /* do a plain search */ + const char *s2 = lmemfind(s+init, l1-init, p, l2); + if (s2) { + lua_pushinteger(L, s2-s+1); + lua_pushinteger(L, s2-s+l2); + return 2; + } + } + else { + MatchState ms; + int anchor = (*p == '^') ? (p++, 1) : 0; + const char *s1=s+init; + ms.L = L; + ms.src_init = s; + ms.src_end = s+l1; + do { + const char *res; + ms.level = 0; + if ((res=match(&ms, s1, p)) != NULL) { + if (find) { + lua_pushinteger(L, s1-s+1); /* start */ + lua_pushinteger(L, res-s); /* end */ + return push_captures(&ms, NULL, 0) + 2; + } + else + return push_captures(&ms, s1, res); + } + } while (s1++ < ms.src_end && !anchor); + } + lua_pushnil(L); /* not found */ + return 1; +} + + +static int str_find (lua_State *L) { + return str_find_aux(L, 1); +} + + +static int str_match (lua_State *L) { + return str_find_aux(L, 0); +} + + +static int gmatch_aux (lua_State *L) { + MatchState ms; + size_t ls; + const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); + const char *p = lua_tostring(L, lua_upvalueindex(2)); + const char *src; + ms.L = L; + ms.src_init = s; + ms.src_end = s+ls; + for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); + src <= ms.src_end; + src++) { + const char *e; + ms.level = 0; + if ((e = match(&ms, src, p)) != NULL) { + lua_Integer newstart = e-s; + if (e == src) newstart++; /* empty match? go at least one position */ + lua_pushinteger(L, newstart); + lua_replace(L, lua_upvalueindex(3)); + return push_captures(&ms, src, e); + } + } + return 0; /* not found */ +} + + +static int gmatch (lua_State *L) { + luaL_checkstring(L, 1); + luaL_checkstring(L, 2); + lua_settop(L, 2); + lua_pushinteger(L, 0); + lua_pushcclosure(L, gmatch_aux, 3); + return 1; +} + + +static int gfind_nodef (lua_State *L) { + return luaL_error(L, LUA_QL("string.gfind") " was renamed to " + LUA_QL("string.gmatch")); +} + + +static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + size_t l, i; + const char *news = lua_tolstring(ms->L, 3, &l); + for (i = 0; i < l; i++) { + if (news[i] != L_ESC) + luaL_addchar(b, news[i]); + else { + i++; /* skip ESC */ + if (!isdigit(uchar(news[i]))) + luaL_addchar(b, news[i]); + else if (news[i] == '0') + luaL_addlstring(b, s, e - s); + else { + push_onecapture(ms, news[i] - '1', s, e); + luaL_addvalue(b); /* add capture to accumulated result */ + } + } + } +} + + +static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + lua_State *L = ms->L; + switch (lua_type(L, 3)) { + case LUA_TNUMBER: + case LUA_TSTRING: { + add_s(ms, b, s, e); + return; + } + case LUA_TFUNCTION: { + int n; + lua_pushvalue(L, 3); + n = push_captures(ms, s, e); + lua_call(L, n, 1); + break; + } + case LUA_TTABLE: { + push_onecapture(ms, 0, s, e); + lua_gettable(L, 3); + break; + } + } + if (!lua_toboolean(L, -1)) { /* nil or false? */ + lua_pop(L, 1); + lua_pushlstring(L, s, e - s); /* keep original text */ + } + else if (!lua_isstring(L, -1)) + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_addvalue(b); /* add result to accumulator */ +} + + +static int str_gsub (lua_State *L) { + size_t srcl; + const char *src = luaL_checklstring(L, 1, &srcl); + const char *p = luaL_checkstring(L, 2); + int tr = lua_type(L, 3); + int max_s = luaL_optint(L, 4, srcl+1); + int anchor = (*p == '^') ? (p++, 1) : 0; + int n = 0; + MatchState ms; + luaL_Buffer b; + luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || + tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, + "string/function/table expected"); + luaL_buffinit(L, &b); + ms.L = L; + ms.src_init = src; + ms.src_end = src+srcl; + while (n < max_s) { + const char *e; + ms.level = 0; + e = match(&ms, src, p); + if (e) { + n++; + add_value(&ms, &b, src, e); + } + if (e && e>src) /* non empty match? */ + src = e; /* skip it */ + else if (src < ms.src_end) + luaL_addchar(&b, *src++); + else break; + if (anchor) break; + } + luaL_addlstring(&b, src, ms.src_end-src); + luaL_pushresult(&b); + lua_pushinteger(L, n); /* number of substitutions */ + return 2; +} + +/* }====================================================== */ + + +/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ +#define MAX_ITEM 512 +/* valid flags in a format specification */ +#define FLAGS "-+ #0" +/* +** maximum size of each format specification (such as '%-099.99d') +** (+10 accounts for %99.99x plus margin of error) +*/ +#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) + + +static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + luaL_addchar(b, '"'); + while (l--) { + switch (*s) { + case '"': case '\\': case '\n': { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); + break; + } + case '\r': { + luaL_addlstring(b, "\\r", 2); + break; + } + case '\0': { + luaL_addlstring(b, "\\000", 4); + break; + } + default: { + luaL_addchar(b, *s); + break; + } + } + s++; + } + luaL_addchar(b, '"'); +} + +static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { + const char *p = strfrmt; + while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ + if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) + luaL_error(L, "invalid format (repeated flags)"); + if (isdigit(uchar(*p))) p++; /* skip width */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + if (*p == '.') { + p++; + if (isdigit(uchar(*p))) p++; /* skip precision */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + } + if (isdigit(uchar(*p))) + luaL_error(L, "invalid format (width or precision too long)"); + *(form++) = '%'; + strncpy(form, strfrmt, p - strfrmt + 1); + form += p - strfrmt + 1; + *form = '\0'; + return p; +} + + +static void addintlen (char *form) { + size_t l = strlen(form); + char spec = form[l - 1]; + strcpy(form + l - 1, LUA_INTFRMLEN); + form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; + form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; +} + + +static int str_format (lua_State *L) { + int arg = 1; + size_t sfl; + const char *strfrmt = luaL_checklstring(L, arg, &sfl); + const char *strfrmt_end = strfrmt+sfl; + luaL_Buffer b; + luaL_buffinit(L, &b); + while (strfrmt < strfrmt_end) { + if (*strfrmt != L_ESC) + luaL_addchar(&b, *strfrmt++); + else if (*++strfrmt == L_ESC) + luaL_addchar(&b, *strfrmt++); /* %% */ + else { /* format item */ + char form[MAX_FORMAT]; /* to store the format (`%...') */ + char buff[MAX_ITEM]; /* to store the formatted item */ + arg++; + strfrmt = scanformat(L, strfrmt, form); + switch (*strfrmt++) { + case 'c': { + sprintf(buff, form, (int)luaL_checknumber(L, arg)); + break; + } + case 'd': case 'i': { + addintlen(form); + sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); + break; + } + case 'o': case 'u': case 'x': case 'X': { + addintlen(form); + sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); + break; + } + case 'e': case 'E': case 'f': + case 'g': case 'G': { + sprintf(buff, form, (double)luaL_checknumber(L, arg)); + break; + } + case 'q': { + addquoted(L, &b, arg); + continue; /* skip the 'addsize' at the end */ + } + case 's': { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + if (!strchr(form, '.') && l >= 100) { + /* no precision and string is too long to be formatted; + keep original string */ + lua_pushvalue(L, arg); + luaL_addvalue(&b); + continue; /* skip the `addsize' at the end */ + } + else { + sprintf(buff, form, s); + break; + } + } + default: { /* also treat cases `pnLlh' */ + return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " + LUA_QL("format"), *(strfrmt - 1)); + } + } + luaL_addlstring(&b, buff, strlen(buff)); + } + } + luaL_pushresult(&b); + return 1; +} + + +static const luaL_Reg strlib[] = { + {"byte", str_byte}, + {"char", str_char}, + {"dump", str_dump}, + {"find", str_find}, + {"format", str_format}, + {"gfind", gfind_nodef}, + {"gmatch", gmatch}, + {"gsub", str_gsub}, + {"len", str_len}, + {"lower", str_lower}, + {"match", str_match}, + {"rep", str_rep}, + {"reverse", str_reverse}, + {"sub", str_sub}, + {"upper", str_upper}, + {NULL, NULL} +}; + + +static void createmetatable (lua_State *L) { + lua_createtable(L, 0, 1); /* create metatable for strings */ + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); + lua_setmetatable(L, -2); /* set string metatable */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* string library... */ + lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ + lua_pop(L, 1); /* pop metatable */ +} + + +/* +** Open string library +*/ +LUALIB_API int luaopen_string (lua_State *L) { + luaL_register(L, LUA_STRLIBNAME, strlib); +#if defined(LUA_COMPAT_GFIND) + lua_getfield(L, -1, "gmatch"); + lua_setfield(L, -2, "gfind"); +#endif + createmetatable(L); + return 1; +} + diff --git a/lua/src/ltable.c b/lua/src/ltable.c new file mode 100644 index 0000000000..ec84f4fabc --- /dev/null +++ b/lua/src/ltable.c @@ -0,0 +1,588 @@ +/* +** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + + +/* +** Implementation of tables (aka arrays, objects, or hash tables). +** Tables keep its elements in two parts: an array part and a hash part. +** Non-negative integer keys are all candidates to be kept in the array +** part. The actual size of the array is the largest `n' such that at +** least half the slots between 0 and n are in use. +** Hash uses a mix of chained scatter table with Brent's variation. +** A main invariant of these tables is that, if an element is not +** in its main position (i.e. the `original' position that its hash gives +** to it), then the colliding element is in its own main position. +** Hence even when the load factor reaches 100%, performance remains good. +*/ + +#include +#include + +#define ltable_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "ltable.h" + + +/* +** max size of array part is 2^MAXBITS +*/ +#if LUAI_BITSINT > 26 +#define MAXBITS 26 +#else +#define MAXBITS (LUAI_BITSINT-2) +#endif + +#define MAXASIZE (1 << MAXBITS) + + +#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) + +#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) +#define hashboolean(t,p) hashpow2(t, p) + + +/* +** for some types, it is better to avoid modulus by power of 2, as +** they tend to have many 2 factors. +*/ +#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) + + +#define hashpointer(t,p) hashmod(t, IntPoint(p)) + + +/* +** number of ints inside a lua_Number +*/ +#define numints cast_int(sizeof(lua_Number)/sizeof(int)) + + + +#define dummynode (&dummynode_) + +static const Node dummynode_ = { + {{NULL}, LUA_TNIL}, /* value */ + {{{NULL}, LUA_TNIL, NULL}} /* key */ +}; + + +/* +** hash for lua_Numbers +*/ +static Node *hashnum (const Table *t, lua_Number n) { + unsigned int a[numints]; + int i; + if (luai_numeq(n, 0)) /* avoid problems with -0 */ + return gnode(t, 0); + memcpy(a, &n, sizeof(a)); + for (i = 1; i < numints; i++) a[0] += a[i]; + return hashmod(t, a[0]); +} + + + +/* +** returns the `main' position of an element in a table (that is, the index +** of its hash value) +*/ +static Node *mainposition (const Table *t, const TValue *key) { + switch (ttype(key)) { + case LUA_TNUMBER: + return hashnum(t, nvalue(key)); + case LUA_TSTRING: + return hashstr(t, rawtsvalue(key)); + case LUA_TBOOLEAN: + return hashboolean(t, bvalue(key)); + case LUA_TLIGHTUSERDATA: + return hashpointer(t, pvalue(key)); + default: + return hashpointer(t, gcvalue(key)); + } +} + + +/* +** returns the index for `key' if `key' is an appropriate key to live in +** the array part of the table, -1 otherwise. +*/ +static int arrayindex (const TValue *key) { + if (ttisnumber(key)) { + lua_Number n = nvalue(key); + int k; + lua_number2int(k, n); + if (luai_numeq(cast_num(k), n)) + return k; + } + return -1; /* `key' did not match some condition */ +} + + +/* +** returns the index of a `key' for table traversals. First goes all +** elements in the array part, then elements in the hash part. The +** beginning of a traversal is signalled by -1. +*/ +static int findindex (lua_State *L, Table *t, StkId key) { + int i; + if (ttisnil(key)) return -1; /* first iteration */ + i = arrayindex(key); + if (0 < i && i <= t->sizearray) /* is `key' inside array part? */ + return i-1; /* yes; that's the index (corrected to C) */ + else { + Node *n = mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in `next' */ + if (luaO_rawequalObj(key2tval(n), key) || + (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && + gcvalue(gkey(n)) == gcvalue(key))) { + i = cast_int(n - gnode(t, 0)); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return i + t->sizearray; + } + else n = gnext(n); + } while (n); + luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */ + return 0; /* to avoid warnings */ + } +} + + +int luaH_next (lua_State *L, Table *t, StkId key) { + int i = findindex(L, t, key); /* find original element */ + for (i++; i < t->sizearray; i++) { /* try first array part */ + if (!ttisnil(&t->array[i])) { /* a non-nil value? */ + setnvalue(key, cast_num(i+1)); + setobj2s(L, key+1, &t->array[i]); + return 1; + } + } + for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ + if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ + setobj2s(L, key, key2tval(gnode(t, i))); + setobj2s(L, key+1, gval(gnode(t, i))); + return 1; + } + } + return 0; /* no more elements */ +} + + +/* +** {============================================================= +** Rehash +** ============================================================== +*/ + + +static int computesizes (int nums[], int *narray) { + int i; + int twotoi; /* 2^i */ + int a = 0; /* number of elements smaller than 2^i */ + int na = 0; /* number of elements to go to array part */ + int n = 0; /* optimal size for array part */ + for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { + if (nums[i] > 0) { + a += nums[i]; + if (a > twotoi/2) { /* more than half elements present? */ + n = twotoi; /* optimal size (till now) */ + na = a; /* all elements smaller than n will go to array part */ + } + } + if (a == *narray) break; /* all elements already counted */ + } + *narray = n; + lua_assert(*narray/2 <= na && na <= *narray); + return na; +} + + +static int countint (const TValue *key, int *nums) { + int k = arrayindex(key); + if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ + nums[ceillog2(k)]++; /* count as such */ + return 1; + } + else + return 0; +} + + +static int numusearray (const Table *t, int *nums) { + int lg; + int ttlg; /* 2^lg */ + int ause = 0; /* summation of `nums' */ + int i = 1; /* count to traverse all array keys */ + for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ + int lc = 0; /* counter */ + int lim = ttlg; + if (lim > t->sizearray) { + lim = t->sizearray; /* adjust upper limit */ + if (i > lim) + break; /* no more elements to count */ + } + /* count elements in range (2^(lg-1), 2^lg] */ + for (; i <= lim; i++) { + if (!ttisnil(&t->array[i-1])) + lc++; + } + nums[lg] += lc; + ause += lc; + } + return ause; +} + + +static int numusehash (const Table *t, int *nums, int *pnasize) { + int totaluse = 0; /* total number of elements */ + int ause = 0; /* summation of `nums' */ + int i = sizenode(t); + while (i--) { + Node *n = &t->node[i]; + if (!ttisnil(gval(n))) { + ause += countint(key2tval(n), nums); + totaluse++; + } + } + *pnasize += ause; + return totaluse; +} + + +static void setarrayvector (lua_State *L, Table *t, int size) { + int i; + luaM_reallocvector(L, t->array, t->sizearray, size, TValue); + for (i=t->sizearray; iarray[i]); + t->sizearray = size; +} + + +static void setnodevector (lua_State *L, Table *t, int size) { + int lsize; + if (size == 0) { /* no elements to hash part? */ + t->node = cast(Node *, dummynode); /* use common `dummynode' */ + lsize = 0; + } + else { + int i; + lsize = ceillog2(size); + if (lsize > MAXBITS) + luaG_runerror(L, "table overflow"); + size = twoto(lsize); + t->node = luaM_newvector(L, size, Node); + for (i=0; ilsizenode = cast_byte(lsize); + t->lastfree = gnode(t, size); /* all positions are free */ +} + + +static void resize (lua_State *L, Table *t, int nasize, int nhsize) { + int i; + int oldasize = t->sizearray; + int oldhsize = t->lsizenode; + Node *nold = t->node; /* save old hash ... */ + if (nasize > oldasize) /* array part must grow? */ + setarrayvector(L, t, nasize); + /* create new hash part with appropriate size */ + setnodevector(L, t, nhsize); + if (nasize < oldasize) { /* array part must shrink? */ + t->sizearray = nasize; + /* re-insert elements from vanishing slice */ + for (i=nasize; iarray[i])) + setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]); + } + /* shrink array */ + luaM_reallocvector(L, t->array, oldasize, nasize, TValue); + } + /* re-insert elements from hash part */ + for (i = twoto(oldhsize) - 1; i >= 0; i--) { + Node *old = nold+i; + if (!ttisnil(gval(old))) + setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); + } + if (nold != dummynode) + luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ +} + + +void luaH_resizearray (lua_State *L, Table *t, int nasize) { + int nsize = (t->node == dummynode) ? 0 : sizenode(t); + resize(L, t, nasize, nsize); +} + + +static void rehash (lua_State *L, Table *t, const TValue *ek) { + int nasize, na; + int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */ + int i; + int totaluse; + for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ + nasize = numusearray(t, nums); /* count keys in array part */ + totaluse = nasize; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ + /* count extra key */ + nasize += countint(ek, nums); + totaluse++; + /* compute new size for array part */ + na = computesizes(nums, &nasize); + /* resize the table to new computed sizes */ + resize(L, t, nasize, totaluse - na); +} + + + +/* +** }============================================================= +*/ + + +Table *luaH_new (lua_State *L, int narray, int nhash) { + Table *t = luaM_new(L, Table); + luaC_link(L, obj2gco(t), LUA_TTABLE); + t->metatable = NULL; + t->flags = cast_byte(~0); + /* temporary values (kept only if some malloc fails) */ + t->array = NULL; + t->sizearray = 0; + t->lsizenode = 0; + t->node = cast(Node *, dummynode); + setarrayvector(L, t, narray); + setnodevector(L, t, nhash); + return t; +} + + +void luaH_free (lua_State *L, Table *t) { + if (t->node != dummynode) + luaM_freearray(L, t->node, sizenode(t), Node); + luaM_freearray(L, t->array, t->sizearray, TValue); + luaM_free(L, t); +} + + +static Node *getfreepos (Table *t) { + while (t->lastfree-- > t->node) { + if (ttisnil(gkey(t->lastfree))) + return t->lastfree; + } + return NULL; /* could not find a free place */ +} + + + +/* +** inserts a new key into a hash table; first, check whether key's main +** position is free. If not, check whether colliding node is in its main +** position or not: if it is not, move colliding node to an empty place and +** put new key in its main position; otherwise (colliding node is in its main +** position), new key goes to an empty position. +*/ +static TValue *newkey (lua_State *L, Table *t, const TValue *key) { + Node *mp = mainposition(t, key); + if (!ttisnil(gval(mp)) || mp == dummynode) { + Node *othern; + Node *n = getfreepos(t); /* get a free place */ + if (n == NULL) { /* cannot find a free place? */ + rehash(L, t, key); /* grow table */ + return luaH_set(L, t, key); /* re-insert key into grown table */ + } + lua_assert(n != dummynode); + othern = mainposition(t, key2tval(mp)); + if (othern != mp) { /* is colliding node out of its main position? */ + /* yes; move colliding node into free position */ + while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ + gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ + *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + gnext(mp) = NULL; /* now `mp' is free */ + setnilvalue(gval(mp)); + } + else { /* colliding node is in its own main position */ + /* new node will go into free position */ + gnext(n) = gnext(mp); /* chain new position */ + gnext(mp) = n; + mp = n; + } + } + gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; + luaC_barriert(L, t, key); + lua_assert(ttisnil(gval(mp))); + return gval(mp); +} + + +/* +** search function for integers +*/ +const TValue *luaH_getnum (Table *t, int key) { + /* (1 <= key && key <= t->sizearray) */ + if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) + return &t->array[key-1]; + else { + lua_Number nk = cast_num(key); + Node *n = hashnum(t, nk); + do { /* check whether `key' is somewhere in the chain */ + if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) + return gval(n); /* that's it */ + else n = gnext(n); + } while (n); + return luaO_nilobject; + } +} + + +/* +** search function for strings +*/ +const TValue *luaH_getstr (Table *t, TString *key) { + Node *n = hashstr(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) + return gval(n); /* that's it */ + else n = gnext(n); + } while (n); + return luaO_nilobject; +} + + +/* +** main search function +*/ +const TValue *luaH_get (Table *t, const TValue *key) { + switch (ttype(key)) { + case LUA_TNIL: return luaO_nilobject; + case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); + case LUA_TNUMBER: { + int k; + lua_Number n = nvalue(key); + lua_number2int(k, n); + if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ + return luaH_getnum(t, k); /* use specialized version */ + /* else go through */ + } + default: { + Node *n = mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (luaO_rawequalObj(key2tval(n), key)) + return gval(n); /* that's it */ + else n = gnext(n); + } while (n); + return luaO_nilobject; + } + } +} + + +TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { + const TValue *p = luaH_get(t, key); + t->flags = 0; + if (p != luaO_nilobject) + return cast(TValue *, p); + else { + if (ttisnil(key)) luaG_runerror(L, "table index is nil"); + else if (ttisnumber(key) && luai_numisnan(nvalue(key))) + luaG_runerror(L, "table index is NaN"); + return newkey(L, t, key); + } +} + + +TValue *luaH_setnum (lua_State *L, Table *t, int key) { + const TValue *p = luaH_getnum(t, key); + if (p != luaO_nilobject) + return cast(TValue *, p); + else { + TValue k; + setnvalue(&k, cast_num(key)); + return newkey(L, t, &k); + } +} + + +TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { + const TValue *p = luaH_getstr(t, key); + if (p != luaO_nilobject) + return cast(TValue *, p); + else { + TValue k; + setsvalue(L, &k, key); + return newkey(L, t, &k); + } +} + + +static int unbound_search (Table *t, unsigned int j) { + unsigned int i = j; /* i is zero or a present index */ + j++; + /* find `i' and `j' such that i is present and j is not */ + while (!ttisnil(luaH_getnum(t, j))) { + i = j; + j *= 2; + if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ + /* table was built with bad purposes: resort to linear search */ + i = 1; + while (!ttisnil(luaH_getnum(t, i))) i++; + return i - 1; + } + } + /* now do a binary search between them */ + while (j - i > 1) { + unsigned int m = (i+j)/2; + if (ttisnil(luaH_getnum(t, m))) j = m; + else i = m; + } + return i; +} + + +/* +** Try to find a boundary in table `t'. A `boundary' is an integer index +** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). +*/ +int luaH_getn (Table *t) { + unsigned int j = t->sizearray; + if (j > 0 && ttisnil(&t->array[j - 1])) { + /* there is a boundary in the array part: (binary) search for it */ + unsigned int i = 0; + while (j - i > 1) { + unsigned int m = (i+j)/2; + if (ttisnil(&t->array[m - 1])) j = m; + else i = m; + } + return i; + } + /* else must find a boundary in hash part */ + else if (t->node == dummynode) /* hash part is empty? */ + return j; /* that is easy... */ + else return unbound_search(t, j); +} + + + +#if defined(LUA_DEBUG) + +Node *luaH_mainposition (const Table *t, const TValue *key) { + return mainposition(t, key); +} + +int luaH_isdummy (Node *n) { return n == dummynode; } + +#endif diff --git a/lua/src/ltable.h b/lua/src/ltable.h new file mode 100644 index 0000000000..f5b9d5ead0 --- /dev/null +++ b/lua/src/ltable.h @@ -0,0 +1,40 @@ +/* +** $Id: ltable.h,v 2.10.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#ifndef ltable_h +#define ltable_h + +#include "lobject.h" + + +#define gnode(t,i) (&(t)->node[i]) +#define gkey(n) (&(n)->i_key.nk) +#define gval(n) (&(n)->i_val) +#define gnext(n) ((n)->i_key.nk.next) + +#define key2tval(n) (&(n)->i_key.tvk) + + +LUAI_FUNC const TValue *luaH_getnum (Table *t, int key); +LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key); +LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); +LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key); +LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); +LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); +LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash); +LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize); +LUAI_FUNC void luaH_free (lua_State *L, Table *t); +LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); +LUAI_FUNC int luaH_getn (Table *t); + + +#if defined(LUA_DEBUG) +LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); +LUAI_FUNC int luaH_isdummy (Node *n); +#endif + + +#endif diff --git a/lua/src/ltablib.c b/lua/src/ltablib.c new file mode 100644 index 0000000000..b6d9cb4ac7 --- /dev/null +++ b/lua/src/ltablib.c @@ -0,0 +1,287 @@ +/* +** $Id: ltablib.c,v 1.38.1.3 2008/02/14 16:46:58 roberto Exp $ +** Library for Table Manipulation +** See Copyright Notice in lua.h +*/ + + +#include + +#define ltablib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) + + +static int foreachi (lua_State *L) { + int i; + int n = aux_getn(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + for (i=1; i <= n; i++) { + lua_pushvalue(L, 2); /* function */ + lua_pushinteger(L, i); /* 1st argument */ + lua_rawgeti(L, 1, i); /* 2nd argument */ + lua_call(L, 2, 1); + if (!lua_isnil(L, -1)) + return 1; + lua_pop(L, 1); /* remove nil result */ + } + return 0; +} + + +static int foreach (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checktype(L, 2, LUA_TFUNCTION); + lua_pushnil(L); /* first key */ + while (lua_next(L, 1)) { + lua_pushvalue(L, 2); /* function */ + lua_pushvalue(L, -3); /* key */ + lua_pushvalue(L, -3); /* value */ + lua_call(L, 2, 1); + if (!lua_isnil(L, -1)) + return 1; + lua_pop(L, 2); /* remove value and result */ + } + return 0; +} + + +static int maxn (lua_State *L) { + lua_Number max = 0; + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushnil(L); /* first key */ + while (lua_next(L, 1)) { + lua_pop(L, 1); /* remove value */ + if (lua_type(L, -1) == LUA_TNUMBER) { + lua_Number v = lua_tonumber(L, -1); + if (v > max) max = v; + } + } + lua_pushnumber(L, max); + return 1; +} + + +static int getn (lua_State *L) { + lua_pushinteger(L, aux_getn(L, 1)); + return 1; +} + + +static int setn (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); +#ifndef luaL_setn + luaL_setn(L, 1, luaL_checkint(L, 2)); +#else + luaL_error(L, LUA_QL("setn") " is obsolete"); +#endif + lua_pushvalue(L, 1); + return 1; +} + + +static int tinsert (lua_State *L) { + int e = aux_getn(L, 1) + 1; /* first empty element */ + int pos; /* where to insert new element */ + switch (lua_gettop(L)) { + case 2: { /* called with only 2 arguments */ + pos = e; /* insert new element at the end */ + break; + } + case 3: { + int i; + pos = luaL_checkint(L, 2); /* 2nd argument is the position */ + if (pos > e) e = pos; /* `grow' array if necessary */ + for (i = e; i > pos; i--) { /* move up elements */ + lua_rawgeti(L, 1, i-1); + lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ + } + break; + } + default: { + return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); + } + } + luaL_setn(L, 1, e); /* new size */ + lua_rawseti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +static int tremove (lua_State *L) { + int e = aux_getn(L, 1); + int pos = luaL_optint(L, 2, e); + if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ + return 0; /* nothing to remove */ + luaL_setn(L, 1, e - 1); /* t.n = n-1 */ + lua_rawgeti(L, 1, pos); /* result = t[pos] */ + for ( ;pos= P */ + while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i>u) luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* repeat --j until a[j] <= P */ + while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j + +#define ltm_c +#define LUA_CORE + +#include "lua.h" + +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + + +const char *const luaT_typenames[] = { + "nil", "boolean", "userdata", "number", + "string", "table", "function", "userdata", "thread", + "proto", "upval" +}; + + +void luaT_init (lua_State *L) { + static const char *const luaT_eventname[] = { /* ORDER TM */ + "__index", "__newindex", + "__gc", "__mode", "__eq", + "__add", "__sub", "__mul", "__div", "__mod", + "__pow", "__unm", "__len", "__lt", "__le", + "__concat", "__call" + }; + int i; + for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); + luaS_fix(G(L)->tmname[i]); /* never collect these names */ + } +} + + +/* +** function to be used with macro "fasttm": optimized for absence of +** tag methods +*/ +const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { + const TValue *tm = luaH_getstr(events, ename); + lua_assert(event <= TM_EQ); + if (ttisnil(tm)) { /* no tag method? */ + events->flags |= cast_byte(1u<metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(o)->metatable; + break; + default: + mt = G(L)->mt[ttype(o)]; + } + return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); +} + diff --git a/lua/src/ltm.h b/lua/src/ltm.h new file mode 100644 index 0000000000..64343b781b --- /dev/null +++ b/lua/src/ltm.h @@ -0,0 +1,54 @@ +/* +** $Id: ltm.h,v 2.6.1.1 2007/12/27 13:02:25 roberto Exp $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#ifndef ltm_h +#define ltm_h + + +#include "lobject.h" + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER TM" +*/ +typedef enum { + TM_INDEX, + TM_NEWINDEX, + TM_GC, + TM_MODE, + TM_EQ, /* last tag method with `fast' access */ + TM_ADD, + TM_SUB, + TM_MUL, + TM_DIV, + TM_MOD, + TM_POW, + TM_UNM, + TM_LEN, + TM_LT, + TM_LE, + TM_CONCAT, + TM_CALL, + TM_N /* number of elements in the enum */ +} TMS; + + + +#define gfasttm(g,et,e) ((et) == NULL ? NULL : \ + ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) + +#define fasttm(l,et,e) gfasttm(G(l), et, e) + +LUAI_DATA const char *const luaT_typenames[]; + + +LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); +LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, + TMS event); +LUAI_FUNC void luaT_init (lua_State *L); + +#endif diff --git a/lua/src/lua.c b/lua/src/lua.c new file mode 100644 index 0000000000..1b9f6bf9ad --- /dev/null +++ b/lua/src/lua.c @@ -0,0 +1,394 @@ +/* +** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $ +** Lua stand-alone interpreter +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define lua_c + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + +static lua_State *globalL = NULL; + +static const char *progname = LUA_PROGNAME; + + + +static void lstop (lua_State *L, lua_Debug *ar) { + (void)ar; /* unused arg. */ + lua_sethook(L, NULL, 0, 0); + luaL_error(L, "interrupted!"); +} + + +static void laction (int i) { + signal(i, SIG_DFL); /* if another SIGINT happens before lstop, + terminate process (default action) */ + lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); +} + + +static void print_usage (void) { + fprintf(stderr, + "usage: %s [options] [script [args]].\n" + "Available options are:\n" + " -e stat execute string " LUA_QL("stat") "\n" + " -l name require library " LUA_QL("name") "\n" + " -i enter interactive mode after executing " LUA_QL("script") "\n" + " -v show version information\n" + " -- stop handling options\n" + " - execute stdin and stop handling options\n" + , + progname); + fflush(stderr); +} + + +static void l_message (const char *pname, const char *msg) { + if (pname) fprintf(stderr, "%s: ", pname); + fprintf(stderr, "%s\n", msg); + fflush(stderr); +} + + +static int report (lua_State *L, int status) { + if (status && !lua_isnil(L, -1)) { + const char *msg = lua_tostring(L, -1); + if (msg == NULL) msg = "(error object is not a string)"; + l_message(progname, msg); + lua_pop(L, 1); + } + return status; +} + + +static int traceback (lua_State *L) { + if (!lua_isstring(L, 1)) /* 'message' not a string? */ + return 1; /* keep it intact */ + lua_getfield(L, LUA_GLOBALSINDEX, "debug"); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + return 1; + } + lua_getfield(L, -1, "traceback"); + if (!lua_isfunction(L, -1)) { + lua_pop(L, 2); + return 1; + } + lua_pushvalue(L, 1); /* pass error message */ + lua_pushinteger(L, 2); /* skip this function and traceback */ + lua_call(L, 2, 1); /* call debug.traceback */ + return 1; +} + + +static int docall (lua_State *L, int narg, int clear) { + int status; + int base = lua_gettop(L) - narg; /* function index */ + lua_pushcfunction(L, traceback); /* push traceback function */ + lua_insert(L, base); /* put it under chunk and args */ + signal(SIGINT, laction); + status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); + signal(SIGINT, SIG_DFL); + lua_remove(L, base); /* remove traceback function */ + /* force a complete garbage collection in case of errors */ + if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); + return status; +} + + +static void print_version (void) { + l_message(NULL, LUA_RELEASE " " LUA_COPYRIGHT); +} + + +static int getargs (lua_State *L, char **argv, int n) { + int narg; + int i; + int argc = 0; + while (argv[argc]) argc++; /* count total number of arguments */ + narg = argc - (n + 1); /* number of arguments to the script */ + luaL_checkstack(L, narg + 3, "too many arguments to script"); + for (i=n+1; i < argc; i++) + lua_pushstring(L, argv[i]); + lua_createtable(L, narg, n + 1); + for (i=0; i < argc; i++) { + lua_pushstring(L, argv[i]); + lua_rawseti(L, -2, i - n); + } + return narg; +} + + +static int dofile (lua_State *L, const char *name) { + int status = luaL_loadfile(L, name) || docall(L, 0, 1); + return report(L, status); +} + + +static int dostring (lua_State *L, const char *s, const char *name) { + int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); + return report(L, status); +} + + +static int dolibrary (lua_State *L, const char *name) { + lua_getglobal(L, "require"); + lua_pushstring(L, name); + return report(L, docall(L, 1, 1)); +} + + +static const char *get_prompt (lua_State *L, int firstline) { + const char *p; + lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); + p = lua_tostring(L, -1); + if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); + lua_pop(L, 1); /* remove global */ + return p; +} + + +static int incomplete (lua_State *L, int status) { + if (status == LUA_ERRSYNTAX) { + size_t lmsg; + const char *msg = lua_tolstring(L, -1, &lmsg); + const char *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); + if (strstr(msg, LUA_QL("")) == tp) { + lua_pop(L, 1); + return 1; + } + } + return 0; /* else... */ +} + + +static int pushline (lua_State *L, int firstline) { + char buffer[LUA_MAXINPUT]; + char *b = buffer; + size_t l; + const char *prmt = get_prompt(L, firstline); + if (lua_readline(L, b, prmt) == 0) + return 0; /* no input */ + l = strlen(b); + if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ + b[l-1] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* first line starts with `=' ? */ + lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ + else + lua_pushstring(L, b); + lua_freeline(L, b); + return 1; +} + + +static int loadline (lua_State *L) { + int status; + lua_settop(L, 0); + if (!pushline(L, 1)) + return -1; /* no input */ + for (;;) { /* repeat until gets a complete line */ + status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + if (!incomplete(L, status)) break; /* cannot try to add lines? */ + if (!pushline(L, 0)) /* no more input? */ + return -1; + lua_pushliteral(L, "\n"); /* add a new line... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } + lua_saveline(L, 1); + lua_remove(L, 1); /* remove line */ + return status; +} + + +static void dotty (lua_State *L) { + int status; + const char *oldprogname = progname; + progname = NULL; + while ((status = loadline(L)) != -1) { + if (status == 0) status = docall(L, 0, 0); + report(L, status); + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + l_message(progname, lua_pushfstring(L, + "error calling " LUA_QL("print") " (%s)", + lua_tostring(L, -1))); + } + } + lua_settop(L, 0); /* clear stack */ + fputs("\n", stdout); + fflush(stdout); + progname = oldprogname; +} + + +static int handle_script (lua_State *L, char **argv, int n) { + int status; + const char *fname; + int narg = getargs(L, argv, n); /* collect arguments */ + lua_setglobal(L, "arg"); + fname = argv[n]; + if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) + fname = NULL; /* stdin */ + status = luaL_loadfile(L, fname); + lua_insert(L, -(narg+1)); + if (status == 0) + status = docall(L, narg, 0); + else + lua_pop(L, narg); + return report(L, status); +} + + +/* check that argument has no extra characters at the end */ +#define notail(x) {if ((x)[2] != '\0') return -1;} + + +static int collectargs (char **argv, int *pi, int *pv, int *pe) { + int i; + for (i = 1; argv[i] != NULL; i++) { + if (argv[i][0] != '-') /* not an option? */ + return i; + switch (argv[i][1]) { /* option */ + case '-': + notail(argv[i]); + return (argv[i+1] != NULL ? i+1 : 0); + case '\0': + return i; + case 'i': + notail(argv[i]); + *pi = 1; /* go through */ + case 'v': + notail(argv[i]); + *pv = 1; + break; + case 'e': + *pe = 1; /* go through */ + case 'l': + if (argv[i][2] == '\0') { + i++; + if (argv[i] == NULL) return -1; + } + break; + default: return -1; /* invalid option */ + } + } + return 0; +} + + +static int runargs (lua_State *L, char **argv, int n) { + int i; + for (i = 1; i < n; i++) { + if (argv[i] == NULL) continue; + lua_assert(argv[i][0] == '-'); + switch (argv[i][1]) { /* option */ + case 'e': { + const char *chunk = argv[i] + 2; + if (*chunk == '\0') chunk = argv[++i]; + lua_assert(chunk != NULL); + if (dostring(L, chunk, "=(command line)") != 0) + return 1; + break; + } + case 'l': { + const char *filename = argv[i] + 2; + if (*filename == '\0') filename = argv[++i]; + lua_assert(filename != NULL); + if (dolibrary(L, filename)) + return 1; /* stop if file fails */ + break; + } + default: break; + } + } + return 0; +} + + +static int handle_luainit (lua_State *L) { + const char *init = getenv(LUA_INIT); + if (init == NULL) return 0; /* status OK */ + else if (init[0] == '@') + return dofile(L, init+1); + else + return dostring(L, init, "=" LUA_INIT); +} + + +struct Smain { + int argc; + char **argv; + int status; +}; + + +static int pmain (lua_State *L) { + struct Smain *s = (struct Smain *)lua_touserdata(L, 1); + char **argv = s->argv; + int script; + int has_i = 0, has_v = 0, has_e = 0; + globalL = L; + if (argv[0] && argv[0][0]) progname = argv[0]; + lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ + luaL_openlibs(L); /* open libraries */ + lua_gc(L, LUA_GCRESTART, 0); + s->status = handle_luainit(L); + if (s->status != 0) return 0; + script = collectargs(argv, &has_i, &has_v, &has_e); + if (script < 0) { /* invalid args? */ + print_usage(); + s->status = 1; + return 0; + } + if (has_v) print_version(); + s->status = runargs(L, argv, (script > 0) ? script : s->argc); + if (s->status != 0) return 0; + if (script) + s->status = handle_script(L, argv, script); + if (s->status != 0) return 0; + if (has_i) + dotty(L); + else if (script == 0 && !has_e && !has_v) { + if (lua_stdin_is_tty()) { + print_version(); + dotty(L); + } + else dofile(L, NULL); /* executes stdin as a file */ + } + return 0; +} + +/* + +int main (int argc, char **argv) { + int status; + struct Smain s; + lua_State *L = lua_open(); + if (L == NULL) { + l_message(argv[0], "cannot create state: not enough memory"); + return EXIT_FAILURE; + } + s.argc = argc; + s.argv = argv; + status = lua_cpcall(L, &pmain, &s); + report(L, status); + lua_close(L); + return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; +} +*/ + diff --git a/lua/src/lua.h b/lua/src/lua.h new file mode 100644 index 0000000000..e4bdfd3b94 --- /dev/null +++ b/lua/src/lua.h @@ -0,0 +1,388 @@ +/* +** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $ +** Lua - An Extensible Extension Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*/ + + +#ifndef lua_h +#define lua_h + +#include +#include + + +#include "luaconf.h" + + +#define LUA_VERSION "Lua 5.1" +#define LUA_RELEASE "Lua 5.1.4" +#define LUA_VERSION_NUM 501 +#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" + + +/* mark for precompiled code (`Lua') */ +#define LUA_SIGNATURE "\033Lua" + +/* option for multiple returns in `lua_pcall' and `lua_call' */ +#define LUA_MULTRET (-1) + + +/* +** pseudo-indices +*/ +#define LUA_REGISTRYINDEX (-10000) +#define LUA_ENVIRONINDEX (-10001) +#define LUA_GLOBALSINDEX (-10002) +#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) + + +/* thread status; 0 is OK */ +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRERR 5 + + +typedef struct lua_State lua_State; + +typedef int (*lua_CFunction) (lua_State *L); + + +/* +** functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); + + +/* +** prototype for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + + +/* +** basic types +*/ +#define LUA_TNONE (-1) + +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 + + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + +/* type of numbers in Lua */ +typedef LUA_NUMBER lua_Number; + + +/* type for integer functions */ +typedef LUA_INTEGER lua_Integer; + + + +/* +** state manipulation +*/ +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API void (lua_close) (lua_State *L); +LUA_API lua_State *(lua_newthread) (lua_State *L); + +LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); + + +/* +** basic stack manipulation +*/ +LUA_API int (lua_gettop) (lua_State *L); +LUA_API void (lua_settop) (lua_State *L, int idx); +LUA_API void (lua_pushvalue) (lua_State *L, int idx); +LUA_API void (lua_remove) (lua_State *L, int idx); +LUA_API void (lua_insert) (lua_State *L, int idx); +LUA_API void (lua_replace) (lua_State *L, int idx); +LUA_API int (lua_checkstack) (lua_State *L, int sz); + +LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); + + +/* +** access functions (stack -> C) +*/ + +LUA_API int (lua_isnumber) (lua_State *L, int idx); +LUA_API int (lua_isstring) (lua_State *L, int idx); +LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isuserdata) (lua_State *L, int idx); +LUA_API int (lua_type) (lua_State *L, int idx); +LUA_API const char *(lua_typename) (lua_State *L, int tp); + +LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); + +LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); +LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); +LUA_API int (lua_toboolean) (lua_State *L, int idx); +LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); +LUA_API size_t (lua_objlen) (lua_State *L, int idx); +LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); +LUA_API void *(lua_touserdata) (lua_State *L, int idx); +LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); +LUA_API const void *(lua_topointer) (lua_State *L, int idx); + + +/* +** push functions (C -> stack) +*/ +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l); +LUA_API void (lua_pushstring) (lua_State *L, const char *s); +LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); +LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); +LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); +LUA_API void (lua_pushboolean) (lua_State *L, int b); +LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); +LUA_API int (lua_pushthread) (lua_State *L); + + +/* +** get functions (Lua -> stack) +*/ +LUA_API void (lua_gettable) (lua_State *L, int idx); +LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawget) (lua_State *L, int idx); +LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); +LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); +LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); +LUA_API int (lua_getmetatable) (lua_State *L, int objindex); +LUA_API void (lua_getfenv) (lua_State *L, int idx); + + +/* +** set functions (stack -> Lua) +*/ +LUA_API void (lua_settable) (lua_State *L, int idx); +LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawset) (lua_State *L, int idx); +LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); +LUA_API int (lua_setmetatable) (lua_State *L, int objindex); +LUA_API int (lua_setfenv) (lua_State *L, int idx); + + +/* +** `load' and `call' functions (load and run Lua code) +*/ +LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); +LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); +LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); +LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname); + +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); + + +/* +** coroutine functions +*/ +LUA_API int (lua_yield) (lua_State *L, int nresults); +LUA_API int (lua_resume) (lua_State *L, int narg); +LUA_API int (lua_status) (lua_State *L); + +/* +** garbage-collection function and options +*/ + +#define LUA_GCSTOP 0 +#define LUA_GCRESTART 1 +#define LUA_GCCOLLECT 2 +#define LUA_GCCOUNT 3 +#define LUA_GCCOUNTB 4 +#define LUA_GCSTEP 5 +#define LUA_GCSETPAUSE 6 +#define LUA_GCSETSTEPMUL 7 + +LUA_API int (lua_gc) (lua_State *L, int what, int data); + + +/* +** miscellaneous functions +*/ + +LUA_API int (lua_error) (lua_State *L); + +LUA_API int (lua_next) (lua_State *L, int idx); + +LUA_API void (lua_concat) (lua_State *L, int n); + +LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#define lua_pop(L,n) lua_settop(L, -(n)-1) + +#define lua_newtable(L) lua_createtable(L, 0, 0) + +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) + +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) + +#define lua_strlen(L,i) lua_objlen(L, (i)) + +#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) +#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) +#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) +#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) +#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) +#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) +#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) +#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) + +#define lua_pushliteral(L, s) \ + lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) + +#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) +#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) + +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) + + + +/* +** compatibility macros and functions +*/ + +#define lua_open() luaL_newstate() + +#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) + +#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) + +#define lua_Chunkreader lua_Reader +#define lua_Chunkwriter lua_Writer + + +/* hack */ +LUA_API void lua_setlevel (lua_State *from, lua_State *to); + + +/* +** {====================================================================== +** Debug API +** ======================================================================= +*/ + + +/* +** Event codes +*/ +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILRET 4 + + +/* +** Event masks +*/ +#define LUA_MASKCALL (1 << LUA_HOOKCALL) +#define LUA_MASKRET (1 << LUA_HOOKRET) +#define LUA_MASKLINE (1 << LUA_HOOKLINE) +#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) + +typedef struct lua_Debug lua_Debug; /* activation record */ + + +/* Functions to be called by the debuger in specific events */ +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n); +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n); + +LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook lua_gethook (lua_State *L); +LUA_API int lua_gethookmask (lua_State *L); +LUA_API int lua_gethookcount (lua_State *L); + + +struct lua_Debug { + int event; + const char *name; /* (n) */ + const char *namewhat; /* (n) `global', `local', `field', `method' */ + const char *what; /* (S) `Lua', `C', `main', `tail' */ + const char *source; /* (S) */ + int currentline; /* (l) */ + int nups; /* (u) number of upvalues */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + int i_ci; /* active function */ +}; + +/* }====================================================================== */ + + +/****************************************************************************** +* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ + + +#endif diff --git a/lua/src/luac.c b/lua/src/luac.c new file mode 100644 index 0000000000..0097833dff --- /dev/null +++ b/lua/src/luac.c @@ -0,0 +1,203 @@ +/* +** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $ +** Lua compiler (saves bytecodes to files; also list bytecodes) +** See Copyright Notice in lua.h +*/ + +#include +#include +#include +#include + +#define luac_c +#define LUA_CORE + +#include "lua.h" +#include "lauxlib.h" + +#include "ldo.h" +#include "lfunc.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstring.h" +#include "lundump.h" + +#define PROGNAME "luac" /* default program name */ +#define OUTPUT PROGNAME ".out" /* default output file */ + +static int listing=0; /* list bytecodes? */ +static int dumping=1; /* dump bytecodes? */ +static int stripping=0; /* strip debug information? */ +static char Output[]={ OUTPUT }; /* default output file name */ +static const char* output=Output; /* actual output file name */ +static const char* progname=PROGNAME; /* actual program name */ + +static void fatal(const char* message) +{ + fprintf(stderr,"%s: %s\n",progname,message); + exit(EXIT_FAILURE); +} + +static void cannot(const char* what) +{ + fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); + exit(EXIT_FAILURE); +} + +static void usage(const char* message) +{ + if (*message=='-') + fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); + else + fprintf(stderr,"%s: %s\n",progname,message); + fprintf(stderr, + "usage: %s [options] [filenames].\n" + "Available options are:\n" + " - process stdin\n" + " -l list\n" + " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" + " -p parse only\n" + " -s strip debug information\n" + " -v show version information\n" + " -- stop handling options\n", + progname,Output); + exit(EXIT_FAILURE); +} + +#define IS(s) (strcmp(argv[i],s)==0) + +static int doargs(int argc, char* argv[]) +{ + int i; + int version=0; + if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0]; + for (i=1; itop+(i))->l.p) + +static const Proto* combine(lua_State* L, int n) +{ + if (n==1) + return toproto(L,-1); + else + { + int i,pc; + Proto* f=luaF_newproto(L); + setptvalue2s(L,L->top,f); incr_top(L); + f->source=luaS_newliteral(L,"=(" PROGNAME ")"); + f->maxstacksize=1; + pc=2*n+1; + f->code=luaM_newvector(L,pc,Instruction); + f->sizecode=pc; + f->p=luaM_newvector(L,n,Proto*); + f->sizep=n; + pc=0; + for (i=0; ip[i]=toproto(L,i-n-1); + f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i); + f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1); + } + f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0); + return f; + } +} + +static int writer(lua_State* L, const void* p, size_t size, void* u) +{ + UNUSED(L); + return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); +} + +struct Smain { + int argc; + char** argv; +}; + +static int pmain(lua_State* L) +{ + struct Smain* s = (struct Smain*)lua_touserdata(L, 1); + int argc=s->argc; + char** argv=s->argv; + const Proto* f; + int i; + if (!lua_checkstack(L,argc)) fatal("too many input files"); + for (i=0; i1); + if (dumping) + { + FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); + if (D==NULL) cannot("open"); + lua_lock(L); + luaU_dump(L,f,writer,D,stripping); + lua_unlock(L); + if (ferror(D)) cannot("write"); + if (fclose(D)) cannot("close"); + } + return 0; +} +/* + +int main(int argc, char* argv[]) +{ + lua_State* L; + struct Smain s; + int i=doargs(argc,argv); + argc-=i; argv+=i; + if (argc<=0) usage("no input files given"); + L=lua_open(); + if (L==NULL) fatal("not enough memory for state"); + s.argc=argc; + s.argv=argv; + if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1)); + lua_close(L); + return EXIT_SUCCESS; +} + +*/ \ No newline at end of file diff --git a/lua/src/luaconf.h b/lua/src/luaconf.h new file mode 100644 index 0000000000..e2cb26163a --- /dev/null +++ b/lua/src/luaconf.h @@ -0,0 +1,763 @@ +/* +** $Id: luaconf.h,v 1.82.1.7 2008/02/11 16:25:08 roberto Exp $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + + +#ifndef lconfig_h +#define lconfig_h + +#include +#include + + +/* +** ================================================================== +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + + +/* +@@ LUA_ANSI controls the use of non-ansi features. +** CHANGE it (define it) if you want Lua to avoid the use of any +** non-ansi feature or library. +*/ +#if defined(__STRICT_ANSI__) +#define LUA_ANSI +#endif + + +#if !defined(LUA_ANSI) && defined(_WIN32) +#define LUA_WIN +#endif + +#if defined(LUA_USE_LINUX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ +#define LUA_USE_READLINE /* needs some extra libraries */ +#endif + +#if defined(LUA_USE_MACOSX) +#define LUA_USE_POSIX +#define LUA_DL_DYLD /* does not need extra library */ +#endif + + + +/* +@@ LUA_USE_POSIX includes all functionallity listed as X/Open System +@* Interfaces Extension (XSI). +** CHANGE it (define it) if your system is XSI compatible. +*/ +#if defined(LUA_USE_POSIX) +#define LUA_USE_MKSTEMP +#define LUA_USE_ISATTY +#define LUA_USE_POPEN +#define LUA_USE_ULONGJMP +#endif + + +/* +@@ LUA_PATH and LUA_CPATH are the names of the environment variables that +@* Lua check to set its paths. +@@ LUA_INIT is the name of the environment variable that Lua +@* checks for initialization code. +** CHANGE them if you want different names. +*/ +#define LUA_PATH "LUA_PATH" +#define LUA_CPATH "LUA_CPATH" +#define LUA_INIT "LUA_INIT" + + +/* +@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for +@* Lua libraries. +@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for +@* C libraries. +** CHANGE them if your machine has a non-conventional directory +** hierarchy or if you want to install your libraries in +** non-conventional directories. +*/ +#if defined(_WIN32) +/* +** In Windows, any exclamation mark ('!') in the path is replaced by the +** path of the directory of the executable file of the current process. +*/ +#define LUA_LDIR "!\\lua\\" +#define LUA_CDIR "!\\" +#define LUA_PATH_DEFAULT \ + ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua" +#define LUA_CPATH_DEFAULT \ + ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll" + +#else +#define LUA_ROOT "/usr/local/" +#define LUA_LDIR LUA_ROOT "share/lua/5.1/" +#define LUA_CDIR LUA_ROOT "lib/lua/5.1/" +#define LUA_PATH_DEFAULT \ + "./?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua" +#define LUA_CPATH_DEFAULT \ + "./?.so;" LUA_CDIR"?.so;" LUA_CDIR"loadall.so" +#endif + + +/* +@@ LUA_DIRSEP is the directory separator (for submodules). +** CHANGE it if your machine does not use "/" as the directory separator +** and is not Windows. (On Windows Lua automatically uses "\".) +*/ +#if defined(_WIN32) +#define LUA_DIRSEP "\\" +#else +#define LUA_DIRSEP "/" +#endif + + +/* +@@ LUA_PATHSEP is the character that separates templates in a path. +@@ LUA_PATH_MARK is the string that marks the substitution points in a +@* template. +@@ LUA_EXECDIR in a Windows path is replaced by the executable's +@* directory. +@@ LUA_IGMARK is a mark to ignore all before it when bulding the +@* luaopen_ function name. +** CHANGE them if for some reason your system cannot use those +** characters. (E.g., if one of those characters is a common character +** in file/directory names.) Probably you do not need to change them. +*/ +#define LUA_PATHSEP ";" +#define LUA_PATH_MARK "?" +#define LUA_EXECDIR "!" +#define LUA_IGMARK "-" + + +/* +@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. +** CHANGE that if ptrdiff_t is not adequate on your machine. (On most +** machines, ptrdiff_t gives a good choice between int or long.) +*/ +#define LUA_INTEGER ptrdiff_t + + +/* +@@ LUA_API is a mark for all core API functions. +@@ LUALIB_API is a mark for all standard library functions. +** CHANGE them if you need to define those functions in some special way. +** For instance, if you want to create one Windows DLL with the core and +** the libraries, you may want to use the following definition (define +** LUA_BUILD_AS_DLL to get it). +*/ +#if defined(LUA_BUILD_AS_DLL) + +#if defined(LUA_CORE) || defined(LUA_LIB) +#define LUA_API __declspec(dllexport) +#else +#define LUA_API __declspec(dllimport) +#endif + +#else + +#define LUA_API extern + +#endif + +/* more often than not the libs go together with the core */ +#define LUALIB_API LUA_API + + +/* +@@ LUAI_FUNC is a mark for all extern functions that are not to be +@* exported to outside modules. +@@ LUAI_DATA is a mark for all extern (const) variables that are not to +@* be exported to outside modules. +** CHANGE them if you need to mark them in some special way. Elf/gcc +** (versions 3.2 and later) mark them as "hidden" to optimize access +** when Lua is compiled as a shared library. +*/ +#if defined(luaall_c) +#define LUAI_FUNC static +#define LUAI_DATA /* empty */ + +#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + defined(__ELF__) +#define LUAI_FUNC __attribute__((visibility("hidden"))) extern +#define LUAI_DATA LUAI_FUNC + +#else +#define LUAI_FUNC extern +#define LUAI_DATA extern +#endif + + + +/* +@@ LUA_QL describes how error messages quote program elements. +** CHANGE it if you want a different appearance. +*/ +#define LUA_QL(x) "'" x "'" +#define LUA_QS LUA_QL("%s") + + +/* +@@ LUA_IDSIZE gives the maximum size for the description of the source +@* of a function in debug information. +** CHANGE it if you want a different size. +*/ +#define LUA_IDSIZE 60 + + +/* +** {================================================================== +** Stand-alone configuration +** =================================================================== +*/ + +#if defined(lua_c) || defined(luaall_c) + +/* +@@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that +@* is, whether we're running lua interactively). +** CHANGE it if you have a better definition for non-POSIX/non-Windows +** systems. +*/ +#if defined(LUA_USE_ISATTY) +#include +#define lua_stdin_is_tty() isatty(0) +#elif defined(LUA_WIN) +#include +#include +#define lua_stdin_is_tty() _isatty(_fileno(stdin)) +#else +#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ +#endif + + +/* +@@ LUA_PROMPT is the default prompt used by stand-alone Lua. +@@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua. +** CHANGE them if you want different prompts. (You can also change the +** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.) +*/ +#define LUA_PROMPT "> " +#define LUA_PROMPT2 ">> " + + +/* +@@ LUA_PROGNAME is the default name for the stand-alone Lua program. +** CHANGE it if your stand-alone interpreter has a different name and +** your system is not able to detect that name automatically. +*/ +#define LUA_PROGNAME "lua" + + +/* +@@ LUA_MAXINPUT is the maximum length for an input line in the +@* stand-alone interpreter. +** CHANGE it if you need longer lines. +*/ +#define LUA_MAXINPUT 512 + + +/* +@@ lua_readline defines how to show a prompt and then read a line from +@* the standard input. +@@ lua_saveline defines how to "save" a read line in a "history". +@@ lua_freeline defines how to free a line read by lua_readline. +** CHANGE them if you want to improve this functionality (e.g., by using +** GNU readline and history facilities). +*/ +#if defined(LUA_USE_READLINE) +#include +#include +#include +#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_saveline(L,idx) \ + if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ + add_history(lua_tostring(L, idx)); /* add it to history */ +#define lua_freeline(L,b) ((void)L, free(b)) +#else +#define lua_readline(L,b,p) \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ +#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_freeline(L,b) { (void)L; (void)b; } +#endif + +#endif + +/* }================================================================== */ + + +/* +@@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles +@* as a percentage. +** CHANGE it if you want the GC to run faster or slower (higher values +** mean larger pauses which mean slower collection.) You can also change +** this value dynamically. +*/ +#define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */ + + +/* +@@ LUAI_GCMUL defines the default speed of garbage collection relative to +@* memory allocation as a percentage. +** CHANGE it if you want to change the granularity of the garbage +** collection. (Higher values mean coarser collections. 0 represents +** infinity, where each step performs a full collection.) You can also +** change this value dynamically. +*/ +#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ + + + +/* +@@ LUA_COMPAT_GETN controls compatibility with old getn behavior. +** CHANGE it (define it) if you want exact compatibility with the +** behavior of setn/getn in Lua 5.0. +*/ +#undef LUA_COMPAT_GETN + +/* +@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. +** CHANGE it to undefined as soon as you do not need a global 'loadlib' +** function (the function is still available as 'package.loadlib'). +*/ +#undef LUA_COMPAT_LOADLIB + +/* +@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. +** CHANGE it to undefined as soon as your programs use only '...' to +** access vararg parameters (instead of the old 'arg' table). +*/ +#define LUA_COMPAT_VARARG + +/* +@@ LUA_COMPAT_MOD controls compatibility with old math.mod function. +** CHANGE it to undefined as soon as your programs use 'math.fmod' or +** the new '%' operator instead of 'math.mod'. +*/ +#define LUA_COMPAT_MOD + +/* +@@ LUA_COMPAT_LSTR controls compatibility with old long string nesting +@* facility. +** CHANGE it to 2 if you want the old behaviour, or undefine it to turn +** off the advisory error when nesting [[...]]. +*/ +#define LUA_COMPAT_LSTR 1 + +/* +@@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. +** CHANGE it to undefined as soon as you rename 'string.gfind' to +** 'string.gmatch'. +*/ +#define LUA_COMPAT_GFIND + +/* +@@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' +@* behavior. +** CHANGE it to undefined as soon as you replace to 'luaL_register' +** your uses of 'luaL_openlib' +*/ +#define LUA_COMPAT_OPENLIB + + + +/* +@@ luai_apicheck is the assert macro used by the Lua-C API. +** CHANGE luai_apicheck if you want Lua to perform some checks in the +** parameters it gets from API calls. This may slow down the interpreter +** a bit, but may be quite useful when debugging C code that interfaces +** with Lua. A useful redefinition is to use assert.h. +*/ +#if defined(LUA_USE_APICHECK) +#include +#define luai_apicheck(L,o) { (void)L; assert(o); } +#else +#define luai_apicheck(L,o) { (void)L; } +#endif + + +/* +@@ LUAI_BITSINT defines the number of bits in an int. +** CHANGE here if Lua cannot automatically detect the number of bits of +** your machine. Probably you do not need to change this. +*/ +/* avoid overflows in comparison */ +#if INT_MAX-20 < 32760 +#define LUAI_BITSINT 16 +#elif INT_MAX > 2147483640L +/* int has at least 32 bits */ +#define LUAI_BITSINT 32 +#else +#error "you must define LUA_BITSINT with number of bits in an integer" +#endif + + +/* +@@ LUAI_UINT32 is an unsigned integer with at least 32 bits. +@@ LUAI_INT32 is an signed integer with at least 32 bits. +@@ LUAI_UMEM is an unsigned integer big enough to count the total +@* memory used by Lua. +@@ LUAI_MEM is a signed integer big enough to count the total memory +@* used by Lua. +** CHANGE here if for some weird reason the default definitions are not +** good enough for your machine. (The definitions in the 'else' +** part always works, but may waste space on machines with 64-bit +** longs.) Probably you do not need to change this. +*/ +#if LUAI_BITSINT >= 32 +#define LUAI_UINT32 unsigned int +#define LUAI_INT32 int +#define LUAI_MAXINT32 INT_MAX +#define LUAI_UMEM size_t +#define LUAI_MEM ptrdiff_t +#else +/* 16-bit ints */ +#define LUAI_UINT32 unsigned long +#define LUAI_INT32 long +#define LUAI_MAXINT32 LONG_MAX +#define LUAI_UMEM unsigned long +#define LUAI_MEM long +#endif + + +/* +@@ LUAI_MAXCALLS limits the number of nested calls. +** CHANGE it if you need really deep recursive calls. This limit is +** arbitrary; its only purpose is to stop infinite recursion before +** exhausting memory. +*/ +#define LUAI_MAXCALLS 20000 + + +/* +@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function +@* can use. +** CHANGE it if you need lots of (Lua) stack space for your C +** functions. This limit is arbitrary; its only purpose is to stop C +** functions to consume unlimited stack space. (must be smaller than +** -LUA_REGISTRYINDEX) +*/ +#define LUAI_MAXCSTACK 8000 + + + +/* +** {================================================================== +** CHANGE (to smaller values) the following definitions if your system +** has a small C stack. (Or you may want to change them to larger +** values if your system has a large C stack and these limits are +** too rigid for you.) Some of these constants control the size of +** stack-allocated arrays used by the compiler or the interpreter, while +** others limit the maximum number of recursive calls that the compiler +** or the interpreter can perform. Values too large may cause a C stack +** overflow for some forms of deep constructs. +** =================================================================== +*/ + + +/* +@@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and +@* syntactical nested non-terminals in a program. +*/ +#define LUAI_MAXCCALLS 200 + + +/* +@@ LUAI_MAXVARS is the maximum number of local variables per function +@* (must be smaller than 250). +*/ +#define LUAI_MAXVARS 200 + + +/* +@@ LUAI_MAXUPVALUES is the maximum number of upvalues per function +@* (must be smaller than 250). +*/ +#define LUAI_MAXUPVALUES 60 + + +/* +@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. +*/ +#define LUAL_BUFFERSIZE BUFSIZ + +/* }================================================================== */ + + + + +/* +** {================================================================== +@@ LUA_NUMBER is the type of numbers in Lua. +** CHANGE the following definitions only if you want to build Lua +** with a number type different from double. You may also need to +** change lua_number2int & lua_number2integer. +** =================================================================== +*/ + +#define LUA_NUMBER_DOUBLE +#define LUA_NUMBER double + +/* +@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' +@* over a number. +*/ +#define LUAI_UACNUMBER double + + +/* +@@ LUA_NUMBER_SCAN is the format for reading numbers. +@@ LUA_NUMBER_FMT is the format for writing numbers. +@@ lua_number2str converts a number to a string. +@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. +@@ lua_str2number converts a string to a number. +*/ +#define LUA_NUMBER_SCAN "%lf" +#define LUA_NUMBER_FMT "%.14g" +#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) +#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ +#define lua_str2number(s,p) strtod((s), (p)) + + +/* +@@ The luai_num* macros define the primitive operations over numbers. +*/ +#if defined(LUA_CORE) +#include +#define luai_numadd(a,b) ((a)+(b)) +#define luai_numsub(a,b) ((a)-(b)) +#define luai_nummul(a,b) ((a)*(b)) +#define luai_numdiv(a,b) ((a)/(b)) +#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) +#define luai_numpow(a,b) (pow(a,b)) +#define luai_numunm(a) (-(a)) +#define luai_numeq(a,b) ((a)==(b)) +#define luai_numlt(a,b) ((a)<(b)) +#define luai_numle(a,b) ((a)<=(b)) +#define luai_numisnan(a) (!luai_numeq((a), (a))) +#endif + + +/* +@@ lua_number2int is a macro to convert lua_Number to int. +@@ lua_number2integer is a macro to convert lua_Number to lua_Integer. +** CHANGE them if you know a faster way to convert a lua_Number to +** int (with any rounding method and without throwing errors) in your +** system. In Pentium machines, a naive typecast from double to int +** in C is extremely slow, so any alternative is worth trying. +*/ + +/* On a Pentium, resort to a trick */ +#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ + (defined(__i386) || defined (_M_IX86) || defined(__i386__)) + +/* On a Microsoft compiler, use assembler */ +#if defined(_MSC_VER) + +#define lua_number2int(i,d) __asm fld d __asm fistp i +#define lua_number2integer(i,n) lua_number2int(i, n) + +/* the next trick should work on any Pentium, but sometimes clashes + with a DirectX idiosyncrasy */ +#else + +union luai_Cast { double l_d; long l_l; }; +#define lua_number2int(i,d) \ + { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } +#define lua_number2integer(i,n) lua_number2int(i, n) + +#endif + + +/* this option always works, but may be slow */ +#else +#define lua_number2int(i,d) ((i)=(int)(d)) +#define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) + +#endif + +/* }================================================================== */ + + +/* +@@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment. +** CHANGE it if your system requires alignments larger than double. (For +** instance, if your system supports long doubles and they must be +** aligned in 16-byte boundaries, then you should add long double in the +** union.) Probably you do not need to change this. +*/ +#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } + + +/* +@@ LUAI_THROW/LUAI_TRY define how Lua does exception handling. +** CHANGE them if you prefer to use longjmp/setjmp even with C++ +** or if want/don't to use _longjmp/_setjmp instead of regular +** longjmp/setjmp. By default, Lua handles errors with exceptions when +** compiling as C++ code, with _longjmp/_setjmp when asked to use them, +** and with longjmp/setjmp otherwise. +*/ +#if defined(__cplusplus) +/* C++ exceptions */ +#define LUAI_THROW(L,c) throw(c) +#define LUAI_TRY(L,c,a) try { a } catch(...) \ + { if ((c)->status == 0) (c)->status = -1; } +#define luai_jmpbuf int /* dummy variable */ + +#elif defined(LUA_USE_ULONGJMP) +/* in Unix, try _longjmp/_setjmp (more efficient) */ +#define LUAI_THROW(L,c) _longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#else +/* default handling with long jumps */ +#define LUAI_THROW(L,c) longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#endif + + +/* +@@ LUA_MAXCAPTURES is the maximum number of captures that a pattern +@* can do during pattern-matching. +** CHANGE it if you need more captures. This limit is arbitrary. +*/ +#define LUA_MAXCAPTURES 32 + + +/* +@@ lua_tmpnam is the function that the OS library uses to create a +@* temporary name. +@@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam. +** CHANGE them if you have an alternative to tmpnam (which is considered +** insecure) or if you want the original tmpnam anyway. By default, Lua +** uses tmpnam except when POSIX is available, where it uses mkstemp. +*/ +#if defined(loslib_c) || defined(luaall_c) + +#if defined(LUA_USE_MKSTEMP) +#include +#define LUA_TMPNAMBUFSIZE 32 +#define lua_tmpnam(b,e) { \ + strcpy(b, "/tmp/lua_XXXXXX"); \ + e = mkstemp(b); \ + if (e != -1) close(e); \ + e = (e == -1); } + +#else +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } +#endif + +#endif + + +/* +@@ lua_popen spawns a new process connected to the current one through +@* the file streams. +** CHANGE it if you have a way to implement it in your system. +*/ +#if defined(LUA_USE_POPEN) + +#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) +#define lua_pclose(L,file) ((void)L, (pclose(file) != -1)) + +#elif defined(LUA_WIN) + +#define lua_popen(L,c,m) ((void)L, _popen(c,m)) +#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) + +#else + +#define lua_popen(L,c,m) ((void)((void)c, m), \ + luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) +#define lua_pclose(L,file) ((void)((void)L, file), 0) + +#endif + +/* +@@ LUA_DL_* define which dynamic-library system Lua should use. +** CHANGE here if Lua has problems choosing the appropriate +** dynamic-library system for your platform (either Windows' DLL, Mac's +** dyld, or Unix's dlopen). If your system is some kind of Unix, there +** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for +** it. To use dlopen you also need to adapt the src/Makefile (probably +** adding -ldl to the linker options), so Lua does not select it +** automatically. (When you change the makefile to add -ldl, you must +** also add -DLUA_USE_DLOPEN.) +** If you do not want any kind of dynamic library, undefine all these +** options. +** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD. +*/ +#if defined(LUA_USE_DLOPEN) +#define LUA_DL_DLOPEN +#endif + +#if defined(LUA_WIN) +#define LUA_DL_DLL +#endif + + +/* +@@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State +@* (the data goes just *before* the lua_State pointer). +** CHANGE (define) this if you really need that. This value must be +** a multiple of the maximum alignment required for your machine. +*/ +#define LUAI_EXTRASPACE 0 + + +/* +@@ luai_userstate* allow user-specific actions on threads. +** CHANGE them if you defined LUAI_EXTRASPACE and need to do something +** extra when a thread is created/deleted/resumed/yielded. +*/ +#define luai_userstateopen(L) ((void)L) +#define luai_userstateclose(L) ((void)L) +#define luai_userstatethread(L,L1) ((void)L) +#define luai_userstatefree(L) ((void)L) +#define luai_userstateresume(L,n) ((void)L) +#define luai_userstateyield(L,n) ((void)L) + + +/* +@@ LUA_INTFRMLEN is the length modifier for integer conversions +@* in 'string.format'. +@@ LUA_INTFRM_T is the integer type correspoding to the previous length +@* modifier. +** CHANGE them if your system supports long long or does not support long. +*/ + +#if defined(LUA_USELONGLONG) + +#define LUA_INTFRMLEN "ll" +#define LUA_INTFRM_T long long + +#else + +#define LUA_INTFRMLEN "l" +#define LUA_INTFRM_T long + +#endif + + + +/* =================================================================== */ + +/* +** Local configuration. You can use this space to add your redefinitions +** without modifying the main part of the file. +*/ + + + +#endif + diff --git a/lua/src/lualib.h b/lua/src/lualib.h new file mode 100644 index 0000000000..469417f670 --- /dev/null +++ b/lua/src/lualib.h @@ -0,0 +1,53 @@ +/* +** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lua standard libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lualib_h +#define lualib_h + +#include "lua.h" + + +/* Key to file-handle type */ +#define LUA_FILEHANDLE "FILE*" + + +#define LUA_COLIBNAME "coroutine" +LUALIB_API int (luaopen_base) (lua_State *L); + +#define LUA_TABLIBNAME "table" +LUALIB_API int (luaopen_table) (lua_State *L); + +#define LUA_IOLIBNAME "io" +LUALIB_API int (luaopen_io) (lua_State *L); + +#define LUA_OSLIBNAME "os" +LUALIB_API int (luaopen_os) (lua_State *L); + +#define LUA_STRLIBNAME "string" +LUALIB_API int (luaopen_string) (lua_State *L); + +#define LUA_MATHLIBNAME "math" +LUALIB_API int (luaopen_math) (lua_State *L); + +#define LUA_DBLIBNAME "debug" +LUALIB_API int (luaopen_debug) (lua_State *L); + +#define LUA_LOADLIBNAME "package" +LUALIB_API int (luaopen_package) (lua_State *L); + + +/* open all previous libraries */ +LUALIB_API void (luaL_openlibs) (lua_State *L); + + + +#ifndef lua_assert +#define lua_assert(x) ((void)0) +#endif + + +#endif diff --git a/lua/src/lundump.c b/lua/src/lundump.c new file mode 100644 index 0000000000..8010a45795 --- /dev/null +++ b/lua/src/lundump.c @@ -0,0 +1,227 @@ +/* +** $Id: lundump.c,v 2.7.1.4 2008/04/04 19:51:41 roberto Exp $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#include + +#define lundump_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstring.h" +#include "lundump.h" +#include "lzio.h" + +typedef struct { + lua_State* L; + ZIO* Z; + Mbuffer* b; + const char* name; +} LoadState; + +#ifdef LUAC_TRUST_BINARIES +#define IF(c,s) +#define error(S,s) +#else +#define IF(c,s) if (c) error(S,s) + +static void error(LoadState* S, const char* why) +{ + luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why); + luaD_throw(S->L,LUA_ERRSYNTAX); +} +#endif + +#define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) +#define LoadByte(S) (lu_byte)LoadChar(S) +#define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) +#define LoadVector(S,b,n,size) LoadMem(S,b,n,size) + +static void LoadBlock(LoadState* S, void* b, size_t size) +{ + size_t r=luaZ_read(S->Z,b,size); + IF (r!=0, "unexpected end"); +} + +static int LoadChar(LoadState* S) +{ + char x; + LoadVar(S,x); + return x; +} + +static int LoadInt(LoadState* S) +{ + int x; + LoadVar(S,x); + IF (x<0, "bad integer"); + return x; +} + +static lua_Number LoadNumber(LoadState* S) +{ + lua_Number x; + LoadVar(S,x); + return x; +} + +static TString* LoadString(LoadState* S) +{ + size_t size; + LoadVar(S,size); + if (size==0) + return NULL; + else + { + char* s=luaZ_openspace(S->L,S->b,size); + LoadBlock(S,s,size); + return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ + } +} + +static void LoadCode(LoadState* S, Proto* f) +{ + int n=LoadInt(S); + f->code=luaM_newvector(S->L,n,Instruction); + f->sizecode=n; + LoadVector(S,f->code,n,sizeof(Instruction)); +} + +static Proto* LoadFunction(LoadState* S, TString* p); + +static void LoadConstants(LoadState* S, Proto* f) +{ + int i,n; + n=LoadInt(S); + f->k=luaM_newvector(S->L,n,TValue); + f->sizek=n; + for (i=0; ik[i]); + for (i=0; ik[i]; + int t=LoadChar(S); + switch (t) + { + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o,LoadChar(S)!=0); + break; + case LUA_TNUMBER: + setnvalue(o,LoadNumber(S)); + break; + case LUA_TSTRING: + setsvalue2n(S->L,o,LoadString(S)); + break; + default: + error(S,"bad constant"); + break; + } + } + n=LoadInt(S); + f->p=luaM_newvector(S->L,n,Proto*); + f->sizep=n; + for (i=0; ip[i]=NULL; + for (i=0; ip[i]=LoadFunction(S,f->source); +} + +static void LoadDebug(LoadState* S, Proto* f) +{ + int i,n; + n=LoadInt(S); + f->lineinfo=luaM_newvector(S->L,n,int); + f->sizelineinfo=n; + LoadVector(S,f->lineinfo,n,sizeof(int)); + n=LoadInt(S); + f->locvars=luaM_newvector(S->L,n,LocVar); + f->sizelocvars=n; + for (i=0; ilocvars[i].varname=NULL; + for (i=0; ilocvars[i].varname=LoadString(S); + f->locvars[i].startpc=LoadInt(S); + f->locvars[i].endpc=LoadInt(S); + } + n=LoadInt(S); + f->upvalues=luaM_newvector(S->L,n,TString*); + f->sizeupvalues=n; + for (i=0; iupvalues[i]=NULL; + for (i=0; iupvalues[i]=LoadString(S); +} + +static Proto* LoadFunction(LoadState* S, TString* p) +{ + Proto* f; + if (++S->L->nCcalls > LUAI_MAXCCALLS) error(S,"code too deep"); + f=luaF_newproto(S->L); + setptvalue2s(S->L,S->L->top,f); incr_top(S->L); + f->source=LoadString(S); if (f->source==NULL) f->source=p; + f->linedefined=LoadInt(S); + f->lastlinedefined=LoadInt(S); + f->nups=LoadByte(S); + f->numparams=LoadByte(S); + f->is_vararg=LoadByte(S); + f->maxstacksize=LoadByte(S); + LoadCode(S,f); + LoadConstants(S,f); + LoadDebug(S,f); + IF (!luaG_checkcode(f), "bad code"); + S->L->top--; + S->L->nCcalls--; + return f; +} + +static void LoadHeader(LoadState* S) +{ + char h[LUAC_HEADERSIZE]; + char s[LUAC_HEADERSIZE]; + luaU_header(h); + LoadBlock(S,s,LUAC_HEADERSIZE); + IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header"); +} + +/* +** load precompiled chunk +*/ +Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) +{ + LoadState S; + if (*name=='@' || *name=='=') + S.name=name+1; + else if (*name==LUA_SIGNATURE[0]) + S.name="binary string"; + else + S.name=name; + S.L=L; + S.Z=Z; + S.b=buff; + LoadHeader(&S); + return LoadFunction(&S,luaS_newliteral(L,"=?")); +} + +/* +* make header +*/ +void luaU_header (char* h) +{ + int x=1; + memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1); + h+=sizeof(LUA_SIGNATURE)-1; + *h++=(char)LUAC_VERSION; + *h++=(char)LUAC_FORMAT; + *h++=(char)*(char*)&x; /* endianness */ + *h++=(char)sizeof(int); + *h++=(char)sizeof(size_t); + *h++=(char)sizeof(Instruction); + *h++=(char)sizeof(lua_Number); + *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */ +} diff --git a/lua/src/lundump.h b/lua/src/lundump.h new file mode 100644 index 0000000000..c80189dbff --- /dev/null +++ b/lua/src/lundump.h @@ -0,0 +1,36 @@ +/* +** $Id: lundump.h,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#ifndef lundump_h +#define lundump_h + +#include "lobject.h" +#include "lzio.h" + +/* load one chunk; from lundump.c */ +LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); + +/* make header; from lundump.c */ +LUAI_FUNC void luaU_header (char* h); + +/* dump one chunk; from ldump.c */ +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); + +#ifdef luac_c +/* print one chunk; from print.c */ +LUAI_FUNC void luaU_print (const Proto* f, int full); +#endif + +/* for header of binary files -- this is Lua 5.1 */ +#define LUAC_VERSION 0x51 + +/* for header of binary files -- this is the official format */ +#define LUAC_FORMAT 0 + +/* size of header of binary files */ +#define LUAC_HEADERSIZE 12 + +#endif diff --git a/lua/src/lvm.c b/lua/src/lvm.c new file mode 100644 index 0000000000..ee3256ab94 --- /dev/null +++ b/lua/src/lvm.c @@ -0,0 +1,763 @@ +/* +** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +#define lvm_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + + +/* limit for table tag-method chains (to avoid loops) */ +#define MAXTAGLOOP 100 + + +const TValue *luaV_tonumber (const TValue *obj, TValue *n) { + lua_Number num; + if (ttisnumber(obj)) return obj; + if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { + setnvalue(n, num); + return n; + } + else + return NULL; +} + + +int luaV_tostring (lua_State *L, StkId obj) { + if (!ttisnumber(obj)) + return 0; + else { + char s[LUAI_MAXNUMBER2STR]; + lua_Number n = nvalue(obj); + lua_number2str(s, n); + setsvalue2s(L, obj, luaS_new(L, s)); + return 1; + } +} + + +static void traceexec (lua_State *L, const Instruction *pc) { + lu_byte mask = L->hookmask; + const Instruction *oldpc = L->savedpc; + L->savedpc = pc; + if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { + resethookcount(L); + luaD_callhook(L, LUA_HOOKCOUNT, -1); + } + if (mask & LUA_MASKLINE) { + Proto *p = ci_func(L->ci)->l.p; + int npc = pcRel(pc, p); + int newline = getline(p, npc); + /* call linehook when enter a new function, when jump back (loop), + or when enter a new line */ + if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) + luaD_callhook(L, LUA_HOOKLINE, newline); + } +} + + +static void callTMres (lua_State *L, StkId res, const TValue *f, + const TValue *p1, const TValue *p2) { + ptrdiff_t result = savestack(L, res); + setobj2s(L, L->top, f); /* push function */ + setobj2s(L, L->top+1, p1); /* 1st argument */ + setobj2s(L, L->top+2, p2); /* 2nd argument */ + luaD_checkstack(L, 3); + L->top += 3; + luaD_call(L, L->top - 3, 1); + res = restorestack(L, result); + L->top--; + setobjs2s(L, res, L->top); +} + + + +static void callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, const TValue *p3) { + setobj2s(L, L->top, f); /* push function */ + setobj2s(L, L->top+1, p1); /* 1st argument */ + setobj2s(L, L->top+2, p2); /* 2nd argument */ + setobj2s(L, L->top+3, p3); /* 3th argument */ + luaD_checkstack(L, 4); + L->top += 4; + luaD_call(L, L->top - 4, 0); +} + + +void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { + int loop; + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; + if (ttistable(t)) { /* `t' is a table? */ + Table *h = hvalue(t); + const TValue *res = luaH_get(h, key); /* do a primitive get */ + if (!ttisnil(res) || /* result is no nil? */ + (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ + setobj2s(L, val, res); + return; + } + /* else will try the tag method */ + } + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) + luaG_typeerror(L, t, "index"); + if (ttisfunction(tm)) { + callTMres(L, val, tm, t, key); + return; + } + t = tm; /* else repeat with `tm' */ + } + luaG_runerror(L, "loop in gettable"); +} + + +void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { + int loop; + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; + if (ttistable(t)) { /* `t' is a table? */ + Table *h = hvalue(t); + TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ + if (!ttisnil(oldval) || /* result is no nil? */ + (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ + setobj2t(L, oldval, val); + luaC_barriert(L, h, val); + return; + } + /* else will try the tag method */ + } + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) + luaG_typeerror(L, t, "index"); + if (ttisfunction(tm)) { + callTM(L, tm, t, key, val); + return; + } + t = tm; /* else repeat with `tm' */ + } + luaG_runerror(L, "loop in settable"); +} + + +static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + if (ttisnil(tm)) + tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ + if (ttisnil(tm)) return 0; + callTMres(L, res, tm, p1, p2); + return 1; +} + + +static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, + TMS event) { + const TValue *tm1 = fasttm(L, mt1, event); + const TValue *tm2; + if (tm1 == NULL) return NULL; /* no metamethod */ + if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ + tm2 = fasttm(L, mt2, event); + if (tm2 == NULL) return NULL; /* no metamethod */ + if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */ + return tm1; + return NULL; +} + + +static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, + TMS event) { + const TValue *tm1 = luaT_gettmbyobj(L, p1, event); + const TValue *tm2; + if (ttisnil(tm1)) return -1; /* no metamethod? */ + tm2 = luaT_gettmbyobj(L, p2, event); + if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ + return -1; + callTMres(L, L->top, tm1, p1, p2); + return !l_isfalse(L->top); +} + + +static int l_strcmp (const TString *ls, const TString *rs) { + const char *l = getstr(ls); + size_t ll = ls->tsv.len; + const char *r = getstr(rs); + size_t lr = rs->tsv.len; + for (;;) { + int temp = strcoll(l, r); + if (temp != 0) return temp; + else { /* strings are equal up to a `\0' */ + size_t len = strlen(l); /* index of first `\0' in both strings */ + if (len == lr) /* r is finished? */ + return (len == ll) ? 0 : 1; + else if (len == ll) /* l is finished? */ + return -1; /* l is smaller than r (because r is not finished) */ + /* both strings longer than `len'; go on comparing (after the `\0') */ + len++; + l += len; ll -= len; r += len; lr -= len; + } + } +} + + +int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { + int res; + if (ttype(l) != ttype(r)) + return luaG_ordererror(L, l, r); + else if (ttisnumber(l)) + return luai_numlt(nvalue(l), nvalue(r)); + else if (ttisstring(l)) + return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; + else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) + return res; + return luaG_ordererror(L, l, r); +} + + +static int lessequal (lua_State *L, const TValue *l, const TValue *r) { + int res; + if (ttype(l) != ttype(r)) + return luaG_ordererror(L, l, r); + else if (ttisnumber(l)) + return luai_numle(nvalue(l), nvalue(r)); + else if (ttisstring(l)) + return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; + else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ + return res; + else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ + return !res; + return luaG_ordererror(L, l, r); +} + + +int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { + const TValue *tm; + lua_assert(ttype(t1) == ttype(t2)); + switch (ttype(t1)) { + case LUA_TNIL: return 1; + case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); + case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ + case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TUSERDATA: { + if (uvalue(t1) == uvalue(t2)) return 1; + tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, + TM_EQ); + break; /* will try TM */ + } + case LUA_TTABLE: { + if (hvalue(t1) == hvalue(t2)) return 1; + tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + default: return gcvalue(t1) == gcvalue(t2); + } + if (tm == NULL) return 0; /* no TM? */ + callTMres(L, L->top, tm, t1, t2); /* call TM */ + return !l_isfalse(L->top); +} + + +void luaV_concat (lua_State *L, int total, int last) { + do { + StkId top = L->base + last + 1; + int n = 2; /* number of elements handled in this pass (at least 2) */ + if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { + if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) + luaG_concaterror(L, top-2, top-1); + } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ + (void)tostring(L, top - 2); /* result is first op (as string) */ + else { + /* at least two string values; get as many as possible */ + size_t tl = tsvalue(top-1)->len; + char *buffer; + int i; + /* collect total length */ + for (n = 1; n < total && tostring(L, top-n-1); n++) { + size_t l = tsvalue(top-n-1)->len; + if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); + tl += l; + } + buffer = luaZ_openspace(L, &G(L)->buff, tl); + tl = 0; + for (i=n; i>0; i--) { /* concat all strings */ + size_t l = tsvalue(top-i)->len; + memcpy(buffer+tl, svalue(top-i), l); + tl += l; + } + setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); + } + total -= n-1; /* got `n' strings to create 1 new */ + last -= n-1; + } while (total > 1); /* repeat until only 1 result left */ +} + + +static void Arith (lua_State *L, StkId ra, const TValue *rb, + const TValue *rc, TMS op) { + TValue tempb, tempc; + const TValue *b, *c; + if ((b = luaV_tonumber(rb, &tempb)) != NULL && + (c = luaV_tonumber(rc, &tempc)) != NULL) { + lua_Number nb = nvalue(b), nc = nvalue(c); + switch (op) { + case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; + case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; + case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; + case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; + case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; + case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; + case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; + default: lua_assert(0); break; + } + } + else if (!call_binTM(L, rb, rc, ra, op)) + luaG_aritherror(L, rb, rc); +} + + + +/* +** some macros for common tasks in `luaV_execute' +*/ + +#define runtime_check(L, c) { if (!(c)) break; } + +#define RA(i) (base+GETARG_A(i)) +/* to be used after possible stack reallocation */ +#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) +#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) +#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ + ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) +#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ + ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) +#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) + + +#define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} + + +#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } + + +#define arith_op(op,tm) { \ + TValue *rb = RKB(i); \ + TValue *rc = RKC(i); \ + if (ttisnumber(rb) && ttisnumber(rc)) { \ + lua_Number nb = nvalue(rb), nc = nvalue(rc); \ + setnvalue(ra, op(nb, nc)); \ + } \ + else \ + Protect(Arith(L, ra, rb, rc, tm)); \ + } + + + +void luaV_execute (lua_State *L, int nexeccalls) { + LClosure *cl; + StkId base; + TValue *k; + const Instruction *pc; + reentry: /* entry point */ + lua_assert(isLua(L->ci)); + pc = L->savedpc; + cl = &clvalue(L->ci->func)->l; + base = L->base; + k = cl->p->k; + /* main loop of interpreter */ + for (;;) { + const Instruction i = *pc++; + StkId ra; + if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && + (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { + traceexec(L, pc); + if (L->status == LUA_YIELD) { /* did hook yield? */ + L->savedpc = pc - 1; + return; + } + base = L->base; + } + /* warning!! several calls may realloc the stack and invalidate `ra' */ + ra = RA(i); + lua_assert(base == L->base && L->base == L->ci->base); + lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); + lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); + switch (GET_OPCODE(i)) { + case OP_MOVE: { + setobjs2s(L, ra, RB(i)); + continue; + } + case OP_LOADK: { + setobj2s(L, ra, KBx(i)); + continue; + } + case OP_LOADBOOL: { + setbvalue(ra, GETARG_B(i)); + if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ + continue; + } + case OP_LOADNIL: { + TValue *rb = RB(i); + do { + setnilvalue(rb--); + } while (rb >= ra); + continue; + } + case OP_GETUPVAL: { + int b = GETARG_B(i); + setobj2s(L, ra, cl->upvals[b]->v); + continue; + } + case OP_GETGLOBAL: { + TValue g; + TValue *rb = KBx(i); + sethvalue(L, &g, cl->env); + lua_assert(ttisstring(rb)); + Protect(luaV_gettable(L, &g, rb, ra)); + continue; + } + case OP_GETTABLE: { + Protect(luaV_gettable(L, RB(i), RKC(i), ra)); + continue; + } + case OP_SETGLOBAL: { + TValue g; + sethvalue(L, &g, cl->env); + lua_assert(ttisstring(KBx(i))); + Protect(luaV_settable(L, &g, KBx(i), ra)); + continue; + } + case OP_SETUPVAL: { + UpVal *uv = cl->upvals[GETARG_B(i)]; + setobj(L, uv->v, ra); + luaC_barrier(L, uv, ra); + continue; + } + case OP_SETTABLE: { + Protect(luaV_settable(L, ra, RKB(i), RKC(i))); + continue; + } + case OP_NEWTABLE: { + int b = GETARG_B(i); + int c = GETARG_C(i); + sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); + Protect(luaC_checkGC(L)); + continue; + } + case OP_SELF: { + StkId rb = RB(i); + setobjs2s(L, ra+1, rb); + Protect(luaV_gettable(L, rb, RKC(i), ra)); + continue; + } + case OP_ADD: { + arith_op(luai_numadd, TM_ADD); + continue; + } + case OP_SUB: { + arith_op(luai_numsub, TM_SUB); + continue; + } + case OP_MUL: { + arith_op(luai_nummul, TM_MUL); + continue; + } + case OP_DIV: { + arith_op(luai_numdiv, TM_DIV); + continue; + } + case OP_MOD: { + arith_op(luai_nummod, TM_MOD); + continue; + } + case OP_POW: { + arith_op(luai_numpow, TM_POW); + continue; + } + case OP_UNM: { + TValue *rb = RB(i); + if (ttisnumber(rb)) { + lua_Number nb = nvalue(rb); + setnvalue(ra, luai_numunm(nb)); + } + else { + Protect(Arith(L, ra, rb, rb, TM_UNM)); + } + continue; + } + case OP_NOT: { + int res = l_isfalse(RB(i)); /* next assignment may change this value */ + setbvalue(ra, res); + continue; + } + case OP_LEN: { + const TValue *rb = RB(i); + switch (ttype(rb)) { + case LUA_TTABLE: { + setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); + break; + } + case LUA_TSTRING: { + setnvalue(ra, cast_num(tsvalue(rb)->len)); + break; + } + default: { /* try metamethod */ + Protect( + if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) + luaG_typeerror(L, rb, "get length of"); + ) + } + } + continue; + } + case OP_CONCAT: { + int b = GETARG_B(i); + int c = GETARG_C(i); + Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); + setobjs2s(L, RA(i), base+b); + continue; + } + case OP_JMP: { + dojump(L, pc, GETARG_sBx(i)); + continue; + } + case OP_EQ: { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + Protect( + if (equalobj(L, rb, rc) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; + } + case OP_LT: { + Protect( + if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; + } + case OP_LE: { + Protect( + if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; + } + case OP_TEST: { + if (l_isfalse(ra) != GETARG_C(i)) + dojump(L, pc, GETARG_sBx(*pc)); + pc++; + continue; + } + case OP_TESTSET: { + TValue *rb = RB(i); + if (l_isfalse(rb) != GETARG_C(i)) { + setobjs2s(L, ra, rb); + dojump(L, pc, GETARG_sBx(*pc)); + } + pc++; + continue; + } + case OP_CALL: { + int b = GETARG_B(i); + int nresults = GETARG_C(i) - 1; + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + L->savedpc = pc; + switch (luaD_precall(L, ra, nresults)) { + case PCRLUA: { + nexeccalls++; + goto reentry; /* restart luaV_execute over new Lua function */ + } + case PCRC: { + /* it was a C function (`precall' called it); adjust results */ + if (nresults >= 0) L->top = L->ci->top; + base = L->base; + continue; + } + default: { + return; /* yield */ + } + } + } + case OP_TAILCALL: { + int b = GETARG_B(i); + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + L->savedpc = pc; + lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); + switch (luaD_precall(L, ra, LUA_MULTRET)) { + case PCRLUA: { + /* tail call: put new frame in place of previous one */ + CallInfo *ci = L->ci - 1; /* previous frame */ + int aux; + StkId func = ci->func; + StkId pfunc = (ci+1)->func; /* previous function index */ + if (L->openupval) luaF_close(L, ci->base); + L->base = ci->base = ci->func + ((ci+1)->base - pfunc); + for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ + setobjs2s(L, func+aux, pfunc+aux); + ci->top = L->top = func+aux; /* correct top */ + lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); + ci->savedpc = L->savedpc; + ci->tailcalls++; /* one more call lost */ + L->ci--; /* remove new frame */ + goto reentry; + } + case PCRC: { /* it was a C function (`precall' called it) */ + base = L->base; + continue; + } + default: { + return; /* yield */ + } + } + } + case OP_RETURN: { + int b = GETARG_B(i); + if (b != 0) L->top = ra+b-1; + if (L->openupval) luaF_close(L, base); + L->savedpc = pc; + b = luaD_poscall(L, ra); + if (--nexeccalls == 0) /* was previous function running `here'? */ + return; /* no: return */ + else { /* yes: continue its execution */ + if (b) L->top = L->ci->top; + lua_assert(isLua(L->ci)); + lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); + goto reentry; + } + } + case OP_FORLOOP: { + lua_Number step = nvalue(ra+2); + lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ + lua_Number limit = nvalue(ra+1); + if (luai_numlt(0, step) ? luai_numle(idx, limit) + : luai_numle(limit, idx)) { + dojump(L, pc, GETARG_sBx(i)); /* jump back */ + setnvalue(ra, idx); /* update internal index... */ + setnvalue(ra+3, idx); /* ...and external index */ + } + continue; + } + case OP_FORPREP: { + const TValue *init = ra; + const TValue *plimit = ra+1; + const TValue *pstep = ra+2; + L->savedpc = pc; /* next steps may throw errors */ + if (!tonumber(init, ra)) + luaG_runerror(L, LUA_QL("for") " initial value must be a number"); + else if (!tonumber(plimit, ra+1)) + luaG_runerror(L, LUA_QL("for") " limit must be a number"); + else if (!tonumber(pstep, ra+2)) + luaG_runerror(L, LUA_QL("for") " step must be a number"); + setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); + dojump(L, pc, GETARG_sBx(i)); + continue; + } + case OP_TFORLOOP: { + StkId cb = ra + 3; /* call base */ + setobjs2s(L, cb+2, ra+2); + setobjs2s(L, cb+1, ra+1); + setobjs2s(L, cb, ra); + L->top = cb+3; /* func. + 2 args (state and index) */ + Protect(luaD_call(L, cb, GETARG_C(i))); + L->top = L->ci->top; + cb = RA(i) + 3; /* previous call may change the stack */ + if (!ttisnil(cb)) { /* continue loop? */ + setobjs2s(L, cb-1, cb); /* save control variable */ + dojump(L, pc, GETARG_sBx(*pc)); /* jump back */ + } + pc++; + continue; + } + case OP_SETLIST: { + int n = GETARG_B(i); + int c = GETARG_C(i); + int last; + Table *h; + if (n == 0) { + n = cast_int(L->top - ra) - 1; + L->top = L->ci->top; + } + if (c == 0) c = cast_int(*pc++); + runtime_check(L, ttistable(ra)); + h = hvalue(ra); + last = ((c-1)*LFIELDS_PER_FLUSH) + n; + if (last > h->sizearray) /* needs more space? */ + luaH_resizearray(L, h, last); /* pre-alloc it at once */ + for (; n > 0; n--) { + TValue *val = ra+n; + setobj2t(L, luaH_setnum(L, h, last--), val); + luaC_barriert(L, h, val); + } + continue; + } + case OP_CLOSE: { + luaF_close(L, ra); + continue; + } + case OP_CLOSURE: { + Proto *p; + Closure *ncl; + int nup, j; + p = cl->p->p[GETARG_Bx(i)]; + nup = p->nups; + ncl = luaF_newLclosure(L, nup, cl->env); + ncl->l.p = p; + for (j=0; jl.upvals[j] = cl->upvals[GETARG_B(*pc)]; + else { + lua_assert(GET_OPCODE(*pc) == OP_MOVE); + ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); + } + } + setclvalue(L, ra, ncl); + Protect(luaC_checkGC(L)); + continue; + } + case OP_VARARG: { + int b = GETARG_B(i) - 1; + int j; + CallInfo *ci = L->ci; + int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; + if (b == LUA_MULTRET) { + Protect(luaD_checkstack(L, n)); + ra = RA(i); /* previous call may change the stack */ + b = n; + L->top = ra + n; + } + for (j = 0; j < b; j++) { + if (j < n) { + setobjs2s(L, ra + j, ci->base - n + j); + } + else { + setnilvalue(ra + j); + } + } + continue; + } + } + } +} + diff --git a/lua/src/lvm.h b/lua/src/lvm.h new file mode 100644 index 0000000000..bfe4f5678d --- /dev/null +++ b/lua/src/lvm.h @@ -0,0 +1,36 @@ +/* +** $Id: lvm.h,v 2.5.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lvm_h +#define lvm_h + + +#include "ldo.h" +#include "lobject.h" +#include "ltm.h" + + +#define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o))) + +#define tonumber(o,n) (ttype(o) == LUA_TNUMBER || \ + (((o) = luaV_tonumber(o,n)) != NULL)) + +#define equalobj(L,o1,o2) \ + (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) + + +LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); +LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); +LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n); +LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj); +LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, + StkId val); +LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, + StkId val); +LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls); +LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); + +#endif diff --git a/lua/src/lzio.c b/lua/src/lzio.c new file mode 100644 index 0000000000..293edd59b0 --- /dev/null +++ b/lua/src/lzio.c @@ -0,0 +1,82 @@ +/* +** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ +** a generic input stream interface +** See Copyright Notice in lua.h +*/ + + +#include + +#define lzio_c +#define LUA_CORE + +#include "lua.h" + +#include "llimits.h" +#include "lmem.h" +#include "lstate.h" +#include "lzio.h" + + +int luaZ_fill (ZIO *z) { + size_t size; + lua_State *L = z->L; + const char *buff; + lua_unlock(L); + buff = z->reader(L, z->data, &size); + lua_lock(L); + if (buff == NULL || size == 0) return EOZ; + z->n = size - 1; + z->p = buff; + return char2int(*(z->p++)); +} + + +int luaZ_lookahead (ZIO *z) { + if (z->n == 0) { + if (luaZ_fill(z) == EOZ) + return EOZ; + else { + z->n++; /* luaZ_fill removed first byte; put back it */ + z->p--; + } + } + return char2int(*z->p); +} + + +void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { + z->L = L; + z->reader = reader; + z->data = data; + z->n = 0; + z->p = NULL; +} + + +/* --------------------------------------------------------------- read --- */ +size_t luaZ_read (ZIO *z, void *b, size_t n) { + while (n) { + size_t m; + if (luaZ_lookahead(z) == EOZ) + return n; /* return number of missing bytes */ + m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ + memcpy(b, z->p, m); + z->n -= m; + z->p += m; + b = (char *)b + m; + n -= m; + } + return 0; +} + +/* ------------------------------------------------------------------------ */ +char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { + if (n > buff->buffsize) { + if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; + luaZ_resizebuffer(L, buff, n); + } + return buff->buffer; +} + + diff --git a/lua/src/lzio.h b/lua/src/lzio.h new file mode 100644 index 0000000000..51d695d8c1 --- /dev/null +++ b/lua/src/lzio.h @@ -0,0 +1,67 @@ +/* +** $Id: lzio.h,v 1.21.1.1 2007/12/27 13:02:25 roberto Exp $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + + +#ifndef lzio_h +#define lzio_h + +#include "lua.h" + +#include "lmem.h" + + +#define EOZ (-1) /* end of stream */ + +typedef struct Zio ZIO; + +#define char2int(c) cast(int, cast(unsigned char, (c))) + +#define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) + +typedef struct Mbuffer { + char *buffer; + size_t n; + size_t buffsize; +} Mbuffer; + +#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) + +#define luaZ_buffer(buff) ((buff)->buffer) +#define luaZ_sizebuffer(buff) ((buff)->buffsize) +#define luaZ_bufflen(buff) ((buff)->n) + +#define luaZ_resetbuffer(buff) ((buff)->n = 0) + + +#define luaZ_resizebuffer(L, buff, size) \ + (luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ + (buff)->buffsize = size) + +#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) + + +LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); +LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, + void *data); +LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ +LUAI_FUNC int luaZ_lookahead (ZIO *z); + + + +/* --------- Private Part ------------------ */ + +struct Zio { + size_t n; /* bytes still unread */ + const char *p; /* current position in buffer */ + lua_Reader reader; + void* data; /* additional data */ + lua_State *L; /* Lua state (for reader) */ +}; + + +LUAI_FUNC int luaZ_fill (ZIO *z); + +#endif diff --git a/lua/src/print.c b/lua/src/print.c new file mode 100644 index 0000000000..e240cfc3c6 --- /dev/null +++ b/lua/src/print.c @@ -0,0 +1,227 @@ +/* +** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $ +** print bytecodes +** See Copyright Notice in lua.h +*/ + +#include +#include + +#define luac_c +#define LUA_CORE + +#include "ldebug.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lundump.h" + +#define PrintFunction luaU_print + +#define Sizeof(x) ((int)sizeof(x)) +#define VOID(p) ((const void*)(p)) + +static void PrintString(const TString* ts) +{ + const char* s=getstr(ts); + size_t i,n=ts->tsv.len; + putchar('"'); + for (i=0; ik[i]; + switch (ttype(o)) + { + case LUA_TNIL: + printf("nil"); + break; + case LUA_TBOOLEAN: + printf(bvalue(o) ? "true" : "false"); + break; + case LUA_TNUMBER: + printf(LUA_NUMBER_FMT,nvalue(o)); + break; + case LUA_TSTRING: + PrintString(rawtsvalue(o)); + break; + default: /* cannot happen */ + printf("? type=%d",ttype(o)); + break; + } +} + +static void PrintCode(const Proto* f) +{ + const Instruction* code=f->code; + int pc,n=f->sizecode; + for (pc=0; pc0) printf("[%d]\t",line); else printf("[-]\t"); + printf("%-9s\t",luaP_opnames[o]); + switch (getOpMode(o)) + { + case iABC: + printf("%d",a); + if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b); + if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); + break; + case iABx: + if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); + break; + case iAsBx: + if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); + break; + } + switch (o) + { + case OP_LOADK: + printf("\t; "); PrintConstant(f,bx); + break; + case OP_GETUPVAL: + case OP_SETUPVAL: + printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-"); + break; + case OP_GETGLOBAL: + case OP_SETGLOBAL: + printf("\t; %s",svalue(&f->k[bx])); + break; + case OP_GETTABLE: + case OP_SELF: + if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } + break; + case OP_SETTABLE: + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_DIV: + case OP_POW: + case OP_EQ: + case OP_LT: + case OP_LE: + if (ISK(b) || ISK(c)) + { + printf("\t; "); + if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); + printf(" "); + if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); + } + break; + case OP_JMP: + case OP_FORLOOP: + case OP_FORPREP: + printf("\t; to %d",sbx+pc+2); + break; + case OP_CLOSURE: + printf("\t; %p",VOID(f->p[bx])); + break; + case OP_SETLIST: + if (c==0) printf("\t; %d",(int)code[++pc]); + else printf("\t; %d",c); + break; + default: + break; + } + printf("\n"); + } +} + +#define SS(x) (x==1)?"":"s" +#define S(x) x,SS(x) + +static void PrintHeader(const Proto* f) +{ + const char* s=getstr(f->source); + if (*s=='@' || *s=='=') + s++; + else if (*s==LUA_SIGNATURE[0]) + s="(bstring)"; + else + s="(string)"; + printf("\n%s <%s:%d,%d> (%d instruction%s, %d bytes at %p)\n", + (f->linedefined==0)?"main":"function",s, + f->linedefined,f->lastlinedefined, + S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); + printf("%d%s param%s, %d slot%s, %d upvalue%s, ", + f->numparams,f->is_vararg?"+":"",SS(f->numparams), + S(f->maxstacksize),S(f->nups)); + printf("%d local%s, %d constant%s, %d function%s\n", + S(f->sizelocvars),S(f->sizek),S(f->sizep)); +} + +static void PrintConstants(const Proto* f) +{ + int i,n=f->sizek; + printf("constants (%d) for %p:\n",n,VOID(f)); + for (i=0; isizelocvars; + printf("locals (%d) for %p:\n",n,VOID(f)); + for (i=0; ilocvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); + } +} + +static void PrintUpvalues(const Proto* f) +{ + int i,n=f->sizeupvalues; + printf("upvalues (%d) for %p:\n",n,VOID(f)); + if (f->upvalues==NULL) return; + for (i=0; iupvalues[i])); + } +} + +void PrintFunction(const Proto* f, int full) +{ + int i,n=f->sizep; + PrintHeader(f); + PrintCode(f); + if (full) + { + PrintConstants(f); + PrintLocals(f); + PrintUpvalues(f); + } + for (i=0; ip[i],full); +} diff --git a/lua/tolua/tolua++.h b/lua/tolua/tolua++.h new file mode 100644 index 0000000000..ee66b0295f --- /dev/null +++ b/lua/tolua/tolua++.h @@ -0,0 +1,186 @@ +/* tolua +** Support code for Lua bindings. +** Written by Waldemar Celes +** TeCGraf/PUC-Rio +** Apr 2003 +** $Id: $ +*/ + +/* This code is free software; you can redistribute it and/or modify it. +** The software provided hereunder is on an "as is" basis, and +** the author has no obligation to provide maintenance, support, updates, +** enhancements, or modifications. +*/ + + +#ifndef TOLUA_H +#define TOLUA_H + +#ifndef TOLUA_API +#define TOLUA_API extern +#endif + +#define TOLUA_VERSION "tolua++-1.0.92" + +#ifdef __cplusplus +extern "C" { +#endif + +#define tolua_pushcppstring(x,y) tolua_pushstring(x,y.c_str()) +#define tolua_iscppstring tolua_isstring + +#define tolua_iscppstringarray tolua_isstringarray +#define tolua_pushfieldcppstring(L,lo,idx,s) tolua_pushfieldstring(L, lo, idx, s.c_str()) + +#ifndef TEMPLATE_BIND + #define TEMPLATE_BIND(p) +#endif + +#define TOLUA_TEMPLATE_BIND(p) + +#define TOLUA_PROTECTED_DESTRUCTOR +#define TOLUA_PROPERTY_TYPE(p) + +typedef int lua_Object; + +#include "lua.h" +#include "lauxlib.h" + +struct tolua_Error +{ + int index; + int array; + const char* type; +}; +typedef struct tolua_Error tolua_Error; + +#define TOLUA_NOPEER LUA_REGISTRYINDEX /* for lua 5.1 */ + +TOLUA_API const char* tolua_typename (lua_State* L, int lo); +TOLUA_API void tolua_error (lua_State* L, const char* msg, tolua_Error* err); +TOLUA_API int tolua_isnoobj (lua_State* L, int lo, tolua_Error* err); +TOLUA_API int tolua_isvalue (lua_State* L, int lo, int def, tolua_Error* err); +TOLUA_API int tolua_isvaluenil (lua_State* L, int lo, tolua_Error* err); +TOLUA_API int tolua_isboolean (lua_State* L, int lo, int def, tolua_Error* err); +TOLUA_API int tolua_isnumber (lua_State* L, int lo, int def, tolua_Error* err); +TOLUA_API int tolua_isstring (lua_State* L, int lo, int def, tolua_Error* err); +TOLUA_API int tolua_istable (lua_State* L, int lo, int def, tolua_Error* err); +TOLUA_API int tolua_isusertable (lua_State* L, int lo, const char* type, int def, tolua_Error* err); +TOLUA_API int tolua_isuserdata (lua_State* L, int lo, int def, tolua_Error* err); +TOLUA_API int tolua_isusertype (lua_State* L, int lo, const char* type, int def, tolua_Error* err); +TOLUA_API int tolua_isvaluearray + (lua_State* L, int lo, int dim, int def, tolua_Error* err); +TOLUA_API int tolua_isbooleanarray + (lua_State* L, int lo, int dim, int def, tolua_Error* err); +TOLUA_API int tolua_isnumberarray + (lua_State* L, int lo, int dim, int def, tolua_Error* err); +TOLUA_API int tolua_isstringarray + (lua_State* L, int lo, int dim, int def, tolua_Error* err); +TOLUA_API int tolua_istablearray + (lua_State* L, int lo, int dim, int def, tolua_Error* err); +TOLUA_API int tolua_isuserdataarray + (lua_State* L, int lo, int dim, int def, tolua_Error* err); +TOLUA_API int tolua_isusertypearray + (lua_State* L, int lo, const char* type, int dim, int def, tolua_Error* err); + +TOLUA_API void tolua_open (lua_State* L); + +TOLUA_API void* tolua_copy (lua_State* L, void* value, unsigned int size); +TOLUA_API int tolua_register_gc (lua_State* L, int lo); +TOLUA_API int tolua_default_collect (lua_State* tolua_S); + +TOLUA_API void tolua_usertype (lua_State* L, const char* type); +TOLUA_API void tolua_beginmodule (lua_State* L, const char* name); +TOLUA_API void tolua_endmodule (lua_State* L); +TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar); +TOLUA_API void tolua_class (lua_State* L, const char* name, const char* base); +TOLUA_API void tolua_cclass (lua_State* L, const char* lname, const char* name, const char* base, lua_CFunction col); +TOLUA_API void tolua_function (lua_State* L, const char* name, lua_CFunction func); +TOLUA_API void tolua_constant (lua_State* L, const char* name, lua_Number value); +TOLUA_API void tolua_variable (lua_State* L, const char* name, lua_CFunction get, lua_CFunction set); +TOLUA_API void tolua_array (lua_State* L,const char* name, lua_CFunction get, lua_CFunction set); + +/* TOLUA_API void tolua_set_call_event(lua_State* L, lua_CFunction func, char* type); */ + TOLUA_API void tolua_addbase(lua_State* L, char* name, char* base); + +TOLUA_API void tolua_pushvalue (lua_State* L, int lo); +TOLUA_API void tolua_pushboolean (lua_State* L, int value); +TOLUA_API void tolua_pushnumber (lua_State* L, lua_Number value); +TOLUA_API void tolua_pushstring (lua_State* L, const char* value); +TOLUA_API void tolua_pushuserdata (lua_State* L, void* value); +TOLUA_API void tolua_pushusertype (lua_State* L, void* value, const char* type); +TOLUA_API void tolua_pushusertype_and_takeownership(lua_State* L, void* value, const char* type); +TOLUA_API void tolua_pushfieldvalue (lua_State* L, int lo, int index, int v); +TOLUA_API void tolua_pushfieldboolean (lua_State* L, int lo, int index, int v); +TOLUA_API void tolua_pushfieldnumber (lua_State* L, int lo, int index, lua_Number v); +TOLUA_API void tolua_pushfieldstring (lua_State* L, int lo, int index, const char* v); +TOLUA_API void tolua_pushfielduserdata (lua_State* L, int lo, int index, void* v); +TOLUA_API void tolua_pushfieldusertype (lua_State* L, int lo, int index, void* v, const char* type); +TOLUA_API void tolua_pushfieldusertype_and_takeownership (lua_State* L, int lo, int index, void* v, const char* type); + +TOLUA_API lua_Number tolua_tonumber (lua_State* L, int narg, lua_Number def); +TOLUA_API const char* tolua_tostring (lua_State* L, int narg, const char* def); +TOLUA_API void* tolua_touserdata (lua_State* L, int narg, void* def); +TOLUA_API void* tolua_tousertype (lua_State* L, int narg, void* def); +TOLUA_API int tolua_tovalue (lua_State* L, int narg, int def); +TOLUA_API int tolua_toboolean (lua_State* L, int narg, int def); +TOLUA_API lua_Number tolua_tofieldnumber (lua_State* L, int lo, int index, lua_Number def); +TOLUA_API const char* tolua_tofieldstring (lua_State* L, int lo, int index, const char* def); +TOLUA_API void* tolua_tofielduserdata (lua_State* L, int lo, int index, void* def); +TOLUA_API void* tolua_tofieldusertype (lua_State* L, int lo, int index, void* def); +TOLUA_API int tolua_tofieldvalue (lua_State* L, int lo, int index, int def); +TOLUA_API int tolua_getfieldboolean (lua_State* L, int lo, int index, int def); + +TOLUA_API void tolua_dobuffer(lua_State* L, char* B, unsigned int size, const char* name); + +TOLUA_API int class_gc_event (lua_State* L); + +#ifdef __cplusplus +static inline const char* tolua_tocppstring (lua_State* L, int narg, const char* def) { + + const char* s = tolua_tostring(L, narg, def); + return s?s:""; +}; + +static inline const char* tolua_tofieldcppstring (lua_State* L, int lo, int index, const char* def) { + + const char* s = tolua_tofieldstring(L, lo, index, def); + return s?s:""; +}; + +#else +#define tolua_tocppstring tolua_tostring +#define tolua_tofieldcppstring tolua_tofieldstring +#endif + +TOLUA_API int tolua_fast_isa(lua_State *L, int mt_indexa, int mt_indexb, int super_index); + +#ifndef Mtolua_new +#define Mtolua_new(EXP) new EXP +#endif + +#ifndef Mtolua_delete +#define Mtolua_delete(EXP) delete EXP +#endif + +#ifndef Mtolua_new_dim +#define Mtolua_new_dim(EXP, len) new EXP[len] +#endif + +#ifndef Mtolua_delete_dim +#define Mtolua_delete_dim(EXP) delete [] EXP +#endif + +#ifndef tolua_outside +#define tolua_outside +#endif + +#ifndef tolua_owned +#define tolua_owned +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lua/tolua/tolua_event.c b/lua/tolua/tolua_event.c new file mode 100644 index 0000000000..8258867b42 --- /dev/null +++ b/lua/tolua/tolua_event.c @@ -0,0 +1,536 @@ +/* tolua: event functions +** Support code for Lua bindings. +** Written by Waldemar Celes +** TeCGraf/PUC-Rio +** Apr 2003 +** $Id: $ +*/ + +/* This code is free software; you can redistribute it and/or modify it. +** The software provided hereunder is on an "as is" basis, and +** the author has no obligation to provide maintenance, support, updates, +** enhancements, or modifications. +*/ + +#include + +#include "tolua++.h" + +/* Store at ubox + * It stores, creating the corresponding table if needed, + * the pair key/value in the corresponding ubox table +*/ +static void storeatubox (lua_State* L, int lo) +{ + #ifdef LUA_VERSION_NUM + lua_getfenv(L, lo); + if (lua_rawequal(L, -1, TOLUA_NOPEER)) { + lua_pop(L, 1); + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setfenv(L, lo); /* stack: k,v,table */ + }; + lua_insert(L, -3); + lua_settable(L, -3); /* on lua 5.1, we trade the "tolua_peers" lookup for a settable call */ + lua_pop(L, 1); + #else + /* stack: key value (to be stored) */ + lua_pushstring(L,"tolua_peers"); + lua_rawget(L,LUA_REGISTRYINDEX); /* stack: k v ubox */ + lua_pushvalue(L,lo); + lua_rawget(L,-2); /* stack: k v ubox ubox[u] */ + if (!lua_istable(L,-1)) + { + lua_pop(L,1); /* stack: k v ubox */ + lua_newtable(L); /* stack: k v ubox table */ + lua_pushvalue(L,1); + lua_pushvalue(L,-2); /* stack: k v ubox table u table */ + lua_rawset(L,-4); /* stack: k v ubox ubox[u]=table */ + } + lua_insert(L,-4); /* put table before k */ + lua_pop(L,1); /* pop ubox */ + lua_rawset(L,-3); /* store at table */ + lua_pop(L,1); /* pop ubox[u] */ + #endif +} + +/* Module index function +*/ +static int module_index_event (lua_State* L) +{ + lua_pushstring(L,".get"); + lua_rawget(L,-3); + if (lua_istable(L,-1)) + { + lua_pushvalue(L,2); /* key */ + lua_rawget(L,-2); + if (lua_iscfunction(L,-1)) + { + lua_call(L,0,1); + return 1; + } + else if (lua_istable(L,-1)) + return 1; + } + /* call old index meta event */ + if (lua_getmetatable(L,1)) + { + lua_pushstring(L,"__index"); + lua_rawget(L,-2); + lua_pushvalue(L,1); + lua_pushvalue(L,2); + if (lua_isfunction(L,-1)) + { + lua_call(L,2,1); + return 1; + } + else if (lua_istable(L,-1)) + { + lua_gettable(L,-3); + return 1; + } + } + lua_pushnil(L); + return 1; +} + +/* Module newindex function +*/ +static int module_newindex_event (lua_State* L) +{ + lua_pushstring(L,".set"); + lua_rawget(L,-4); + if (lua_istable(L,-1)) + { + lua_pushvalue(L,2); /* key */ + lua_rawget(L,-2); + if (lua_iscfunction(L,-1)) + { + lua_pushvalue(L,1); /* only to be compatible with non-static vars */ + lua_pushvalue(L,3); /* value */ + lua_call(L,2,0); + return 0; + } + } + /* call old newindex meta event */ + if (lua_getmetatable(L,1) && lua_getmetatable(L,-1)) + { + lua_pushstring(L,"__newindex"); + lua_rawget(L,-2); + if (lua_isfunction(L,-1)) + { + lua_pushvalue(L,1); + lua_pushvalue(L,2); + lua_pushvalue(L,3); + lua_call(L,3,0); + } + } + lua_settop(L,3); + lua_rawset(L,-3); + return 0; +} + +/* Class index function + * If the object is a userdata (ie, an object), it searches the field in + * the alternative table stored in the corresponding "ubox" table. +*/ +static int class_index_event (lua_State* L) +{ + int t = lua_type(L,1); + if (t == LUA_TUSERDATA) + { + /* Access alternative table */ + #ifdef LUA_VERSION_NUM /* new macro on version 5.1 */ + lua_getfenv(L,1); + if (!lua_rawequal(L, -1, TOLUA_NOPEER)) { + lua_pushvalue(L, 2); /* key */ + lua_gettable(L, -2); /* on lua 5.1, we trade the "tolua_peers" lookup for a gettable call */ + if (!lua_isnil(L, -1)) + return 1; + }; + #else + lua_pushstring(L,"tolua_peers"); + lua_rawget(L,LUA_REGISTRYINDEX); /* stack: obj key ubox */ + lua_pushvalue(L,1); + lua_rawget(L,-2); /* stack: obj key ubox ubox[u] */ + if (lua_istable(L,-1)) + { + lua_pushvalue(L,2); /* key */ + lua_rawget(L,-2); /* stack: obj key ubox ubox[u] value */ + if (!lua_isnil(L,-1)) + return 1; + } + #endif + lua_settop(L,2); /* stack: obj key */ + /* Try metatables */ + lua_pushvalue(L,1); /* stack: obj key obj */ + while (lua_getmetatable(L,-1)) + { /* stack: obj key obj mt */ + lua_remove(L,-2); /* stack: obj key mt */ + if (lua_isnumber(L,2)) /* check if key is a numeric value */ + { + /* try operator[] */ + lua_pushstring(L,".geti"); + lua_rawget(L,-2); /* stack: obj key mt func */ + if (lua_isfunction(L,-1)) + { + lua_pushvalue(L,1); + lua_pushvalue(L,2); + lua_call(L,2,1); + return 1; + } + } + else + { + lua_pushvalue(L,2); /* stack: obj key mt key */ + lua_rawget(L,-2); /* stack: obj key mt value */ + if (!lua_isnil(L,-1)) + return 1; + else + lua_pop(L,1); + /* try C/C++ variable */ + lua_pushstring(L,".get"); + lua_rawget(L,-2); /* stack: obj key mt tget */ + if (lua_istable(L,-1)) + { + lua_pushvalue(L,2); + lua_rawget(L,-2); /* stack: obj key mt value */ + if (lua_iscfunction(L,-1)) + { + lua_pushvalue(L,1); + lua_pushvalue(L,2); + lua_call(L,2,1); + return 1; + } + else if (lua_istable(L,-1)) + { + /* deal with array: create table to be returned and cache it in ubox */ + void* u = *((void**)lua_touserdata(L,1)); + lua_newtable(L); /* stack: obj key mt value table */ + lua_pushstring(L,".self"); + lua_pushlightuserdata(L,u); + lua_rawset(L,-3); /* store usertype in ".self" */ + lua_insert(L,-2); /* stack: obj key mt table value */ + lua_setmetatable(L,-2); /* set stored value as metatable */ + lua_pushvalue(L,-1); /* stack: obj key met table table */ + lua_pushvalue(L,2); /* stack: obj key mt table table key */ + lua_insert(L,-2); /* stack: obj key mt table key table */ + storeatubox(L,1); /* stack: obj key mt table */ + return 1; + } + } + } + lua_settop(L,3); + } + lua_pushnil(L); + return 1; + } + else if (t== LUA_TTABLE) + { + module_index_event(L); + return 1; + } + lua_pushnil(L); + return 1; +} + +/* Newindex function + * It first searches for a C/C++ varaible to be set. + * Then, it either stores it in the alternative ubox table (in the case it is + * an object) or in the own table (that represents the class or module). +*/ +static int class_newindex_event (lua_State* L) +{ + int t = lua_type(L,1); + if (t == LUA_TUSERDATA) + { + /* Try accessing a C/C++ variable to be set */ + lua_getmetatable(L,1); + while (lua_istable(L,-1)) /* stack: t k v mt */ + { + if (lua_isnumber(L,2)) /* check if key is a numeric value */ + { + /* try operator[] */ + lua_pushstring(L,".seti"); + lua_rawget(L,-2); /* stack: obj key mt func */ + if (lua_isfunction(L,-1)) + { + lua_pushvalue(L,1); + lua_pushvalue(L,2); + lua_pushvalue(L,3); + lua_call(L,3,0); + return 0; + } + } + else + { + lua_pushstring(L,".set"); + lua_rawget(L,-2); /* stack: t k v mt tset */ + if (lua_istable(L,-1)) + { + lua_pushvalue(L,2); + lua_rawget(L,-2); /* stack: t k v mt tset func */ + if (lua_iscfunction(L,-1)) + { + lua_pushvalue(L,1); + lua_pushvalue(L,3); + lua_call(L,2,0); + return 0; + } + lua_pop(L,1); /* stack: t k v mt tset */ + } + lua_pop(L,1); /* stack: t k v mt */ + if (!lua_getmetatable(L,-1)) /* stack: t k v mt mt */ + lua_pushnil(L); + lua_remove(L,-2); /* stack: t k v mt */ + } + } + lua_settop(L,3); /* stack: t k v */ + + /* then, store as a new field */ + storeatubox(L,1); + } + else if (t== LUA_TTABLE) + { + module_newindex_event(L); + } + return 0; +} + +static int class_call_event(lua_State* L) { + + if (lua_istable(L, 1)) { + lua_pushstring(L, ".call"); + lua_rawget(L, 1); + if (lua_isfunction(L, -1)) { + + lua_insert(L, 1); + lua_call(L, lua_gettop(L)-1, 1); + + return 1; + }; + }; + tolua_error(L,"Attempt to call a non-callable object.",NULL); + return 0; +}; + +static int do_operator (lua_State* L, const char* op) +{ + if (lua_isuserdata(L,1)) + { + /* Try metatables */ + lua_pushvalue(L,1); /* stack: op1 op2 */ + while (lua_getmetatable(L,-1)) + { /* stack: op1 op2 op1 mt */ + lua_remove(L,-2); /* stack: op1 op2 mt */ + lua_pushstring(L,op); /* stack: op1 op2 mt key */ + lua_rawget(L,-2); /* stack: obj key mt func */ + if (lua_isfunction(L,-1)) + { + lua_pushvalue(L,1); + lua_pushvalue(L,2); + lua_call(L,2,1); + return 1; + } + lua_settop(L,3); + } + } + tolua_error(L,"Attempt to perform operation on an invalid operand",NULL); + return 0; +} + +static int class_add_event (lua_State* L) +{ + return do_operator(L,".add"); +} + +static int class_sub_event (lua_State* L) +{ + return do_operator(L,".sub"); +} + +static int class_mul_event (lua_State* L) +{ + return do_operator(L,".mul"); +} + +static int class_div_event (lua_State* L) +{ + return do_operator(L,".div"); +} + +static int class_lt_event (lua_State* L) +{ + return do_operator(L,".lt"); +} + +static int class_le_event (lua_State* L) +{ + return do_operator(L,".le"); +} + +static int class_eq_event (lua_State* L) +{ + /* copying code from do_operator here to return false when no operator is found */ + if (lua_isuserdata(L,1)) + { + /* Try metatables */ + lua_pushvalue(L,1); /* stack: op1 op2 */ + while (lua_getmetatable(L,-1)) + { /* stack: op1 op2 op1 mt */ + lua_remove(L,-2); /* stack: op1 op2 mt */ + lua_pushstring(L,".eq"); /* stack: op1 op2 mt key */ + lua_rawget(L,-2); /* stack: obj key mt func */ + if (lua_isfunction(L,-1)) + { + lua_pushvalue(L,1); + lua_pushvalue(L,2); + lua_call(L,2,1); + return 1; + } + lua_settop(L,3); + } + } + + lua_settop(L, 3); + lua_pushboolean(L, 0); + return 1; +} + +/* +static int class_gc_event (lua_State* L) +{ + void* u = *((void**)lua_touserdata(L,1)); + fprintf(stderr, "collecting: looking at %p\n", u); + lua_pushstring(L,"tolua_gc"); + lua_rawget(L,LUA_REGISTRYINDEX); + lua_pushlightuserdata(L,u); + lua_rawget(L,-2); + if (lua_isfunction(L,-1)) + { + lua_pushvalue(L,1); + lua_call(L,1,0); + lua_pushlightuserdata(L,u); + lua_pushnil(L); + lua_rawset(L,-3); + } + lua_pop(L,2); + return 0; +} +*/ +TOLUA_API int class_gc_event (lua_State* L) +{ + void* u = *((void**)lua_touserdata(L,1)); + int top; + /*fprintf(stderr, "collecting: looking at %p\n", u);*/ + /* + lua_pushstring(L,"tolua_gc"); + lua_rawget(L,LUA_REGISTRYINDEX); + */ + lua_pushvalue(L, lua_upvalueindex(1)); + lua_pushlightuserdata(L,u); + lua_rawget(L,-2); /* stack: gc umt */ + lua_getmetatable(L,1); /* stack: gc umt mt */ + /*fprintf(stderr, "checking type\n");*/ + top = lua_gettop(L); + if (tolua_fast_isa(L,top,top-1, lua_upvalueindex(2))) /* make sure we collect correct type */ + { + /*fprintf(stderr, "Found type!\n");*/ + /* get gc function */ + lua_pushliteral(L,".collector"); + lua_rawget(L,-2); /* stack: gc umt mt collector */ + if (lua_isfunction(L,-1)) { + /*fprintf(stderr, "Found .collector!\n");*/ + } + else { + lua_pop(L,1); + /*fprintf(stderr, "Using default cleanup\n");*/ + lua_pushcfunction(L,tolua_default_collect); + } + + lua_pushvalue(L,1); /* stack: gc umt mt collector u */ + lua_call(L,1,0); + + lua_pushlightuserdata(L,u); /* stack: gc umt mt u */ + lua_pushnil(L); /* stack: gc umt mt u nil */ + lua_rawset(L,-5); /* stack: gc umt mt */ + } + lua_pop(L,3); + return 0; +} + + +/* Register module events + * It expects the metatable on the top of the stack +*/ +TOLUA_API void tolua_moduleevents (lua_State* L) +{ + lua_pushstring(L,"__index"); + lua_pushcfunction(L,module_index_event); + lua_rawset(L,-3); + lua_pushstring(L,"__newindex"); + lua_pushcfunction(L,module_newindex_event); + lua_rawset(L,-3); +} + +/* Check if the object on the top has a module metatable +*/ +TOLUA_API int tolua_ismodulemetatable (lua_State* L) +{ + int r = 0; + if (lua_getmetatable(L,-1)) + { + lua_pushstring(L,"__index"); + lua_rawget(L,-2); + r = (lua_tocfunction(L,-1) == module_index_event); + lua_pop(L,2); + } + return r; +} + +/* Register class events + * It expects the metatable on the top of the stack +*/ +TOLUA_API void tolua_classevents (lua_State* L) +{ + lua_pushstring(L,"__index"); + lua_pushcfunction(L,class_index_event); + lua_rawset(L,-3); + lua_pushstring(L,"__newindex"); + lua_pushcfunction(L,class_newindex_event); + lua_rawset(L,-3); + + lua_pushstring(L,"__add"); + lua_pushcfunction(L,class_add_event); + lua_rawset(L,-3); + lua_pushstring(L,"__sub"); + lua_pushcfunction(L,class_sub_event); + lua_rawset(L,-3); + lua_pushstring(L,"__mul"); + lua_pushcfunction(L,class_mul_event); + lua_rawset(L,-3); + lua_pushstring(L,"__div"); + lua_pushcfunction(L,class_div_event); + lua_rawset(L,-3); + + lua_pushstring(L,"__lt"); + lua_pushcfunction(L,class_lt_event); + lua_rawset(L,-3); + lua_pushstring(L,"__le"); + lua_pushcfunction(L,class_le_event); + lua_rawset(L,-3); + lua_pushstring(L,"__eq"); + lua_pushcfunction(L,class_eq_event); + lua_rawset(L,-3); + + lua_pushstring(L,"__call"); + lua_pushcfunction(L,class_call_event); + lua_rawset(L,-3); + + lua_pushstring(L,"__gc"); + lua_pushstring(L, "tolua_gc_event"); + lua_rawget(L, LUA_REGISTRYINDEX); + /*lua_pushcfunction(L,class_gc_event);*/ + lua_rawset(L,-3); +} + diff --git a/lua/tolua/tolua_event.h b/lua/tolua/tolua_event.h new file mode 100644 index 0000000000..898f33dfcb --- /dev/null +++ b/lua/tolua/tolua_event.h @@ -0,0 +1,24 @@ +/* tolua: event functions +** Support code for Lua bindings. +** Written by Waldemar Celes +** TeCGraf/PUC-Rio +** Apr 2003 +** $Id: $ +*/ + +/* This code is free software; you can redistribute it and/or modify it. +** The software provided hereunder is on an "as is" basis, and +** the author has no obligation to provide maintenance, support, updates, +** enhancements, or modifications. +*/ + +#ifndef TOLUA_EVENT_H +#define TOLUA_EVENT_H + +#include "tolua++.h" + +TOLUA_API void tolua_moduleevents (lua_State* L); +TOLUA_API int tolua_ismodulemetatable (lua_State* L); +TOLUA_API void tolua_classevents (lua_State* L); + +#endif diff --git a/lua/tolua/tolua_is.c b/lua/tolua/tolua_is.c new file mode 100644 index 0000000000..add337d19a --- /dev/null +++ b/lua/tolua/tolua_is.c @@ -0,0 +1,621 @@ +/* tolua: functions to check types. +** Support code for Lua bindings. +** Written by Waldemar Celes +** TeCGraf/PUC-Rio +** Apr 2003 +** $Id: $ +*/ + +/* This code is free software; you can redistribute it and/or modify it. +** The software provided hereunder is on an "as is" basis, and +** the author has no obligation to provide maintenance, support, updates, +** enhancements, or modifications. +*/ + +#include "tolua++.h" +#include "lauxlib.h" + +#include +#include + +/* a fast check if a is b, without parameter validation + i.e. if b is equal to a or a superclass of a. */ +TOLUA_API int tolua_fast_isa(lua_State *L, int mt_indexa, int mt_indexb, int super_index) +{ + int result; + if (lua_rawequal(L,mt_indexa,mt_indexb)) + result = 1; + else + { + if (super_index) { + lua_pushvalue(L, super_index); + } else { + lua_pushliteral(L,"tolua_super"); + lua_rawget(L,LUA_REGISTRYINDEX); /* stack: super */ + }; + lua_pushvalue(L,mt_indexa); /* stack: super mta */ + lua_rawget(L,-2); /* stack: super super[mta] */ + lua_pushvalue(L,mt_indexb); /* stack: super super[mta] mtb */ + lua_rawget(L,LUA_REGISTRYINDEX); /* stack: super super[mta] typenameB */ + lua_rawget(L,-2); /* stack: super super[mta] bool */ + result = lua_toboolean(L,-1); + lua_pop(L,3); + } + return result; +} + +/* Push and returns the corresponding object typename */ +TOLUA_API const char* tolua_typename (lua_State* L, int lo) +{ + int tag = lua_type(L,lo); + if (tag == LUA_TNONE) + lua_pushstring(L,"[no object]"); + else if (tag != LUA_TUSERDATA && tag != LUA_TTABLE) + lua_pushstring(L,lua_typename(L,tag)); + else if (tag == LUA_TUSERDATA) + { + if (!lua_getmetatable(L,lo)) + lua_pushstring(L,lua_typename(L,tag)); + else + { + lua_rawget(L,LUA_REGISTRYINDEX); + if (!lua_isstring(L,-1)) + { + lua_pop(L,1); + lua_pushstring(L,"[undefined]"); + } + } + } + else /* is table */ + { + lua_pushvalue(L,lo); + lua_rawget(L,LUA_REGISTRYINDEX); + if (!lua_isstring(L,-1)) + { + lua_pop(L,1); + lua_pushstring(L,"table"); + } + else + { + lua_pushstring(L,"class "); + lua_insert(L,-2); + lua_concat(L,2); + } + } + return lua_tostring(L,-1); +} + +TOLUA_API void tolua_error (lua_State* L, const char* msg, tolua_Error* err) +{ + if (msg[0] == '#') + { + const char* expected = err->type; + const char* provided = tolua_typename(L,err->index); + if (msg[1]=='f') + { + int narg = err->index; + if (err->array) + luaL_error(L,"%s\n argument #%d is array of '%s'; array of '%s' expected.\n", + msg+2,narg,provided,expected); + else + luaL_error(L,"%s\n argument #%d is '%s'; '%s' expected.\n", + msg+2,narg,provided,expected); + } + else if (msg[1]=='v') + { + if (err->array) + luaL_error(L,"%s\n value is array of '%s'; array of '%s' expected.\n", + msg+2,provided,expected); + else + luaL_error(L,"%s\n value is '%s'; '%s' expected.\n", + msg+2,provided,expected); + } + } + else + luaL_error(L,msg); +} + +/* the equivalent of lua_is* for usertable */ +static int lua_isusertable (lua_State* L, int lo, const const char* type) +{ + int r = 0; + if (lo < 0) lo = lua_gettop(L)+lo+1; + lua_pushvalue(L,lo); + lua_rawget(L,LUA_REGISTRYINDEX); /* get registry[t] */ + if (lua_isstring(L,-1)) + { + r = strcmp(lua_tostring(L,-1),type)==0; + if (!r) + { + /* try const */ + lua_pushstring(L,"const "); + lua_insert(L,-2); + lua_concat(L,2); + r = lua_isstring(L,-1) && strcmp(lua_tostring(L,-1),type)==0; + } + } + lua_pop(L, 1); + return r; +} + +int push_table_instance(lua_State* L, int lo) { + + if (lua_istable(L, lo)) { + + lua_pushstring(L, ".c_instance"); + lua_gettable(L, lo); + if (lua_isuserdata(L, -1)) { + + lua_replace(L, lo); + return 1; + } else { + + lua_pop(L, 1); + return 0; + }; + } else { + return 0; + }; + + return 0; +}; + +/* the equivalent of lua_is* for usertype */ +static int lua_isusertype (lua_State* L, int lo, const char* type) +{ + if (!lua_isuserdata(L,lo)) { + if (!push_table_instance(L, lo)) { + return 0; + }; + }; + { + /* check if it is of the same type */ + int r; + const char *tn; + if (lua_getmetatable(L,lo)) /* if metatable? */ + { + lua_rawget(L,LUA_REGISTRYINDEX); /* get registry[mt] */ + tn = lua_tostring(L,-1); + r = tn && (strcmp(tn,type) == 0); + lua_pop(L, 1); + if (r) + return 1; + else + { + /* check if it is a specialized class */ + lua_pushstring(L,"tolua_super"); + lua_rawget(L,LUA_REGISTRYINDEX); /* get super */ + lua_getmetatable(L,lo); + lua_rawget(L,-2); /* get super[mt] */ + if (lua_istable(L,-1)) + { + int b; + lua_pushstring(L,type); + lua_rawget(L,-2); /* get super[mt][type] */ + b = lua_toboolean(L,-1); + lua_pop(L,3); + if (b) + return 1; + } + } + } + } + return 0; +} + +TOLUA_API int tolua_isnoobj (lua_State* L, int lo, tolua_Error* err) +{ + if (lua_gettop(L)index = lo; + err->array = 0; + err->type = "[no object]"; + return 0; +} + +TOLUA_API int tolua_isboolean (lua_State* L, int lo, int def, tolua_Error* err) +{ + if (def && lua_gettop(L)index = lo; + err->array = 0; + err->type = "boolean"; + return 0; +} + +TOLUA_API int tolua_isnumber (lua_State* L, int lo, int def, tolua_Error* err) +{ + if (def && lua_gettop(L)index = lo; + err->array = 0; + err->type = "number"; + return 0; +} + +TOLUA_API int tolua_isstring (lua_State* L, int lo, int def, tolua_Error* err) +{ + if (def && lua_gettop(L)index = lo; + err->array = 0; + err->type = "string"; + return 0; +} + +TOLUA_API int tolua_istable (lua_State* L, int lo, int def, tolua_Error* err) +{ + if (def && lua_gettop(L)index = lo; + err->array = 0; + err->type = "table"; + return 0; +} + +TOLUA_API int tolua_isusertable (lua_State* L, int lo, const char* type, int def, tolua_Error* err) +{ + if (def && lua_gettop(L)index = lo; + err->array = 0; + err->type = type; + return 0; +} + + +TOLUA_API int tolua_isuserdata (lua_State* L, int lo, int def, tolua_Error* err) +{ + if (def && lua_gettop(L)index = lo; + err->array = 0; + err->type = "userdata"; + return 0; +} + +TOLUA_API int tolua_isvaluenil (lua_State* L, int lo, tolua_Error* err) { + + if (lua_gettop(L)index = lo; + err->array = 0; + err->type = "value"; + return 1; +}; + +TOLUA_API int tolua_isvalue (lua_State* L, int lo, int def, tolua_Error* err) +{ + if (def || abs(lo)<=lua_gettop(L)) /* any valid index */ + return 1; + err->index = lo; + err->array = 0; + err->type = "value"; + return 0; +} + +TOLUA_API int tolua_isusertype (lua_State* L, int lo, const char* type, int def, tolua_Error* err) +{ + if (def && lua_gettop(L)index = lo; + err->array = 0; + err->type = type; + return 0; +} + +TOLUA_API int tolua_isvaluearray + (lua_State* L, int lo, int dim, int def, tolua_Error* err) +{ + if (!tolua_istable(L,lo,def,err)) + return 0; + else + return 1; +} + +TOLUA_API int tolua_isbooleanarray + (lua_State* L, int lo, int dim, int def, tolua_Error* err) +{ + if (!tolua_istable(L,lo,def,err)) + return 0; + else + { + int i; + for (i=1; i<=dim; ++i) + { + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (!(lua_isnil(L,-1) || lua_isboolean(L,-1)) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->array = 1; + err->type = "boolean"; + return 0; + } + lua_pop(L,1); + } + } + return 1; +} + +TOLUA_API int tolua_isnumberarray + (lua_State* L, int lo, int dim, int def, tolua_Error* err) +{ + if (!tolua_istable(L,lo,def,err)) + return 0; + else + { + int i; + for (i=1; i<=dim; ++i) + { + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (!lua_isnumber(L,-1) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->array = 1; + err->type = "number"; + return 0; + } + lua_pop(L,1); + } + } + return 1; +} + +TOLUA_API int tolua_isstringarray + (lua_State* L, int lo, int dim, int def, tolua_Error* err) +{ + if (!tolua_istable(L,lo,def,err)) + return 0; + else + { + int i; + for (i=1; i<=dim; ++i) + { + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (!(lua_isnil(L,-1) || lua_isstring(L,-1)) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->array = 1; + err->type = "string"; + return 0; + } + lua_pop(L,1); + } + } + return 1; +} + +TOLUA_API int tolua_istablearray + (lua_State* L, int lo, int dim, int def, tolua_Error* err) +{ + if (!tolua_istable(L,lo,def,err)) + return 0; + else + { + int i; + for (i=1; i<=dim; ++i) + { + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (! lua_istable(L,-1) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->array = 1; + err->type = "table"; + return 0; + } + lua_pop(L,1); + } + } + return 1; +} + +TOLUA_API int tolua_isuserdataarray + (lua_State* L, int lo, int dim, int def, tolua_Error* err) +{ + if (!tolua_istable(L,lo,def,err)) + return 0; + else + { + int i; + for (i=1; i<=dim; ++i) + { + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (!(lua_isnil(L,-1) || lua_isuserdata(L,-1)) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->array = 1; + err->type = "userdata"; + return 0; + } + lua_pop(L,1); + } + } + return 1; +} + +TOLUA_API int tolua_isusertypearray + (lua_State* L, int lo, const char* type, int dim, int def, tolua_Error* err) +{ + if (!tolua_istable(L,lo,def,err)) + return 0; + else + { + int i; + for (i=1; i<=dim; ++i) + { + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (!(lua_isnil(L,-1) || lua_isuserdata(L,-1)) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->type = type; + err->array = 1; + return 0; + } + lua_pop(L,1); + } + } + return 1; +} + +#if 0 +int tolua_isbooleanfield + (lua_State* L, int lo, int i, int def, tolua_Error* err) +{ + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (!(lua_isnil(L,-1) || lua_isboolean(L,-1)) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->array = 1; + err->type = "boolean"; + return 0; + } + lua_pop(L,1); + return 1; +} + +int tolua_isnumberfield + (lua_State* L, int lo, int i, int def, tolua_Error* err) +{ + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (!lua_isnumber(L,-1) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->array = 1; + err->type = "number"; + return 0; + } + lua_pop(L,1); + return 1; +} + +int tolua_isstringfield + (lua_State* L, int lo, int i, int def, tolua_Error* err) +{ + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (!(lua_isnil(L,-1) || lua_isstring(L,-1)) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->array = 1; + err->type = "string"; + return 0; + } + lua_pop(L,1); + return 1; +} + +int tolua_istablefield + (lua_State* L, int lo, int i, int def, tolua_Error* err) +{ + lua_pushnumber(L,i+1); + lua_gettable(L,lo); + if (! lua_istable(L,-1) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->array = 1; + err->type = "table"; + return 0; + } + lua_pop(L,1); +} + +int tolua_isusertablefield + (lua_State* L, int lo, const char* type, int i, int def, tolua_Error* err) +{ + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (! lua_isusertable(L,-1,type) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->array = 1; + err->type = type; + return 0; + } + lua_pop(L,1); + return 1; +} + +int tolua_isuserdatafield + (lua_State* L, int lo, int i, int def, tolua_Error* err) +{ + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (!(lua_isnil(L,-1) || lua_isuserdata(L,-1)) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->array = 1; + err->type = "userdata"; + return 0; + } + lua_pop(L,1); + return 1; +} + +int tolua_isusertypefield + (lua_State* L, int lo, const char* type, int i, int def, tolua_Error* err) +{ + lua_pushnumber(L,i); + lua_gettable(L,lo); + if (!(lua_isnil(L,-1) || lua_isusertype(L,-1,type)) && + !(def && lua_isnil(L,-1)) + ) + { + err->index = lo; + err->type = type; + err->array = 1; + return 0; + } + lua_pop(L,1); + return 1; +} + +#endif diff --git a/lua/tolua/tolua_map.c b/lua/tolua/tolua_map.c new file mode 100644 index 0000000000..af40b6f51a --- /dev/null +++ b/lua/tolua/tolua_map.c @@ -0,0 +1,705 @@ +/* tolua: functions to map features +** Support code for Lua bindings. +** Written by Waldemar Celes +** TeCGraf/PUC-Rio +** Apr 2003 +** $Id: $ +*/ + +/* This code is free software; you can redistribute it and/or modify it. +** The software provided hereunder is on an "as is" basis, and +** the author has no obligation to provide maintenance, support, updates, +** enhancements, or modifications. +*/ + +#include "tolua++.h" +#include "tolua_event.h" +#include "lauxlib.h" + +#include +#include +#include +#include + + +/* Create metatable + * Create and register new metatable +*/ +static int tolua_newmetatable (lua_State* L, char* name) +{ + int r = luaL_newmetatable(L,name); + + #ifdef LUA_VERSION_NUM /* only lua 5.1 */ + if (r) { + lua_pushvalue(L, -1); + lua_pushstring(L, name); + lua_settable(L, LUA_REGISTRYINDEX); /* reg[mt] = type_name */ + }; + #endif + + if (r) + tolua_classevents(L); /* set meta events */ + lua_pop(L,1); + return r; +} + +/* Map super classes + * It sets 'name' as being also a 'base', mapping all super classes of 'base' in 'name' +*/ +static void mapsuper (lua_State* L, const char* name, const char* base) +{ + /* push registry.super */ + lua_pushstring(L,"tolua_super"); + lua_rawget(L,LUA_REGISTRYINDEX); /* stack: super */ + luaL_getmetatable(L,name); /* stack: super mt */ + lua_rawget(L,-2); /* stack: super table */ + if (lua_isnil(L,-1)) + { + /* create table */ + lua_pop(L,1); + lua_newtable(L); /* stack: super table */ + luaL_getmetatable(L,name); /* stack: super table mt */ + lua_pushvalue(L,-2); /* stack: super table mt table */ + lua_rawset(L,-4); /* stack: super table */ + } + + /* set base as super class */ + lua_pushstring(L,base); + lua_pushboolean(L,1); + lua_rawset(L,-3); /* stack: super table */ + + /* set all super class of base as super class of name */ + luaL_getmetatable(L,base); /* stack: super table base_mt */ + lua_rawget(L,-3); /* stack: super table base_table */ + if (lua_istable(L,-1)) + { + /* traverse base table */ + lua_pushnil(L); /* first key */ + while (lua_next(L,-2) != 0) + { + /* stack: ... base_table key value */ + lua_pushvalue(L,-2); /* stack: ... base_table key value key */ + lua_insert(L,-2); /* stack: ... base_table key key value */ + lua_rawset(L,-5); /* stack: ... base_table key */ + } + } + lua_pop(L,3); /* stack: */ +} + +/* creates a 'tolua_ubox' table for base clases, and +// expects the metatable and base metatable on the stack */ +static void set_ubox(lua_State* L) { + + /* mt basemt */ + if (!lua_isnil(L, -1)) { + lua_pushstring(L, "tolua_ubox"); + lua_rawget(L,-2); + } else { + lua_pushnil(L); + }; + /* mt basemt base_ubox */ + if (!lua_isnil(L,-1)) { + lua_pushstring(L, "tolua_ubox"); + lua_insert(L, -2); + /* mt basemt key ubox */ + lua_rawset(L,-4); + /* (mt with ubox) basemt */ + } else { + /* mt basemt nil */ + lua_pop(L, 1); + lua_pushstring(L,"tolua_ubox"); lua_newtable(L); + /* make weak value metatable for ubox table to allow userdata to be + garbage-collected */ + lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "v"); lua_rawset(L, -3); /* stack: string ubox mt */ + lua_setmetatable(L, -2); /* stack:mt basemt string ubox */ + lua_rawset(L,-4); + }; + +}; + +/* Map inheritance + * It sets 'name' as derived from 'base' by setting 'base' as metatable of 'name' +*/ +static void mapinheritance (lua_State* L, const char* name, const char* base) +{ + /* set metatable inheritance */ + luaL_getmetatable(L,name); + + if (base && *base) + luaL_getmetatable(L,base); + else { + + if (lua_getmetatable(L, -1)) { /* already has a mt, we don't overwrite it */ + lua_pop(L, 2); + return; + }; + luaL_getmetatable(L,"tolua_commonclass"); + }; + + set_ubox(L); + + lua_setmetatable(L,-2); + lua_pop(L,1); +} + +/* Object type +*/ +static int tolua_bnd_type (lua_State* L) +{ + tolua_typename(L,lua_gettop(L)); + return 1; +} + +/* Take ownership +*/ +static int tolua_bnd_takeownership (lua_State* L) +{ + int success = 0; + if (lua_isuserdata(L,1)) + { + if (lua_getmetatable(L,1)) /* if metatable? */ + { + lua_pop(L,1); /* clear metatable off stack */ + /* force garbage collection to avoid C to reuse a to-be-collected address */ + #ifdef LUA_VERSION_NUM + lua_gc(L, LUA_GCCOLLECT, 0); + #else + lua_setgcthreshold(L,0); + #endif + + success = tolua_register_gc(L,1); + } + } + lua_pushboolean(L,success!=0); + return 1; +} + +/* Release ownership +*/ +static int tolua_bnd_releaseownership (lua_State* L) +{ + int done = 0; + if (lua_isuserdata(L,1)) + { + void* u = *((void**)lua_touserdata(L,1)); + /* force garbage collection to avoid releasing a to-be-collected address */ + #ifdef LUA_VERSION_NUM + lua_gc(L, LUA_GCCOLLECT, 0); + #else + lua_setgcthreshold(L,0); + #endif + lua_pushstring(L,"tolua_gc"); + lua_rawget(L,LUA_REGISTRYINDEX); + lua_pushlightuserdata(L,u); + lua_rawget(L,-2); + lua_getmetatable(L,1); + if (lua_rawequal(L,-1,-2)) /* check that we are releasing the correct type */ + { + lua_pushlightuserdata(L,u); + lua_pushnil(L); + lua_rawset(L,-5); + done = 1; + } + } + lua_pushboolean(L,done!=0); + return 1; +} + +/* Type casting +*/ +static int tolua_bnd_cast (lua_State* L) +{ + +/* // old code + void* v = tolua_tousertype(L,1,NULL); + const char* s = tolua_tostring(L,2,NULL); + if (v && s) + tolua_pushusertype(L,v,s); + else + lua_pushnil(L); + return 1; +*/ + + void* v; + const char* s; + if (lua_islightuserdata(L, 1)) { + v = tolua_touserdata(L, 1, NULL); + } else { + v = tolua_tousertype(L, 1, 0); + }; + + s = tolua_tostring(L,2,NULL); + if (v && s) + tolua_pushusertype(L,v,s); + else + lua_pushnil(L); + return 1; +} + +/* Inheritance +*/ +static int tolua_bnd_inherit (lua_State* L) { + + /* stack: lua object, c object */ + lua_pushstring(L, ".c_instance"); + lua_pushvalue(L, -2); + lua_rawset(L, -4); + /* l_obj[".c_instance"] = c_obj */ + + return 0; +}; + +#ifdef LUA_VERSION_NUM /* lua 5.1 */ +static int tolua_bnd_setpeer(lua_State* L) { + + /* stack: userdata, table */ + if (!lua_isuserdata(L, -2)) { + lua_pushstring(L, "Invalid argument #1 to setpeer: userdata expected."); + lua_error(L); + }; + + if (lua_isnil(L, -1)) { + + lua_pop(L, 1); + lua_pushvalue(L, TOLUA_NOPEER); + }; + lua_setfenv(L, -2); + + return 0; +}; + +static int tolua_bnd_getpeer(lua_State* L) { + + /* stack: userdata */ + lua_getfenv(L, -1); + if (lua_rawequal(L, -1, TOLUA_NOPEER)) { + lua_pop(L, 1); + lua_pushnil(L); + }; + return 1; +}; +#endif + +/* static int class_gc_event (lua_State* L); */ + +TOLUA_API void tolua_open (lua_State* L) +{ + int top = lua_gettop(L); + lua_pushstring(L,"tolua_opened"); + lua_rawget(L,LUA_REGISTRYINDEX); + if (!lua_isboolean(L,-1)) + { + lua_pushstring(L,"tolua_opened"); lua_pushboolean(L,1); lua_rawset(L,LUA_REGISTRYINDEX); + + #ifndef LUA_VERSION_NUM /* only prior to lua 5.1 */ + /* create peer object table */ + lua_pushstring(L, "tolua_peers"); lua_newtable(L); + /* make weak key metatable for peers indexed by userdata object */ + lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "k"); lua_rawset(L, -3); /* stack: string peers mt */ + lua_setmetatable(L, -2); /* stack: string peers */ + lua_rawset(L,LUA_REGISTRYINDEX); + #endif + + /* create object ptr -> udata mapping table */ + lua_pushstring(L,"tolua_ubox"); lua_newtable(L); + /* make weak value metatable for ubox table to allow userdata to be + garbage-collected */ + lua_newtable(L); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "v"); lua_rawset(L, -3); /* stack: string ubox mt */ + lua_setmetatable(L, -2); /* stack: string ubox */ + lua_rawset(L,LUA_REGISTRYINDEX); + + lua_pushstring(L,"tolua_super"); lua_newtable(L); lua_rawset(L,LUA_REGISTRYINDEX); + lua_pushstring(L,"tolua_gc"); lua_newtable(L);lua_rawset(L,LUA_REGISTRYINDEX); + + /* create gc_event closure */ + lua_pushstring(L, "tolua_gc_event"); + lua_pushstring(L, "tolua_gc"); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushstring(L, "tolua_super"); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushcclosure(L, class_gc_event, 2); + lua_rawset(L, LUA_REGISTRYINDEX); + + tolua_newmetatable(L,"tolua_commonclass"); + + tolua_module(L,NULL,0); + tolua_beginmodule(L,NULL); + tolua_module(L,"tolua",0); + tolua_beginmodule(L,"tolua"); + tolua_function(L,"type",tolua_bnd_type); + tolua_function(L,"takeownership",tolua_bnd_takeownership); + tolua_function(L,"releaseownership",tolua_bnd_releaseownership); + tolua_function(L,"cast",tolua_bnd_cast); + tolua_function(L,"inherit", tolua_bnd_inherit); + #ifdef LUA_VERSION_NUM /* lua 5.1 */ + tolua_function(L, "setpeer", tolua_bnd_setpeer); + tolua_function(L, "getpeer", tolua_bnd_getpeer); + #endif + + tolua_endmodule(L); + tolua_endmodule(L); + } + lua_settop(L,top); +} + +/* Copy a C object +*/ +TOLUA_API void* tolua_copy (lua_State* L, void* value, unsigned int size) +{ + void* clone = (void*)malloc(size); + if (clone) + memcpy(clone,value,size); + else + tolua_error(L,"insuficient memory",NULL); + return clone; +} + +/* Default collect function +*/ +TOLUA_API int tolua_default_collect (lua_State* tolua_S) +{ + void* self = tolua_tousertype(tolua_S,1,0); + free(self); + return 0; +} + +/* Do clone +*/ +TOLUA_API int tolua_register_gc (lua_State* L, int lo) +{ + int success = 1; + void *value = *(void **)lua_touserdata(L,lo); + lua_pushstring(L,"tolua_gc"); + lua_rawget(L,LUA_REGISTRYINDEX); + lua_pushlightuserdata(L,value); + lua_rawget(L,-2); + if (!lua_isnil(L,-1)) /* make sure that object is not already owned */ + success = 0; + else + { + lua_pushlightuserdata(L,value); + lua_getmetatable(L,lo); + lua_rawset(L,-4); + } + lua_pop(L,2); + return success; +} + +/* Register a usertype + * It creates the correspoding metatable in the registry, for both 'type' and 'const type'. + * It maps 'const type' as being also a 'type' +*/ +TOLUA_API void tolua_usertype (lua_State* L, const char* type) +{ + char ctype[128] = "const "; + strncat(ctype,type,120); + + /* create both metatables */ + if (tolua_newmetatable(L,ctype) && tolua_newmetatable(L,type)) + mapsuper(L,type,ctype); /* 'type' is also a 'const type' */ +} + + +/* Begin module + * It pushes the module (or class) table on the stack +*/ +TOLUA_API void tolua_beginmodule (lua_State* L, const char* name) +{ + if (name) + { + lua_pushstring(L,name); + lua_rawget(L,-2); + } + else + lua_pushvalue(L,LUA_GLOBALSINDEX); +} + +/* End module + * It pops the module (or class) from the stack +*/ +TOLUA_API void tolua_endmodule (lua_State* L) +{ + lua_pop(L,1); +} + +/* Map module + * It creates a new module +*/ +#if 1 +TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar) +{ + if (name) + { + /* tolua module */ + lua_pushstring(L,name); + lua_rawget(L,-2); + if (!lua_istable(L,-1)) /* check if module already exists */ + { + lua_pop(L,1); + lua_newtable(L); + lua_pushstring(L,name); + lua_pushvalue(L,-2); + lua_rawset(L,-4); /* assing module into module */ + } + } + else + { + /* global table */ + lua_pushvalue(L,LUA_GLOBALSINDEX); + } + if (hasvar) + { + if (!tolua_ismodulemetatable(L)) /* check if it already has a module metatable */ + { + /* create metatable to get/set C/C++ variable */ + lua_newtable(L); + tolua_moduleevents(L); + if (lua_getmetatable(L,-2)) + lua_setmetatable(L,-2); /* set old metatable as metatable of metatable */ + lua_setmetatable(L,-2); + } + } + lua_pop(L,1); /* pop module */ +} +#else +TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar) +{ + if (name) + { + /* tolua module */ + lua_pushstring(L,name); + lua_newtable(L); + } + else + { + /* global table */ + lua_pushvalue(L,LUA_GLOBALSINDEX); + } + if (hasvar) + { + /* create metatable to get/set C/C++ variable */ + lua_newtable(L); + tolua_moduleevents(L); + if (lua_getmetatable(L,-2)) + lua_setmetatable(L,-2); /* set old metatable as metatable of metatable */ + lua_setmetatable(L,-2); + } + if (name) + lua_rawset(L,-3); /* assing module into module */ + else + lua_pop(L,1); /* pop global table */ +} +#endif + +static void push_collector(lua_State* L, const char* type, lua_CFunction col) { + + /* push collector function, but only if it's not NULL, or if there's no + collector already */ + if (!col) return; + luaL_getmetatable(L,type); + lua_pushstring(L,".collector"); + /* + if (!col) { + lua_pushvalue(L, -1); + lua_rawget(L, -3); + if (!lua_isnil(L, -1)) { + lua_pop(L, 3); + return; + }; + lua_pop(L, 1); + }; + // */ + lua_pushcfunction(L,col); + + lua_rawset(L,-3); + lua_pop(L, 1); +}; + +/* Map C class + * It maps a C class, setting the appropriate inheritance and super classes. +*/ +TOLUA_API void tolua_cclass (lua_State* L, const char* lname, const char* name, const char* base, lua_CFunction col) +{ + char cname[128] = "const "; + char cbase[128] = "const "; + strncat(cname,name,120); + strncat(cbase,base,120); + + mapinheritance(L,name,base); + mapinheritance(L,cname,name); + + mapsuper(L,cname,cbase); + mapsuper(L,name,base); + + lua_pushstring(L,lname); + + push_collector(L, name, col); + /* + luaL_getmetatable(L,name); + lua_pushstring(L,".collector"); + lua_pushcfunction(L,col); + + lua_rawset(L,-3); + */ + + luaL_getmetatable(L,name); + lua_rawset(L,-3); /* assign class metatable to module */ + + /* now we also need to store the collector table for the const + instances of the class */ + push_collector(L, cname, col); + /* + luaL_getmetatable(L,cname); + lua_pushstring(L,".collector"); + lua_pushcfunction(L,col); + lua_rawset(L,-3); + lua_pop(L,1); + */ + + +} + +/* Add base + * It adds additional base classes to a class (for multiple inheritance) + * (not for now) + */ +TOLUA_API void tolua_addbase(lua_State* L, char* name, char* base) { + + char cname[128] = "const "; + char cbase[128] = "const "; + strncat(cname,name,120); + strncat(cbase,base,120); + + mapsuper(L,cname,cbase); + mapsuper(L,name,base); +}; + + +/* Map function + * It assigns a function into the current module (or class) +*/ +TOLUA_API void tolua_function (lua_State* L, const char* name, lua_CFunction func) +{ + lua_pushstring(L,name); + lua_pushcfunction(L,func); + lua_rawset(L,-3); +} + +/* sets the __call event for the class (expects the class' main table on top) */ +/* never really worked :( +TOLUA_API void tolua_set_call_event(lua_State* L, lua_CFunction func, char* type) { + + lua_getmetatable(L, -1); + //luaL_getmetatable(L, type); + lua_pushstring(L,"__call"); + lua_pushcfunction(L,func); + lua_rawset(L,-3); + lua_pop(L, 1); +}; +*/ + +/* Map constant number + * It assigns a constant number into the current module (or class) +*/ +TOLUA_API void tolua_constant (lua_State* L, const char* name, lua_Number value) +{ + lua_pushstring(L,name); + tolua_pushnumber(L,value); + lua_rawset(L,-3); +} + + +/* Map variable + * It assigns a variable into the current module (or class) +*/ +TOLUA_API void tolua_variable (lua_State* L, const char* name, lua_CFunction get, lua_CFunction set) +{ + /* get func */ + lua_pushstring(L,".get"); + lua_rawget(L,-2); + if (!lua_istable(L,-1)) + { + /* create .get table, leaving it at the top */ + lua_pop(L,1); + lua_newtable(L); + lua_pushstring(L,".get"); + lua_pushvalue(L,-2); + lua_rawset(L,-4); + } + lua_pushstring(L,name); + lua_pushcfunction(L,get); + lua_rawset(L,-3); /* store variable */ + lua_pop(L,1); /* pop .get table */ + + /* set func */ + if (set) + { + lua_pushstring(L,".set"); + lua_rawget(L,-2); + if (!lua_istable(L,-1)) + { + /* create .set table, leaving it at the top */ + lua_pop(L,1); + lua_newtable(L); + lua_pushstring(L,".set"); + lua_pushvalue(L,-2); + lua_rawset(L,-4); + } + lua_pushstring(L,name); + lua_pushcfunction(L,set); + lua_rawset(L,-3); /* store variable */ + lua_pop(L,1); /* pop .set table */ + } +} + +/* Access const array + * It reports an error when trying to write into a const array +*/ +static int const_array (lua_State* L) +{ + luaL_error(L,"value of const array cannot be changed"); + return 0; +} + +/* Map an array + * It assigns an array into the current module (or class) +*/ +TOLUA_API void tolua_array (lua_State* L, const char* name, lua_CFunction get, lua_CFunction set) +{ + lua_pushstring(L,".get"); + lua_rawget(L,-2); + if (!lua_istable(L,-1)) + { + /* create .get table, leaving it at the top */ + lua_pop(L,1); + lua_newtable(L); + lua_pushstring(L,".get"); + lua_pushvalue(L,-2); + lua_rawset(L,-4); + } + lua_pushstring(L,name); + + lua_newtable(L); /* create array metatable */ + lua_pushvalue(L,-1); + lua_setmetatable(L,-2); /* set the own table as metatable (for modules) */ + lua_pushstring(L,"__index"); + lua_pushcfunction(L,get); + lua_rawset(L,-3); + lua_pushstring(L,"__newindex"); + lua_pushcfunction(L,set?set:const_array); + lua_rawset(L,-3); + + lua_rawset(L,-3); /* store variable */ + lua_pop(L,1); /* pop .get table */ +} + + +TOLUA_API void tolua_dobuffer(lua_State* L, char* B, unsigned int size, const char* name) { + + #ifdef LUA_VERSION_NUM /* lua 5.1 */ + luaL_loadbuffer(L, B, size, name) || lua_pcall(L, 0, 0, 0); + #else + lua_dobuffer(L, B, size, name); + #endif +}; + diff --git a/lua/tolua/tolua_push.c b/lua/tolua/tolua_push.c new file mode 100644 index 0000000000..6394147555 --- /dev/null +++ b/lua/tolua/tolua_push.c @@ -0,0 +1,171 @@ +/* tolua: functions to push C values. +** Support code for Lua bindings. +** Written by Waldemar Celes +** TeCGraf/PUC-Rio +** Apr 2003 +** $Id: $ +*/ + +/* This code is free software; you can redistribute it and/or modify it. +** The software provided hereunder is on an "as is" basis, and +** the author has no obligation to provide maintenance, support, updates, +** enhancements, or modifications. +*/ + +#include "tolua++.h" +#include "lauxlib.h" + +#include + +TOLUA_API void tolua_pushvalue (lua_State* L, int lo) +{ + lua_pushvalue(L,lo); +} + +TOLUA_API void tolua_pushboolean (lua_State* L, int value) +{ + lua_pushboolean(L,value); +} + +TOLUA_API void tolua_pushnumber (lua_State* L, lua_Number value) +{ + lua_pushnumber(L,value); +} + +TOLUA_API void tolua_pushstring (lua_State* L, const char* value) +{ + if (value == NULL) + lua_pushnil(L); + else + lua_pushstring(L,value); +} + +TOLUA_API void tolua_pushuserdata (lua_State* L, void* value) +{ + if (value == NULL) + lua_pushnil(L); + else + lua_pushlightuserdata(L,value); +} + +TOLUA_API void tolua_pushusertype (lua_State* L, void* value, const char* type) +{ + if (value == NULL) + lua_pushnil(L); + else + { + luaL_getmetatable(L, type); + lua_pushstring(L,"tolua_ubox"); + lua_rawget(L,-2); /* stack: mt ubox */ + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + lua_pushstring(L, "tolua_ubox"); + lua_rawget(L, LUA_REGISTRYINDEX); + }; + lua_pushlightuserdata(L,value); + lua_rawget(L,-2); /* stack: mt ubox ubox[u] */ + if (lua_isnil(L,-1)) + { + lua_pop(L,1); /* stack: mt ubox */ + lua_pushlightuserdata(L,value); + *(void**)lua_newuserdata(L,sizeof(void *)) = value; /* stack: mt ubox u newud */ + lua_pushvalue(L,-1); /* stack: mt ubox u newud newud */ + lua_insert(L,-4); /* stack: mt newud ubox u newud */ + lua_rawset(L,-3); /* stack: mt newud ubox */ + lua_pop(L,1); /* stack: mt newud */ + /*luaL_getmetatable(L,type);*/ + lua_pushvalue(L, -2); /* stack: mt newud mt */ + lua_setmetatable(L,-2); /* stack: mt newud */ + + #ifdef LUA_VERSION_NUM + lua_pushvalue(L, TOLUA_NOPEER); + lua_setfenv(L, -2); + #endif + } + else + { + /* check the need of updating the metatable to a more specialized class */ + lua_insert(L,-2); /* stack: mt ubox[u] ubox */ + lua_pop(L,1); /* stack: mt ubox[u] */ + lua_pushstring(L,"tolua_super"); + lua_rawget(L,LUA_REGISTRYINDEX); /* stack: mt ubox[u] super */ + lua_getmetatable(L,-2); /* stack: mt ubox[u] super mt */ + lua_rawget(L,-2); /* stack: mt ubox[u] super super[mt] */ + if (lua_istable(L,-1)) + { + lua_pushstring(L,type); /* stack: mt ubox[u] super super[mt] type */ + lua_rawget(L,-2); /* stack: mt ubox[u] super super[mt] flag */ + if (lua_toboolean(L,-1) == 1) /* if true */ + { + lua_pop(L,3); /* mt ubox[u]*/ + lua_remove(L, -2); + return; + } + } + /* type represents a more specilized type */ + /*luaL_getmetatable(L,type); // stack: mt ubox[u] super super[mt] flag mt */ + lua_pushvalue(L, -5); /* stack: mt ubox[u] super super[mt] flag mt */ + lua_setmetatable(L,-5); /* stack: mt ubox[u] super super[mt] flag */ + lua_pop(L,3); /* stack: mt ubox[u] */ + } + lua_remove(L, -2); /* stack: ubox[u]*/ + } +} + +TOLUA_API void tolua_pushusertype_and_takeownership (lua_State* L, void* value, const char* type) +{ + tolua_pushusertype(L,value,type); + tolua_register_gc(L,lua_gettop(L)); +} + +TOLUA_API void tolua_pushfieldvalue (lua_State* L, int lo, int index, int v) +{ + lua_pushnumber(L,index); + lua_pushvalue(L,v); + lua_settable(L,lo); +} + +TOLUA_API void tolua_pushfieldboolean (lua_State* L, int lo, int index, int v) +{ + lua_pushnumber(L,index); + lua_pushboolean(L,v); + lua_settable(L,lo); +} + + +TOLUA_API void tolua_pushfieldnumber (lua_State* L, int lo, int index, lua_Number v) +{ + lua_pushnumber(L,index); + tolua_pushnumber(L,v); + lua_settable(L,lo); +} + +TOLUA_API void tolua_pushfieldstring (lua_State* L, int lo, int index, const char* v) +{ + lua_pushnumber(L,index); + tolua_pushstring(L,v); + lua_settable(L,lo); +} + +TOLUA_API void tolua_pushfielduserdata (lua_State* L, int lo, int index, void* v) +{ + lua_pushnumber(L,index); + tolua_pushuserdata(L,v); + lua_settable(L,lo); +} + +TOLUA_API void tolua_pushfieldusertype (lua_State* L, int lo, int index, void* v, const char* type) +{ + lua_pushnumber(L,index); + tolua_pushusertype(L,v,type); + lua_settable(L,lo); +} + +TOLUA_API void tolua_pushfieldusertype_and_takeownership (lua_State* L, int lo, int index, void* v, const char* type) +{ + lua_pushnumber(L,index); + tolua_pushusertype(L,v,type); + tolua_register_gc(L,lua_gettop(L)); + lua_settable(L,lo); +} + diff --git a/lua/tolua/tolua_to.c b/lua/tolua/tolua_to.c new file mode 100644 index 0000000000..542ca67d16 --- /dev/null +++ b/lua/tolua/tolua_to.c @@ -0,0 +1,133 @@ +/* tolua: funcitons to convert to C types +** Support code for Lua bindings. +** Written by Waldemar Celes +** TeCGraf/PUC-Rio +** Apr 2003 +** $Id: $ +*/ + +/* This code is free software; you can redistribute it and/or modify it. +** The software provided hereunder is on an "as is" basis, and +** the author has no obligation to provide maintenance, support, updates, +** enhancements, or modifications. +*/ + +#include "tolua++.h" + +#include +#include + +TOLUA_API lua_Number tolua_tonumber (lua_State* L, int narg, lua_Number def) +{ + return lua_gettop(L) + { + public: + CCActionInstant(); + + + CCObject* copyWithZone(CCZone *pZone); + bool isDone(void); + void step(ccTime dt); + void update(ccTime time); + CCFiniteTimeAction * reverse(void); + }; + + + class CCShow : public CCActionInstant + { + + CCShow(){} + + virtual void startWithTarget(CCNode *pTarget); + virtual CCFiniteTimeAction * reverse(void); + static CCShow * action(); + }; + + + class CCHide : public CCActionInstant + { + + CCHide(){} + + virtual void startWithTarget(CCNode *pTarget); + virtual CCFiniteTimeAction * reverse(void); + static CCHide * action(); + }; + + + class CCToggleVisibility : public CCActionInstant + { + + CCToggleVisibility(); + virtual void startWithTarget(CCNode *pTarget); + static CCToggleVisibility * action(); + }; + + class CCFlipX : public CCActionInstant + { + + CCFlipX(); + + static CCFlipX * actionWithFlipX(bool x); + + bool initWithFlipX(bool x); + + void startWithTarget(CCNode *pTarget); + CCFiniteTimeAction * reverse(void); + CCObject* copyWithZone(CCZone *pZone); + + + }; + + class CCFlipY : public CCActionInstant + { + public: + CCFlipY(); + static CCFlipY * actionWithFlipY(bool y); + bool initWithFlipY(bool y); + void startWithTarget(CCNode *pTarget); + CCFiniteTimeAction * reverse(void); + CCObject* copyWithZone(CCZone *pZone); + }; + + + class CCPlace : public CCActionInstant // + { + CCPlace(); + static CCPlace * actionWithPosition(CCPoint pos); + bool initWithPosition(CCPoint pos); + void startWithTarget(CCNode *pTarget); + CCObject* copyWithZone(CCZone *pZone); + }; + + /** @brief Calls a 'callback' + */ + class CCCallFunc : public CCActionInstant // + { + CCCallFunc(); + static CCCallFunc * actionWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFunc selector); + bool initWithTarget(SelectorProtocol* pSelectorTarget); + void execute(); + void startWithTarget(CCNode *pTarget); + CCObject * copyWithZone(cocos2d::CCZone *pZone); + + }; + + + class CCCallFuncN : public CCCallFunc + { + CCCallFuncN(); + static CCCallFuncN * actionWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncN selector); + bool initWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncN selector); + CCObject* copyWithZone(CCZone *pZone); + void execute(); + }; + + + + class CCCallFuncND : public CCCallFuncN + { + + /** creates the action with the callback and the data to pass as an argument */ + static CCCallFuncND * actionWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncND selector, void* d); + /** initializes the action with the callback and the data to pass as an argument */ + virtual bool initWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncND selector, void* d); + // super methods + virtual CCObject* copyWithZone(CCZone *pZone); + virtual void execute(); + + }; + + + + class CCCallFuncO : public CCCallFunc + { + + CCCallFuncO(); + + static CCCallFuncO * actionWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncO selector, CCObject* pObject); + + bool initWithTarget(SelectorProtocol* pSelectorTarget, SEL_CallFuncO selector, CCObject* pObject); + + CCObject* copyWithZone(CCZone *pZone); + void execute(); + + }; + +} + diff --git a/tools/tolua++/CCActionInterval.pkg b/tools/tolua++/CCActionInterval.pkg new file mode 100644 index 0000000000..608d57fdff --- /dev/null +++ b/tools/tolua++/CCActionInterval.pkg @@ -0,0 +1,346 @@ + +#include "CCNode.h" +#include "CCAction.h" +#include "CCProtocols.h" +#include "CCSpriteFrame.h" +#include "CCAnimation.h" + +namespace cocos2d { + + class CCActionInterval : public CCFiniteTimeAction + { + + ccTime getElapsed(void); + bool initWithDuration(ccTime d); + bool isDone(void); + CCObject* copyWithZone(CCZone* pZone); + void step(ccTime dt); + void startWithTarget(CCNode *pTarget); + CCActionInterval* reverse(void); + static CCActionInterval* actionWithDuration(ccTime d); + void setAmplitudeRate(CGFloat amp); + CGFloat getAmplitudeRate(void); + }; + + class CCSequence : public CCActionInterval + { + + + bool initOneTwo(CCFiniteTimeAction *pActionOne, CCFiniteTimeAction *pActionTwo); + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void stop(void); + void update(ccTime time); + CCActionInterval* reverse(void); + // static CCFiniteTimeAction* actions(CCFiniteTimeAction *pAction1, ...); + //ÓÃÒÔÏ·½·¨Ìæ´ú + static CCSequence* actionOneTwo(CCFiniteTimeAction *pActionOne, CCFiniteTimeAction *pActionTwo); + }; + + + class CCRepeat : public CCActionInterval + { + + + + bool initWithAction(CCFiniteTimeAction *pAction, unsigned int times); + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void stop(void); + void update(ccTime time); + bool isDone(void); + CCActionInterval* reverse(void); + + static CCRepeat* actionWithAction(CCFiniteTimeAction *pAction, unsigned int times); + + }; + + + class CCRepeatForever : public CCActionInterval + { + + CCRepeatForever(); + + bool initWithAction(CCActionInterval *pAction); + CCObject* copyWithZone(CCZone *pZone); + void startWithTarget(CCNode* pTarget); + void step(ccTime dt); + bool isDone(void); + CCActionInterval* reverse(void); + static CCRepeatForever* actionWithAction(CCActionInterval *pAction); + + }; + + /** @brief Spawn a new action immediately + */ + class CCSpawn : public CCActionInterval + { + bool initOneTwo(CCFiniteTimeAction *pAction1, CCFiniteTimeAction *pAction2); + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void stop(void); + void update(ccTime time); + CCActionInterval* reverse(void); + //static CCFiniteTimeAction* actions(CCFiniteTimeAction *pAction1, ...); + //ÓÃÒÔÏ·½·¨Ìæ´ú + static CCSpawn* actionOneTwo(CCFiniteTimeAction *pAction1, CCFiniteTimeAction *pAction2); + + }; + + class CCRotateTo : public CCActionInterval + { + + bool initWithDuration(ccTime duration, float fDeltaAngle); + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void update(ccTime time); + static CCRotateTo* actionWithDuration(ccTime duration, float fDeltaAngle); + }; + + /** @brief Rotates a CCNode object clockwise a number of degrees by modifying it's rotation attribute. + */ + class CCRotateBy : public CCActionInterval + { + + bool initWithDuration(ccTime duration, float fDeltaAngle); + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void update(ccTime time); + CCActionInterval* reverse(void); + static CCRotateBy* actionWithDuration(ccTime duration, float fDeltaAngle); + + }; + + /** @brief Moves a CCNode object to the position x,y. x and y are absolute coordinates by modifying it's position attribute. + */ + class CCMoveTo : public CCActionInterval + { + + bool initWithDuration(ccTime duration, CCPoint position); + + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void update(ccTime time); + + static CCMoveTo* actionWithDuration(ccTime duration, CCPoint position); + + }; + + + class CCMoveBy : public CCMoveTo + { + + bool initWithDuration(ccTime duration, CCPoint position); + + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + CCActionInterval* reverse(void); + static CCMoveBy* actionWithDuration(ccTime duration, CCPoint position); + }; + + class CCJumpBy : public CCActionInterval + { + + bool initWithDuration(ccTime duration, CCPoint position, ccTime height, int jumps); + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void update(ccTime time); + CCActionInterval* reverse(void); + static CCJumpBy* actionWithDuration(ccTime duration, CCPoint position, ccTime height, int jumps); + }; + + + class CCJumpTo : public CCJumpBy + { + public: + void startWithTarget(CCNode *pTarget); + CCObject* copyWithZone(CCZone* pZone); + static CCJumpTo* actionWithDuration(ccTime duration, CCPoint position, ccTime height, int jumps); + }; + + typedef struct _ccBezierConfig { + //! end position of the bezier + CCPoint endPosition; + //! Bezier control point 1 + CCPoint controlPoint_1; + //! Bezier control point 2 + CCPoint controlPoint_2; + } ccBezierConfig; + + + class CCBezierBy : public CCActionInterval + { + + bool initWithDuration(ccTime t, ccBezierConfig c); + virtual CCObject* copyWithZone(CCZone* pZone); + virtual void startWithTarget(CCNode *pTarget); + virtual void update(ccTime time); + virtual CCActionInterval* reverse(void); + + + static CCBezierBy* actionWithDuration(ccTime t, ccBezierConfig c); + + }; + + + class CCBezierTo : public CCBezierBy + { + public: + virtual void startWithTarget(CCNode *pTarget); + virtual CCObject* copyWithZone(CCZone* pZone); + static CCBezierTo* actionWithDuration(ccTime t, ccBezierConfig c); + }; + + + class CCScaleTo : public CCActionInterval + { + + bool initWithDuration(ccTime duration, float s); + bool initWithDuration(ccTime duration, float sx, float sy); + + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void update(ccTime time); + static CCScaleTo* actionWithDuration(ccTime duration, float s); + static CCScaleTo* actionWithDuration(ccTime duration, float sx, float sy); + }; + + + class CCScaleBy : public CCScaleTo + { + + virtual void startWithTarget(CCNode *pTarget); + virtual CCActionInterval* reverse(void); + virtual CCObject* copyWithZone(CCZone* pZone); + + static CCScaleBy* actionWithDuration(ccTime duration, float s); + static CCScaleBy* actionWithDuration(ccTime duration, float sx, float sy); + }; + + + class CCBlink : public CCActionInterval + { + + bool initWithDuration(ccTime duration, unsigned int uBlinks); + + virtual CCObject* copyWithZone(CCZone* pZone); + virtual void update(ccTime time); + virtual CCActionInterval* reverse(void); + static CCBlink* actionWithDuration(ccTime duration, unsigned int uBlinks); + + }; + + class CCFadeIn : public CCActionInterval + { + + virtual void update(ccTime time); + virtual CCActionInterval* reverse(void); + virtual CCObject* copyWithZone(CCZone* pZone); + static CCFadeIn* actionWithDuration(ccTime d); + }; + + class CCFadeOut : public CCActionInterval + { + + virtual void update(ccTime time); + virtual CCActionInterval* reverse(void); + virtual CCObject* copyWithZone(CCZone* pZone); + static CCFadeOut* actionWithDuration(ccTime d); + }; + + + class CCFadeTo : public CCActionInterval + { + + bool initWithDuration(ccTime duration, GLubyte opacity); + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void update(ccTime time); + static CCFadeTo* actionWithDuration(ccTime duration, GLubyte opacity); + }; + + + class CCTintTo : public CCActionInterval + { + bool initWithDuration(ccTime duration, GLubyte red, GLubyte green, GLubyte blue); + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void update(ccTime time); + static CCTintTo* actionWithDuration(ccTime duration, GLubyte red, GLubyte green, GLubyte blue); + }; + + class CCTintBy : public CCActionInterval + { + + bool initWithDuration(ccTime duration, GLshort deltaRed, GLshort deltaGreen, GLshort deltaBlue); + + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void update(ccTime time); + CCActionInterval* reverse(void); + + static CCTintBy* actionWithDuration(ccTime duration, GLshort deltaRed, GLshort deltaGreen, GLshort deltaBlue); + + }; + + /** @brief Delays the action a certain amount of seconds + */ + class CCDelayTime : public CCActionInterval + { + + void update(ccTime time); + CCActionInterval* reverse(void); + CCObject* copyWithZone(CCZone* pZone); + static CCDelayTime* actionWithDuration(ccTime d); + }; + + + class CCReverseTime : public CCActionInterval + { + + + + bool initWithAction(CCFiniteTimeAction *pAction); + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void stop(void); + void update(ccTime time); + CCActionInterval* reverse(void); + + static CCReverseTime* actionWithAction(CCFiniteTimeAction *pAction); + + }; + + class CCTexture2D; + + class CCAnimate : public CCActionInterval + { + + + + CCAnimation* getAnimation(void); + void setAnimation(CCAnimation *pAnimation); + bool initWithAnimation(CCAnimation *pAnimation); + bool initWithAnimation(CCAnimation *pAnimation, bool bRestoreOriginalFrame); + + + bool initWithDuration(ccTime duration, CCAnimation *pAnimation, bool bRestoreOriginalFrame); + + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void stop(void); + void update(ccTime time); + CCActionInterval* reverse(void); + + + static CCAnimate* actionWithAnimation(CCAnimation *pAnimation); + + static CCAnimate* actionWithAnimation(CCAnimation *pAnimation, bool bRestoreOriginalFrame); + + + static CCAnimate* actionWithDuration(ccTime duration, CCAnimation *pAnimation, bool bRestoreOriginalFrame); + + }; + +} + diff --git a/tools/tolua++/CCActionManager.pkg b/tools/tolua++/CCActionManager.pkg new file mode 100644 index 0000000000..a87b1dc6ad --- /dev/null +++ b/tools/tolua++/CCActionManager.pkg @@ -0,0 +1,36 @@ + +#include "CCAction.h" +#include "CCMutableArray.h" +#include "CCObject.h" +#include "selector_protocol.h" + +namespace cocos2d { + +struct _hashElement; + +class CCActionManager : public CCObject, public SelectorProtocol +{ +public: + CCActionManager(void); + bool init(void); + void addAction(CCAction *pAction, CCNode *pTarget, bool paused); + void removeAllActions(void); + void removeAllActionsFromTarget(CCObject *pTarget); + void removeAction(CCAction *pAction); + void removeActionByTag(int tag, CCObject *pTarget); + CCAction* getActionByTag(int tag, CCObject *pTarget); + int numberOfRunningActionsInTarget(CCObject *pTarget); + void pauseTarget(CCObject *pTarget); + void resumeTarget(CCObject *pTarget); + void resumeAllActionsForTarget(CCObject *pTarget); + void pauseAllActionsForTarget(CCObject *pTarget); + void purgeSharedManager(void); + void selectorProtocolRetain(void); + void selectorProtocolRelease(void); + static CCActionManager* sharedManager(void); + +}; + +} + + diff --git a/tools/tolua++/CCActionPageTurn3D.pkg b/tools/tolua++/CCActionPageTurn3D.pkg new file mode 100644 index 0000000000..d1039f91ca --- /dev/null +++ b/tools/tolua++/CCActionPageTurn3D.pkg @@ -0,0 +1,13 @@ + +#include "CCActionGrid3D.h" + +namespace cocos2d +{ + + class CCPageTurn3D : public CCGrid3DAction + { + void update(ccTime time); + static CCPageTurn3D* actionWithSize(ccGridSize gridSize, ccTime time); + }; +} + diff --git a/tools/tolua++/CCActionProgressTimer.pkg b/tools/tolua++/CCActionProgressTimer.pkg new file mode 100644 index 0000000000..8be7422691 --- /dev/null +++ b/tools/tolua++/CCActionProgressTimer.pkg @@ -0,0 +1,32 @@ + +#include "CCActionInterval.h" + +namespace cocos2d +{ + class CCProgressTo : public CCActionInterval + { + public: + + bool initWithDuration(ccTime duration, float fPercent); + + CCObject* copyWithZone(CCZone *pZone); + void startWithTarget(CCNode *pTarget); + void update(ccTime time); + static CCProgressTo* actionWithDuration(ccTime duration, float fPercent); + }; + + + class CCProgressFromTo : public CCActionInterval + { + + bool initWithDuration(ccTime duration, float fFromPercentage, float fToPercentage); + virtual CCObject* copyWithZone(CCZone *pZone); + virtual CCActionInterval* reverse(void); + virtual void startWithTarget(CCNode *pTarget); + virtual void update(ccTime time); + static CCProgressFromTo* actionWithDuration(ccTime duration, float fFromPercentage, float fToPercentage); + + }; + +} // end of namespace cocos2d + diff --git a/tools/tolua++/CCActionTiledGrid.pkg b/tools/tolua++/CCActionTiledGrid.pkg new file mode 100644 index 0000000000..f287e09461 --- /dev/null +++ b/tools/tolua++/CCActionTiledGrid.pkg @@ -0,0 +1,160 @@ + +#include "CCActionGrid.h" + +namespace cocos2d +{ + + class CCShakyTiles3D : public CCTiledGrid3DAction + { + bool initWithRange(int nRange, bool bShakeZ, ccGridSize gridSize,ccTime duration); + + CCObject* copyWithZone(CCZone* pZone); + void update(ccTime time); + static CCShakyTiles3D* actionWithRange(int nRange, bool bShakeZ, ccGridSize gridSize, + ccTime duration); + + }; + + + class CCShatteredTiles3D : public CCTiledGrid3DAction + { + + bool initWithRange(int nRange, bool bShatterZ, ccGridSize gridSize, ccTime duration); + + CCObject* copyWithZone(CCZone* pZone); + void update(ccTime time); + + + static CCShatteredTiles3D* actionWithRange(int nRange, bool bShatterZ, ccGridSize gridSize, + ccTime duration); + }; + + struct Tile; + + class CCShuffleTiles : public CCTiledGrid3DAction + { + + bool initWithSeed(int s, ccGridSize gridSize, ccTime duration); + void shuffle(int *pArray, int nLen); + ccGridSize getDelta(ccGridSize pos); + void placeTile(ccGridSize pos, Tile *t); + + virtual void startWithTarget(CCNode *pTarget); + virtual void update(ccTime time); + virtual CCObject* copyWithZone(CCZone* pZone); + static CCShuffleTiles* actionWithSeed(int s, ccGridSize gridSize, ccTime duration); + }; + + + class CCFadeOutTRTiles : public CCTiledGrid3DAction + { + + float testFunc(ccGridSize pos, ccTime time); + void turnOnTile(ccGridSize pos); + void turnOffTile(ccGridSize pos); + virtual void transformTile(ccGridSize pos, float distance); + virtual void update(ccTime time); + static CCFadeOutTRTiles* actionWithSize(ccGridSize gridSize, ccTime time); + }; + + + class CCFadeOutBLTiles : public CCFadeOutTRTiles + { + + float testFunc(ccGridSize pos, ccTime time); + static CCFadeOutBLTiles* actionWithSize(ccGridSize gridSize, ccTime time); + }; + + + class CCFadeOutUpTiles : public CCFadeOutTRTiles + { + + float testFunc(ccGridSize pos, ccTime time); + virtual void transformTile(ccGridSize pos, float distance); + static CCFadeOutUpTiles* actionWithSize(ccGridSize gridSize, ccTime time); + }; + + + class CCFadeOutDownTiles : public CCFadeOutUpTiles + { + + virtual float testFunc(ccGridSize pos, ccTime time); + static CCFadeOutDownTiles* actionWithSize(ccGridSize gridSize, ccTime time); + }; + + + class CCTurnOffTiles : public CCTiledGrid3DAction + { + + bool initWithSeed(int s, ccGridSize gridSize, ccTime duration); + void shuffle(int *pArray, int nLen); + void turnOnTile(ccGridSize pos); + void turnOffTile(ccGridSize pos); + + CCObject* copyWithZone(CCZone* pZone); + void startWithTarget(CCNode *pTarget); + void update(ccTime time); + + static CCTurnOffTiles* actionWithSize(ccGridSize size, ccTime d); + static CCTurnOffTiles* actionWithSeed(int s, ccGridSize gridSize, ccTime duration); + }; + + /** @brief CCWavesTiles3D action. */ + class CCWavesTiles3D : public CCTiledGrid3DAction + { + + float getAmplitude(void); + void setAmplitude(float fAmplitude); + float getAmplitudeRate(void); + void setAmplitudeRate(float fAmplitudeRate); + bool initWithWaves(int wav, float amp, ccGridSize gridSize, ccTime duration); + CCObject* copyWithZone(CCZone* pZone); + void update(ccTime time); + static CCWavesTiles3D* actionWithWaves(int wav, float amp, ccGridSize gridSize, ccTime duration); + + }; + + /** @brief CCJumpTiles3D action. + A sin function is executed to move the tiles across the Z axis + */ + class CCJumpTiles3D : public CCTiledGrid3DAction + { + + float getAmplitude(void); + void setAmplitude(float fAmplitude); + float getAmplitudeRate(void); + void setAmplitudeRate(float fAmplitudeRate); + bool initWithJumps(int j, float amp, ccGridSize gridSize, ccTime duration); + virtual CCObject* copyWithZone(CCZone* pZone); + virtual void update(ccTime time); + static CCJumpTiles3D* actionWithJumps(int j, float amp, ccGridSize gridSize, ccTime duration); + + }; + + /** @brief CCSplitRows action */ + class CCSplitRows : public CCTiledGrid3DAction + { + + bool initWithRows(int nRows, ccTime duration); + CCObject* copyWithZone(CCZone* pZone); + void update(ccTime time); + void startWithTarget(CCNode *pTarget); + static CCSplitRows* actionWithRows(int nRows, ccTime duration); + + }; + + /** @brief CCSplitCols action */ + class CCSplitCols : public CCTiledGrid3DAction + { + + bool initWithCols(int nCols, ccTime duration); + virtual CCObject* copyWithZone(CCZone* pZone); + virtual void update(ccTime time); + virtual void startWithTarget(CCNode *pTarget); + static CCSplitCols* actionWithCols(int nCols, ccTime duration); + + + }; +} // end of namespace cocos2d + + diff --git a/tools/tolua++/CCAffineTransform.pkg b/tools/tolua++/CCAffineTransform.pkg new file mode 100644 index 0000000000..08bab996a3 --- /dev/null +++ b/tools/tolua++/CCAffineTransform.pkg @@ -0,0 +1,30 @@ +namespace cocos2d { + +struct CCAffineTransform { + CGFloat a, b, c, d; + CGFloat tx, ty; +}; +CCAffineTransform __CCAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty); +CCAffineTransform CCAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty); + +CCPoint __CCPointApplyAffineTransform(CCPoint point, CCAffineTransform t); +CCPoint CCPointApplyAffineTransform(CCPoint point, CCAffineTransform t); + + +CCSize CCSizeApplyAffineTransform(CCSize size, CCAffineTransform t); +CCSize __CCSizeApplyAffineTransform(CCSize size, CCAffineTransform t); + +CCAffineTransform CCAffineTransformMakeIdentity(); +CCRect CCRectApplyAffineTransform(CCRect rect, CCAffineTransform anAffineTransform); + +CCAffineTransform CCAffineTransformTranslate(CCAffineTransform t, float tx, float ty); +CCAffineTransform CCAffineTransformRotate(CCAffineTransform aTransform, CGFloat anAngle); +CCAffineTransform CCAffineTransformScale(CCAffineTransform t, CGFloat sx, CGFloat sy); +CCAffineTransform CCAffineTransformConcat(CCAffineTransform t1,CCAffineTransform t2); +bool CCAffineTransformEqualToTransform(CCAffineTransform t1,CCAffineTransform t2); +CCAffineTransform CCAffineTransformInvert(CCAffineTransform t); + +//extern const CCAffineTransform CCAffineTransformIdentity; +}//namespace cocos2d + + diff --git a/tools/tolua++/CCAnimation.pkg b/tools/tolua++/CCAnimation.pkg new file mode 100644 index 0000000000..f08e5f9da0 --- /dev/null +++ b/tools/tolua++/CCAnimation.pkg @@ -0,0 +1,72 @@ + +#include "CCPlatformConfig.h" +#include "CCObject.h" +#include "CCMutableArray.h" +#include "CCGeometry.h" +#include + +namespace cocos2d { + + class CCSpriteFrame; + class CCTexture2D; + + class CCAnimation : public CCObject + { + + + const char* getName(void); + void setName(const char *pszName); + float getDelay(void); + void setDelay(float fDelay); + CCMutableArray* getFrames(void); + void setFrames(CCMutableArray *pFrames); + + + bool initWithFrames(CCMutableArray *pFrames); + + + bool initWithFrames(CCMutableArray *pFrames, float delay); + + + bool initWithName(const char *pszName); + + + bool initWithName(const char *pszName, CCMutableArray *pFrames); + + bool initWithName(const char *pszName, float fDelay); + + + bool initWithName(const char *pszName, float fDelay, CCMutableArray *pFrames); + + + void addFrame(CCSpriteFrame *pFrame); + + void addFrameWithFileName(const char *pszFileName); + + + void addFrameWithTexture(CCTexture2D* pobTexture, CCRect rect); + + bool init(void); + + public: + + static CCAnimation* animation(void); + + static CCAnimation* animationWithFrames(CCMutableArray *frames); + + static CCAnimation* animationWithFrames(CCMutableArray *frames, float delay); + + + static CCAnimation* animationWithName(const char *pszName); + + + static CCAnimation* animationWithName(const char *pszName, CCMutableArray *pFrames); + + /** Creates a CCAnimation with a name and delay between frames. */ + static CCAnimation* animationWithName(const char *pszName, float fDelay); + + /** Creates a CCAnimation with a name, delay and an array of CCSpriteFrames. */ + static CCAnimation* animationWithName(const char *pszName, float fDelay, CCMutableArray *pFrames); + }; +} // end of name sapce cocos2d + diff --git a/tools/tolua++/CCAnimationCache.pkg b/tools/tolua++/CCAnimationCache.pkg new file mode 100644 index 0000000000..7d78d18c92 --- /dev/null +++ b/tools/tolua++/CCAnimationCache.pkg @@ -0,0 +1,32 @@ + +#include "CCObject.h" +#include "CCMutableDictionary.h" + +#include + +namespace cocos2d +{ + class CCAnimation; + + /** Singleton that manages the Animations. + It saves in a cache the animations. You should use this class if you want to save your animations in a cache. + + Before v0.99.5, the recommend way was to save them on the CCSprite. Since v0.99.5, you should use this class instead. + + @since v0.99.5 + */ + class CCAnimationCache : public CCObject + { + + CCAnimationCache(); + static CCAnimationCache* sharedAnimationCache(void); + static void purgeSharedAnimationCache(void); + + void addAnimation(CCAnimation *animation, const char * name); + void removeAnimationByName(const char* name); + CCAnimation* animationByName(const char* name); + + bool init(void); + + }; +} diff --git a/tools/tolua++/CCApplication.pkg b/tools/tolua++/CCApplication.pkg new file mode 100644 index 0000000000..9e193e6388 --- /dev/null +++ b/tools/tolua++/CCApplication.pkg @@ -0,0 +1,3 @@ + +#include "platform/CCApplication_platform.h" + diff --git a/tools/tolua++/CCArray.pkg b/tools/tolua++/CCArray.pkg new file mode 100644 index 0000000000..b6b108c67f --- /dev/null +++ b/tools/tolua++/CCArray.pkg @@ -0,0 +1,46 @@ + +#include "support/data_support/ccCArray.h" + + + +namespace cocos2d +{ + + class CCArray : public CCObject + { + + static CCArray* array(); + static CCArray* arrayWithCapacity(unsigned int capacity); + static CCArray* arrayWithArray(CCArray* otherArray); + + bool init(); + bool initWithCapacity(unsigned int capacity); + bool initWithArray(CCArray* otherArray); + + unsigned int count(); + unsigned int capacity(); + unsigned int indexOfObject(CCObject* object); + CCObject* objectAtIndex(unsigned int index); + CCObject* lastObject(); + CCObject* randomObject(); + bool containsObject(CCObject* object); + + void addObject(CCObject* object); + void addObjectsFromArray(CCArray* otherArray); + void insertObject(CCObject* object, unsigned int index); + + void removeLastObject(); + void removeObject(CCObject* object); + void removeObjectAtIndex(unsigned int index); + void removeObjectsInArray(CCArray* otherArray); + void removeAllObjects(); + void fastRemoveObject(CCObject* object); + void fastRemoveObjectAtIndex(unsigned int index); + + public: + ccArray* data; + }; + +} + + diff --git a/tools/tolua++/CCAtlasNode.pkg b/tools/tolua++/CCAtlasNode.pkg new file mode 100644 index 0000000000..ecd70dfccd --- /dev/null +++ b/tools/tolua++/CCAtlasNode.pkg @@ -0,0 +1,31 @@ + +#include "CCNode.h" +#include "CCProtocols.h" +#include "ccTypes.h" + +namespace cocos2d { + class CCTextureAtlas; + + class CCAtlasNode : public CCNode, public CCRGBAProtocol, public CCTextureProtocol + { + + CCAtlasNode(); + + static CCAtlasNode * atlasWithTileFile(const char* tile,int tileWidth, int tileHeight, int itemsToRender); + + /** initializes an CCAtlasNode with an Atlas file the width and height of each item and the quantity of items to render*/ + bool initWithTileFile(const char* tile, int tileWidth, int tileHeight, int itemsToRender); + + void updateAtlasValues(); + + void draw(); + CCRGBAProtocol* convertToRGBAProtocol(); + CCTexture2D* getTexture(void); + void setTexture(CCTexture2D *texture); + + + }; +}//namespace cocos2d + + + diff --git a/tools/tolua++/CCAutoreleasePool.pkg b/tools/tolua++/CCAutoreleasePool.pkg new file mode 100644 index 0000000000..03cb36053e --- /dev/null +++ b/tools/tolua++/CCAutoreleasePool.pkg @@ -0,0 +1,30 @@ + +#include "CCObject.h" +#include "CCMutableArray.h" + +namespace cocos2d { + class CCAutoreleasePool : public CCObject + { + + CCAutoreleasePool(void); + void addObject(CCObject *pObject); + void removeObject(CCObject *pObject); + void clear(); + }; + + class CCPoolManager + { + + CCPoolManager(); + void finalize(); + void push(); + void pop(); + void removeObject(CCObject* pObject); + void addObject(CCObject* pObject); + static CCPoolManager* getInstance(); + + }; + +} + + diff --git a/tools/tolua++/CCCamera.pkg b/tools/tolua++/CCCamera.pkg new file mode 100644 index 0000000000..1669b937a1 --- /dev/null +++ b/tools/tolua++/CCCamera.pkg @@ -0,0 +1,41 @@ + +#include "CCObject.h" +#include "ccMacros.h" +#include +namespace cocos2d { + + class CCCamera : public CCObject + { + + CCCamera(void); + + void init(void); + char * description(void); + + /** sets the dirty value */ + void setDirty(bool bValue); + bool getDirty(void); + void restore(void); + /** Sets the camera using gluLookAt using its eye, center and up_vector */ + void locate(void); + /** sets the eye values in points */ + void setEyeXYZ(float fEyeX, float fEyeY, float fEyeZ); + /** sets the center values in points */ + void setCenterXYZ(float fCenterX, float fCenterY, float fCenterZ); + /** sets the up values */ + void setUpXYZ(float fUpX, float fUpY, float fUpZ); + + /** get the eye vector values in points */ + void getEyeXYZ(float *pEyeX, float *pEyeY, float *pEyeZ); + /** get the center vector values int points */ + void getCenterXYZ(float *pCenterX, float *pCenterY, float *pCenterZ); + /** get the up vector values */ + void getUpXYZ(float *pUpX, float *pUpY, float *pUpZ); + + static float getZEye(); + + }; + +}//namespace cocos2d + + diff --git a/tools/tolua++/CCCommon.pkg b/tools/tolua++/CCCommon.pkg new file mode 100644 index 0000000000..93f96a803e --- /dev/null +++ b/tools/tolua++/CCCommon.pkg @@ -0,0 +1,19 @@ + + +namespace cocos2d +{ + + + +/** +@brief Output Debug message. +*/ +void CCLog(const char * pszFormat, ...); + +void CCLuaLog(const char * pszFormat); +/** +@brief Pop out a message box +*/ +void CCMessageBox(const char * pszMsg, const char * pszTitle); + +} diff --git a/tools/tolua++/CCData.pkg b/tools/tolua++/CCData.pkg new file mode 100644 index 0000000000..7acb5e4757 --- /dev/null +++ b/tools/tolua++/CCData.pkg @@ -0,0 +1,13 @@ +namespace cocos2d { + +class CCData : public CCObject +{ + CCData(void); + ~CCData(void); + + void* bytes(void); + static CCData* dataWithBytes(unsigned char *pBytes, int size); + static CCData* dataWithContentsOfFile(const std::string &strPath); + +}; +}//namespace cocos2d diff --git a/tools/tolua++/CCDirector.pkg b/tools/tolua++/CCDirector.pkg new file mode 100644 index 0000000000..36e11e7557 --- /dev/null +++ b/tools/tolua++/CCDirector.pkg @@ -0,0 +1,200 @@ +#include "platform/CCPlatformMacros.h" +#include "CCObject.h" +#include "ccTypes.h" +#include "CCGeometry.h" +#include "CCMutableArray.h" +#include "CCGeometry.h" +#include "CCEGLView.h" +#include "CCGL.h" + +namespace cocos2d { + + enum { + /// If the window is resized, it won't be autoscaled + kCCDirectorResize_NoScale, + /// If the window is resized, it will be autoscaled (default behavior) + kCCDirectorResize_AutoScale, + }; + + /** @typedef tPixelFormat + Possible Pixel Formats for the CCEGLView + */ + typedef enum { + /** RGB565 pixel format. No alpha. 16-bit. (Default) */ + kCCPixelFormatRGB565, + /** RGBA format. 32-bit. Needed for some 3D effects. It is not as fast as the RGB565 format. */ + kCCPixelFormatRGBA8888, + /** default pixel format */ + kCCPixelFormatDefault = kCCPixelFormatRGB565, + + // backward compatibility stuff + kPixelFormatRGB565 = kCCPixelFormatRGB565, + kRGB565 = kCCPixelFormatRGB565, + kPixelFormatRGBA8888 = kCCPixelFormatRGBA8888, + kRGBA8 = kCCPixelFormatRGBA8888, + } tPixelFormat; + + + typedef enum { + /// A Depth Buffer of 0 bits will be used (default) + kCCDepthBufferNone, + /// A depth buffer of 16 bits will be used + kCCDepthBuffer16, + /// A depth buffer of 24 bits will be used + kCCDepthBuffer24, + + // backward compatibility stuff + kDepthBuffer16 = kCCDepthBuffer16, + kDepthBuffer24 = kCCDepthBuffer24, + } tDepthBufferFormat; + + typedef enum { + /// sets a 2D projection (orthogonal projection) + kCCDirectorProjection2D, + + /// sets a 3D projection with a fovy=60, znear=0.5f and zfar=1500. + kCCDirectorProjection3D, + + /// it calls "updateProjection" on the projection delegate. + kCCDirectorProjectionCustom, + + /// Detault projection is 3D projection + kCCDirectorProjectionDefault = kCCDirectorProjection3D, + + // backward compatibility stuff + CCDirectorProjection2D = kCCDirectorProjection2D, + CCDirectorProjection3D = kCCDirectorProjection3D, + CCDirectorProjectionCustom = kCCDirectorProjectionCustom, + } ccDirectorProjection; + + + typedef enum { + kCCDirectorTypeNSTimer, + kCCDirectorTypeMainLoop, + kCCDirectorTypeThreadMainLoop, + kCCDirectorTypeDisplayLink, + kCCDirectorTypeDefault = kCCDirectorTypeNSTimer, + CCDirectorTypeNSTimer = kCCDirectorTypeNSTimer, + CCDirectorTypeMainLoop = kCCDirectorTypeMainLoop, + CCDirectorTypeThreadMainLoop = kCCDirectorTypeThreadMainLoop, + CCDirectorTypeDisplayLink = kCCDirectorTypeDisplayLink, + CCDirectorTypeDefault =kCCDirectorTypeDefault, + } ccDirectorType; + + typedef enum { + /// Device oriented vertically, home button on the bottom + kCCDeviceOrientationPortrait = 0, // UIDeviceOrientationPortrait, + /// Device oriented vertically, home button on the top + kCCDeviceOrientationPortraitUpsideDown = 1, // UIDeviceOrientationPortraitUpsideDown, + /// Device oriented horizontally, home button on the right + kCCDeviceOrientationLandscapeLeft = 2, // UIDeviceOrientationLandscapeLeft, + /// Device oriented horizontally, home button on the left + kCCDeviceOrientationLandscapeRight = 3, // UIDeviceOrientationLandscapeRight, + + // Backward compatibility stuff + CCDeviceOrientationPortrait = kCCDeviceOrientationPortrait, + CCDeviceOrientationPortraitUpsideDown = kCCDeviceOrientationPortraitUpsideDown, + CCDeviceOrientationLandscapeLeft = kCCDeviceOrientationLandscapeLeft, + CCDeviceOrientationLandscapeRight = kCCDeviceOrientationLandscapeRight, + } ccDeviceOrientation; + + class CCLabelTTF; + class CCScene; + class CCEGLView; + class CCNode; + class CCProjectionProtocol; + + class CCDirector : public CCObject + { + public: + bool init(void); + CCDirector(void); + + + CCScene* getRunningScene(void); + + + double getAnimationInterval(void); + void setAnimationInterval(double dValue); + bool isDisplayFPS(void); + void setDisplayFPS(bool bDisplayFPS); + CC_GLVIEW* getOpenGLView(void); + void setOpenGLView(CC_GLVIEW *pobOpenGLView); + bool isNextDeltaTimeZero(void); + void setNextDeltaTimeZero(bool bNextDeltaTimeZero); + bool isPaused(void); + ccDirectorProjection getProjection(void); + void setProjection(ccDirectorProjection kProjection); + bool isSendCleanupToScene(void); + CCSize getWinSize(void); + CCSize getWinSizeInPixels(void); + CCSize getDisplaySizeInPixels(void); + void reshapeProjection(CCSize newWindowSize); + CCPoint convertToGL(CCPoint obPoint); + CCPoint convertToUI(CCPoint obPoint); + float getZEye(void); + void runWithScene(CCScene *pScene); + void pushScene(CCScene *pScene); + void popScene(void); + void replaceScene(CCScene *pScene); + void endToLua(void); + void pause(void); + void resume(void); + void drawScene(void); + void purgeCachedData(void); + void setGLDefaultValues(void); + + /** enables/disables OpenGL alpha blending */ + void setAlphaBlending(bool bOn); + + /** enables/disables OpenGL depth test */ + void setDepthTest(bool bOn); + + virtual void mainLoop(void) = 0; + + // Profiler + void showProfilers(void); + + /** rotates the screen if an orientation different than Portrait is used */ + void applyOrientation(void); + + ccDeviceOrientation getDeviceOrientation(void); + void setDeviceOrientation(ccDeviceOrientation kDeviceOrientation); + + void setContentScaleFactor(CGFloat scaleFactor); + CGFloat getContentScaleFactor(void); + + bool enableRetinaDisplay(bool enabled); + bool isRetinaDisplay() { return m_bRetinaDisplay; } + + static bool setDirectorType(ccDirectorType obDirectorType); + + + void setPixelFormat(tPixelFormat kPixelFormat); + /** Pixel format used to create the context */ + tPixelFormat getPiexFormat(void); + + + void setDepthBufferFormat(tDepthBufferFormat kDepthBufferFormat); + + + bool detach(void); + void registerTick(const char* szfn); + + static CCDirector* sharedDirector(void); + }; + +/* + class CCDisplayLinkDirector : public CCDirector + { + + CCDisplayLinkDirector(void); + void mainLoop(void); + void setAnimationInterval(double dValue); + void startAnimation(void); + void stopAnimation(); + }; +*/ +}//namespace cocos2d + + diff --git a/tools/tolua++/CCDrawingPrimitives.pkg b/tools/tolua++/CCDrawingPrimitives.pkg new file mode 100644 index 0000000000..7d6075a5d1 --- /dev/null +++ b/tools/tolua++/CCDrawingPrimitives.pkg @@ -0,0 +1,15 @@ + +#include "CCGeometry.h" // for CCPoint +namespace cocos2d { + +/** draws a point given x and y coordinate measured in points */ +void ccDrawPoint( CCPoint point ); +void ccDrawPoints( const CCPoint *points, unsigned int numberOfPoints ); +void ccDrawLine( CCPoint origin, CCPoint destination ); +void ccDrawPoly( const CCPoint *vertices, int numOfVertices, bool closePolygon ); +void ccDrawCircle( CCPoint center, float radius, float angle, int segments, bool drawLineToCenter); +void ccDrawQuadBezier(CCPoint origin, CCPoint control, CCPoint destination, int segments); +void ccDrawCubicBezier(CCPoint origin, CCPoint control1, CCPoint control2, CCPoint destination, int segments); +}//namespace cocos2d + + diff --git a/tools/tolua++/CCEGLView.pkg b/tools/tolua++/CCEGLView.pkg new file mode 100644 index 0000000000..6e7aa80ef7 --- /dev/null +++ b/tools/tolua++/CCEGLView.pkg @@ -0,0 +1,3 @@ +#include "../platform/CCEGLView_platform.h" + + diff --git a/tools/tolua++/CCGL.pkg b/tools/tolua++/CCGL.pkg new file mode 100644 index 0000000000..04a592be6b --- /dev/null +++ b/tools/tolua++/CCGL.pkg @@ -0,0 +1 @@ +#include "platform/CCGL.h" \ No newline at end of file diff --git a/tools/tolua++/CCGeometry.pkg b/tools/tolua++/CCGeometry.pkg new file mode 100644 index 0000000000..a87b2dd897 --- /dev/null +++ b/tools/tolua++/CCGeometry.pkg @@ -0,0 +1,81 @@ + +#include "CCCommon.h" + +namespace cocos2d { + +typedef float CGFloat; + +class CCPoint +{ +public: + float x; + float y; +public: + CCPoint(); + CCPoint(float x, float y); + static bool CCPointEqualToPoint(const CCPoint& point1, const CCPoint& point2); +}; + +class CCSize +{ +public: + float width; + float height; + +public: + CCSize(); + CCSize(float width, float height); + static bool CCSizeEqualToSize(const CCSize& size1, const CCSize& size2); +}; + +class CCRect +{ +public: + CCPoint origin; + CCSize size; + +public: + CCRect(); + CCRect(float x, float y, float width, float height); + +public: + //! return the leftmost x-value of 'rect' + static CGFloat CCRectGetMinX(const CCRect& rect); + + //! return the rightmost x-value of 'rect' + static CGFloat CCRectGetMaxX(const CCRect& rect); + + //! return the midpoint x-value of 'rect' + static CGFloat CCRectGetMidX(const CCRect& rect); + + //! Return the bottommost y-value of `rect' + static CGFloat CCRectGetMinY(const CCRect& rect); + + //! Return the topmost y-value of `rect' + static CGFloat CCRectGetMaxY(const CCRect& rect); + + //! Return the midpoint y-value of `rect' + static CGFloat CCRectGetMidY(const CCRect& rect); + + static bool CCRectEqualToRect(const CCRect& rect1, const CCRect& rect2); + + static bool CCRectContainsPoint(const CCRect& rect, const CCPoint& point); + + static bool CCRectIntersectsRect(const CCRect& rectA, const CCRect& rectB); +}; + +/* +#define CCPointMake(x, y) CCPoint((x), (y)) +#define CCSizeMake(width, height) CCSize((width), (height)) +#define CCRectMake(x, y, width, height) CCRect((x), (y), (width), (height)) +*/ +CCPoint CCPointMake(float x, float y); +CCSize CCSizeMake(float width, float height); +CCRect CCRectMake(float x, float y, float width,float height); +/* +const CCPoint CCPointZero; +const CCSize CCSizeZero; +const CCRect CCRectZero; +*/ +}//namespace cocos2d + diff --git a/tools/tolua++/CCIMEDelegate.pkg b/tools/tolua++/CCIMEDelegate.pkg new file mode 100644 index 0000000000..73cfef701a --- /dev/null +++ b/tools/tolua++/CCIMEDelegate.pkg @@ -0,0 +1,17 @@ + +typedef struct +{ + CCRect begin; // the soft keyboard rectangle when animatin begin + CCRect end; // the soft keyboard rectangle when animatin end + float duration; // the soft keyboard animation duration +} CCIMEKeyboardNotificationInfo; + +class CCIMEDelegate +{ + bool attachWithIME(); + bool detachWithIME(); +}; + + + + diff --git a/tools/tolua++/CCIMEDispatcher.pkg b/tools/tolua++/CCIMEDispatcher.pkg new file mode 100644 index 0000000000..fc13ac4d30 --- /dev/null +++ b/tools/tolua++/CCIMEDispatcher.pkg @@ -0,0 +1,21 @@ + +class CCIMEDispatcher +{ + + + static CCIMEDispatcher* sharedDispatcher(); + void dispatchInsertText(const char * pText, int nLen); + void dispatchDeleteBackward(); + + ////////////////////////////////////////////////////////////////////////// + // dispatch keyboard notification + ////////////////////////////////////////////////////////////////////////// + void dispatchKeyboardWillShow(CCIMEKeyboardNotificationInfo& info); + void dispatchKeyboardDidShow(CCIMEKeyboardNotificationInfo& info); + void dispatchKeyboardWillHide(CCIMEKeyboardNotificationInfo& info); + void dispatchKeyboardDidHide(CCIMEKeyboardNotificationInfo& info); + +}; + + + diff --git a/tools/tolua++/CCKeypadDelegate.pkg b/tools/tolua++/CCKeypadDelegate.pkg new file mode 100644 index 0000000000..40664fe811 --- /dev/null +++ b/tools/tolua++/CCKeypadDelegate.pkg @@ -0,0 +1,29 @@ +namespace cocos2d { + + class CCKeypadDelegate + { + + void KeypadDestroy(); + + void KeypadKeep(); + + // The back key clicked + void keyBackClicked(); + + // The menu key clicked. only avialble on wophone & android + void keyMenuClicked(); + }; + + + class CCKeypadHandler : public CCObject + { + + CCKeypadDelegate* getDelegate(); + void setDelegate(CCKeypadDelegate *pDelegate); + bool initWithDelegate(CCKeypadDelegate *pDelegate); + + }; + +} //namespace cocos2d + + diff --git a/tools/tolua++/CCKeypadDispatcher.pkg b/tools/tolua++/CCKeypadDispatcher.pkg new file mode 100644 index 0000000000..7f0cdc0e53 --- /dev/null +++ b/tools/tolua++/CCKeypadDispatcher.pkg @@ -0,0 +1,35 @@ + +#include "CCKeypadDelegate.h" +#include "CCMutableArray.h" + +namespace cocos2d { + + typedef enum { + // the back key clicked msg + kTypeBackClicked = 1, + kTypeMenuClicked, + } ccKeypadMSGType; + class CCKeypadDispatcher : public CCObject + { + + CCKeypadDispatcher(); + + static CCKeypadDispatcher* sharedDispatcher(); + static void purgeSharedDispatcher(); + + void addDelegate(CCKeypadDelegate* pDelegate); + + void removeDelegate(CCKeypadDelegate* pDelegate); + + void forceAddDelegate(CCKeypadDelegate* pDelegate); + + + void forceRemoveDelegate(CCKeypadDelegate* pDelegate); + + + bool dispatchKeypadMSG(ccKeypadMSGType nMsgType); + + }; + +} // namespace cocos2d + diff --git a/tools/tolua++/CCLabelAtlas.pkg b/tools/tolua++/CCLabelAtlas.pkg new file mode 100644 index 0000000000..8a35e0c887 --- /dev/null +++ b/tools/tolua++/CCLabelAtlas.pkg @@ -0,0 +1,38 @@ +#include "CCAtlasNode.h" +namespace cocos2d{ + + + class CCLabelAtlas : public CCAtlasNode, public CCLabelProtocol + { + public: + CCLabelAtlas(); + + /** creates the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas */ + static CCLabelAtlas * labelWithString(const char *label, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap); + + static CCLabelAtlas * labelAtlasWithString(const char *label, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap); + + /** initializes the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas */ + bool initWithString(const char *label, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap); + // super methods + void updateAtlasValues(); + void setString(const char *label); + const char* getString(void); + void draw(); + CCLabelProtocol* convertToLabelProtocol(); + + + static CCAtlasNode * atlasWithTileFile(const char* tile,int tileWidth, int tileHeight, int itemsToRender); + + /** initializes an CCAtlasNode with an Atlas file the width and height of each item and the quantity of items to render*/ + bool initWithTileFile(const char* tile, int tileWidth, int tileHeight, int itemsToRender); + + void updateAtlasValues(); + + void draw(); + CCRGBAProtocol* convertToRGBAProtocol(); + CCTexture2D* getTexture(void); + void setTexture(CCTexture2D *texture); + }; +}// namespace cocos2d + diff --git a/tools/tolua++/CCLabelBMFont.pkg b/tools/tolua++/CCLabelBMFont.pkg new file mode 100644 index 0000000000..afbc12a455 --- /dev/null +++ b/tools/tolua++/CCLabelBMFont.pkg @@ -0,0 +1,77 @@ + +#include "CCSpriteBatchNode.h" +namespace cocos2d{ + + struct _KerningHashElement; + + + typedef struct _BMFontDef { + + unsigned int charID; + + CCRect rect; + + int xOffset; + //! The Y amount the image should be offset when drawing the image (in pixels) + int yOffset; + //! The amount to move the current position after drawing the character (in pixels) + int xAdvance; + } ccBMFontDef; + + + typedef struct _BMFontPadding { + /// padding left + int left; + /// padding top + int top; + /// padding right + int right; + /// padding bottom + int bottom; + } ccBMFontPadding; + + enum { + // how many characters are supported + kCCBMFontMaxChars = 2048, //256, + }; + + + class CCBMFontConfiguration : public CCObject + { + CCBMFontConfiguration(); + char * description(); + static CCBMFontConfiguration * configurationWithFNTFile(const char *FNTfile); + bool initWithFNTfile(const char *FNTfile); + }; + + + class CCLabelBMFont : public CCSpriteBatchNode, public CCLabelProtocol, public CCRGBAProtocol + { + + CCLabelBMFont(); + static void purgeCachedData(); + static CCLabelBMFont * labelWithString(const char *str, const char *fntFile); + static CCLabelBMFont * bitmapFontAtlasWithString(const char *str, const char *fntFile); + bool initWithString(const char *str, const char *fntFile); + void createFontChars(); + void setString(const char *label); + const char* getString(void); + void setCString(const char *label); + void setAnchorPoint(CCPoint var); + CCRGBAProtocol* convertToRGBAProtocol(); + CCLabelProtocol* convertToLabelProtocol(); + void draw(); + }; + + + CCBMFontConfiguration * FNTConfigLoadFile( const char *file ); + + void FNTConfigRemoveCache( void ); + + class CCBitmapFontAtlas : public CCLabelBMFont + { + }; + +}// namespace cocos2d + + diff --git a/tools/tolua++/CCLabelTTF.pkg b/tools/tolua++/CCLabelTTF.pkg new file mode 100644 index 0000000000..8cfd6be0e8 --- /dev/null +++ b/tools/tolua++/CCLabelTTF.pkg @@ -0,0 +1,29 @@ + +#include "CCSprite.h" +#include "CCTexture2D.h" + +namespace cocos2d{ + class CCLabelTTF : public CCSprite, public CCLabelProtocol + { + CCLabelTTF(); + ~CCLabelTTF(); + char * description(); + + static CCLabelTTF * labelWithString(const char *label, CCSize dimensions, CCTextAlignment alignment, const char *fontName, float fontSize); + + static CCLabelTTF * labelWithString(const char *label, const char *fontName, float fontSize); + + bool initWithString(const char *label, CCSize dimensions, CCTextAlignment alignment, const char *fontName, float fontSize); + + bool initWithString(const char *label, const char *fontName, float fontSize); + + + void setString(const char *label); + const char* getString(void); + + CCLabelProtocol* convertToLabelProtocol(); + + }; + +} //namespace cocos2d + diff --git a/tools/tolua++/CCLayer.pkg b/tools/tolua++/CCLayer.pkg new file mode 100644 index 0000000000..599abb9a11 --- /dev/null +++ b/tools/tolua++/CCLayer.pkg @@ -0,0 +1,121 @@ +#include "CCNode.h" +#include "CCProtocols.h" +#include "CCTouchDelegateProtocol.h" +#include "CCAccelerometerDelegate.h" +#include "CCKeypadDelegate.h" + +namespace cocos2d { + + class CCLayer : public CCNode, public CCTouchDelegate, public CCAccelerometerDelegate, public CCKeypadDelegate + { + public: + CCLayer(); + bool init(); + static CCLayer *node(void); + void onEnter(); + void onExit(); + void onEnterTransitionDidFinish(); + bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); + void destroy(void); + void keep(void); + + void didAccelerate(CCAcceleration* pAccelerationValue) {} + void AccelerometerDestroy(void); + void AccelerometerKeep(void); + + void KeypadDestroy(); + void KeypadKeep(); + void registerWithTouchDispatcher(void); + + void setIsTouchEnabled(bool bValue); + bool getIsTouchEnabled(); + + void setIsAccelerometerEnabled(bool bValue); + bool getIsAccelerometerEnabled(); + + void setIsKeypadEnabled(bool bValue); + bool getIsKeypadEnabled(); + }; + + class CCLayerColor : public CCLayer , public CCRGBAProtocol, public CCBlendProtocol + { + + + + CCLayerColor(); + void draw(); + void setContentSize(CCSize var); + static CCLayerColor * layerWithColorWidthHeight(ccColor4B color, GLfloat width, GLfloat height); + static CCLayerColor * layerWithColor(ccColor4B color); + bool initWithColorWidthHeight(ccColor4B color, GLfloat width, GLfloat height); + bool initWithColor(ccColor4B color); + void changeWidth(GLfloat w); + void changeHeight(GLfloat h); + void changeWidthAndHeight(GLfloat w ,GLfloat h); + + + GLubyte getOpacity(void); + void setOpacity(GLubyte var); + + + + void setColor(ccColor3B Value); + ccColor3B getColor(void); + + void setBlendFunc(ccBlendFunc Value); + ccBlendFunc getBlendFunc(void); + + CCRGBAProtocol* convertToRGBAProtocol(); + + }; + + class CCColorLayer : public CCLayerColor + { + + }; + + class CCLayerGradient : public CCLayerColor + { + + + static CCLayerGradient* layerWithColor(ccColor4B start, ccColor4B end); + + /** Creates a full-screen CCLayer with a gradient between start and end in the direction of v. */ + static CCLayerGradient* layerWithColor(ccColor4B start, ccColor4B end, CCPoint v); + + /** Initializes the CCLayer with a gradient between start and end. */ + bool initWithColor(ccColor4B start, ccColor4B end); + + /** Initializes the CCLayer with a gradient between start and end in the direction of v. */ + bool initWithColor(ccColor4B start, ccColor4B end, CCPoint v); + + ccColor3B getStartColor(); + void setStartColor(ccColor3B colors); + + void setEndColor(ccColor3B Value); + ccColor3B getEndColor(void); + + void setStartOpacity(GLubyte Value); + GLubyte getStartOpacity(void); + + void setEndOpacity(GLubyte Value); + GLubyte getEndOpacity(void); + + void setVector(CCPoint Value); + CCPoint getVector(void); + }; + + + class CCMultiplexLayer : public CCLayer + { + CCMultiplexLayer(); + //static CCMultiplexLayer * layerWithLayers(CCLayer* layer, ... ); + //lua instead with follow func + static CCMultiplexLayer * layerWithLayer(CCLayer* layer); + void addLayer(CCLayer* layer); + bool initWithLayer(CCLayer* layer); + bool initWithLayers(CCLayer* layer, va_list params); + void switchTo(unsigned int n); + void switchToAndReleaseMe(unsigned int n); + }; +}//namespace cocos2d diff --git a/tools/tolua++/CCMenu.pkg b/tools/tolua++/CCMenu.pkg new file mode 100644 index 0000000000..222e353660 --- /dev/null +++ b/tools/tolua++/CCMenu.pkg @@ -0,0 +1,89 @@ + +#include "CCMenuItem.h" +#include "CCLayer.h" + +namespace cocos2d{ + + typedef enum + { + kCCMenuStateWaiting, + kCCMenuStateTrackingTouch + } tCCMenuState; + + enum { + //* priority used by the menu + kCCMenuTouchPriority = -128, + }; + + class CCMenu : public CCLayer, public CCRGBAProtocol + { + public: + CCMenu(); + virtual ~CCMenu(){} + static CCMenu*menuWithItem(CCMenuItem* item); + bool initWithItems(CCMenuItem* item, va_list args); + void alignItemsVertically(); + + void alignItemsVerticallyWithPadding(float padding); + void alignItemsHorizontally(); + void alignItemsHorizontallyWithPadding(float padding); + + + void alignItemsInRows(unsigned int rows, ...); + void alignItemsInColumns(unsigned int columns, va_list args); + + /** align items in columns of rows */ + void alignItemsInColumns(unsigned int columns, ...); + void alignItemsInRows(unsigned int rows, va_list args); + + //super methods + void addChild(CCNode * child, int zOrder); + void addChild(CCNode * child, int zOrder, int tag); + void registerWithTouchDispatcher(); + bool ccTouchBegan(CCTouch* touch, CCEvent* event); + void ccTouchEnded(CCTouch* touch, CCEvent* event); + void ccTouchCancelled(CCTouch *touch, CCEvent* event); + void ccTouchMoved(CCTouch* touch, CCEvent* event); + + void destroy(void); + void keep(void); + + + void onExit(); + + void setOpacity(GLubyte opacity); + GLubyte getOpacity(void); + ccColor3B getColor(void); + void setColor(ccColor3B color); + CCRGBAProtocol* convertToRGBAProtocol(); + + + bool init(); + static CCLayer *node(void); + void onEnter(); + void onExit(); + void onEnterTransitionDidFinish(); + bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); + void destroy(void); + void keep(void); + + void didAccelerate(CCAcceleration* pAccelerationValue) {} + void AccelerometerDestroy(void); + void AccelerometerKeep(void); + + void KeypadDestroy(); + void KeypadKeep(); + void registerWithTouchDispatcher(void); + + void setIsTouchEnabled(bool bValue); + bool getIsTouchEnabled(); + + void setIsAccelerometerEnabled(bool bValue); + bool getIsAccelerometerEnabled(); + + void setIsKeypadEnabled(bool bValue); + bool getIsKeypadEnabled(); + }; + +} + diff --git a/tools/tolua++/CCMenuItem.pkg b/tools/tolua++/CCMenuItem.pkg new file mode 100644 index 0000000000..624269cfc4 --- /dev/null +++ b/tools/tolua++/CCMenuItem.pkg @@ -0,0 +1,139 @@ +#include "CCNode.h" +#include "CCProtocols.h" +#include "selector_protocol.h" + +namespace cocos2d{ + + class CCLabelTTF; + class CCLabelAtlas; + class CCSprite; + + + class CCMenuItem : public CCNode + { + + public: + CCMenuItem(); + + static CCMenuItem * itemWithTarget(SelectorProtocol *rec, SEL_MenuHandler selector); + bool initWithTarget(SelectorProtocol *rec, SEL_MenuHandler selector); + + CCRect rect(); + void activate(); + void selected(); + void unselected(); + + void registerMenuHandler(const char* fn); + + }; + + class CCMenuItemLabel : public CCMenuItem, public CCRGBAProtocol + { + + public: + CCMenuItemLabel(); + + static CCMenuItemLabel * itemWithLabel(CCNode*label, SelectorProtocol* target, SEL_MenuHandler selector); + + bool initWithLabel(CCNode* label, SelectorProtocol* target, SEL_MenuHandler selector); + + void setString(const char * label); + + virtual void activate(); + virtual void selected(); + virtual void unselected(); + virtual void setIsEnabled(bool enabled); + virtual void setOpacity(GLubyte opacity); + virtual GLubyte getOpacity(); + virtual void setColor(ccColor3B color); + virtual ccColor3B getColor(); + virtual CCRGBAProtocol* convertToRGBAProtocol(); + + }; + + /** @brief A CCMenuItemAtlasFont + Helper class that creates a MenuItemLabel class with a LabelAtlas + */ + class CCMenuItemAtlasFont : public CCMenuItemLabel + { + + CCMenuItemAtlasFont(); + static CCMenuItemAtlasFont* itemFromString(const char *value, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap); + /** creates a menu item from a string and atlas. Use it with MenuItemToggle */ + static CCMenuItemAtlasFont* itemFromString(const char *value, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap, SelectorProtocol* target, SEL_MenuHandler selector); + /** initializes a menu item from a string and atlas with a target/selector */ + bool initFromString(const char *value, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap, SelectorProtocol* target, SEL_MenuHandler selector); + }; + + class CCMenuItemFont : public CCMenuItemLabel + { + + CCMenuItemFont(); + + static void setFontSize(int s); + static int fontSize(); + /** set the font name */ + static void setFontName(const char *name); + /** get the font name */ + static const char *fontName(); + /** creates a menu item from a string without target/selector. To be used with CCMenuItemToggle */ + static CCMenuItemFont * itemFromString(const char *value); + /** creates a menu item from a string with a target/selector */ + static CCMenuItemFont * itemFromString(const char *value, SelectorProtocol* target, SEL_MenuHandler selector); + /** initializes a menu item from a string with a target/selector */ + bool initFromString(const char *value, SelectorProtocol* target, SEL_MenuHandler selector); + }; + + + class CCMenuItemSprite : public CCMenuItem, public CCRGBAProtocol + { + CCMenuItemSprite(); + static CCMenuItemSprite * itemFromNormalSprite(CCNode* normalSprite, CCNode* selectedSprite); + static CCMenuItemSprite * itemFromNormalSprite(CCNode* normalSprite, CCNode* selectedSprite, SelectorProtocol* target, SEL_MenuHandler selector); + static CCMenuItemSprite * itemFromNormalSprite(CCNode* normalSprite, CCNode* selectedSprite, CCNode* disabledSprite, SelectorProtocol* target, SEL_MenuHandler selector); + bool initFromNormalSprite(CCNode* normalSprite, CCNode* selectedSprite, CCNode* disabledSprite, SelectorProtocol* target, SEL_MenuHandler selector); + void setColor(ccColor3B color); + ccColor3B getColor(); + void setOpacity(GLubyte opacity); + GLubyte getOpacity(); + void selected(); + void unselected(); + void setIsEnabled(bool bEnabled); + CCRGBAProtocol* convertToRGBAProtocol(); + }; + + + class CCMenuItemImage : public CCMenuItemSprite + { + + CCMenuItemImage(); + static CCMenuItemImage* itemFromNormalImage(const char *normalImage, const char *selectedImage); + static CCMenuItemImage* itemFromNormalImage(const char *normalImage, const char *selectedImage, const char *disabledImage); + static CCMenuItemImage* itemFromNormalImage(const char *normalImage, const char *selectedImage, SelectorProtocol* target, SEL_MenuHandler selector); + static CCMenuItemImage* itemFromNormalImage(const char *normalImage, const char *selectedImage, const char *disabledImage, SelectorProtocol* target, SEL_MenuHandler selector); + bool initFromNormalImage(const char *normalImage, const char *selectedImage, const char *disabledImage, SelectorProtocol* target, SEL_MenuHandler selector); + void setColor(ccColor3B color); + ccColor3B getColor(); + void setOpacity(GLubyte opacity); + GLubyte getOpacity(); + }; + + + class CCMenuItemToggle : public CCMenuItem, public CCRGBAProtocol + { + + CCMenuItemToggle(); + + // static CCMenuItemToggle* itemWithTarget(SelectorProtocol* target, SEL_MenuHandler selector, CCMenuItem* item, ...); + // bool initWithTarget(SelectorProtocol* target, SEL_MenuHandler selector, CCMenuItem* item, va_list args); + CCMenuItem* selectedItem(); + // super methods + virtual void activate(); + virtual void selected(); + virtual void unselected(); + void setIsEnabled(bool var); + CCRGBAProtocol* convertToRGBAProtocol(); + }; + +} + diff --git a/tools/tolua++/CCMotionStreak.pkg b/tools/tolua++/CCMotionStreak.pkg new file mode 100644 index 0000000000..046710fb23 --- /dev/null +++ b/tools/tolua++/CCMotionStreak.pkg @@ -0,0 +1,29 @@ + +#include "CCNode.h" +#include "CCProtocols.h" + +namespace cocos2d { + +class CCRibbon; +class CCMotionStreak : public CCNode, public CCTextureProtocol +{ + +// CC_PROPERTY_READONLY(CCRibbon*, m_pRibbon, Ribbon) + CCRibbon* getRibbon(void); + + //CC_PROPERTY(CCTexture2D*, m_pTexture, Texture) + CCTexture2D* getTexture(void); + void setTexture(CCTexture2D* var); + + ccBlendFunc getBlendFunc(void); + void setBlendFunc(ccBlendFunc var); + + CCMotionStreak(); + static CCMotionStreak * streakWithFade(float fade, float seg, const char *imagePath, float width, float length, ccColor4B color); + bool initWithFade(float fade, float seg, const char *imagePath, float width, float length, ccColor4B color); + void updateMotion(ccTime delta); +}; + +} // namespace cocos2d + + diff --git a/tools/tolua++/CCMutableArray.pkg b/tools/tolua++/CCMutableArray.pkg new file mode 100644 index 0000000000..b1180cc6ba --- /dev/null +++ b/tools/tolua++/CCMutableArray.pkg @@ -0,0 +1,54 @@ + +namespace cocos2d { + +class CCMutableArray : public CCObject +{ + TOLUA_TEMPLATE_BIND(T, CCObject*, CCSpriteFrame*, CCFiniteTimeAction*) + + CCMutableArray(unsigned int uSize = 0); + + ~CCMutableArray(void); + + unsigned int count(void); + unsigned int getIndexOfObject(T pObject); + + bool containsObject(T pObject); + + T getLastObject(void); + T getObjectAtIndex(unsigned int uIndex); + + // Adding objects + void addObject(T pObject); + void addObjectsFromArray(CCMutableArray *pArray); + + void insertObjectAtIndex(T pObject, unsigned int uIndex); + // Removing objects + void removeLastObject(bool bDeleteObject = true); + + void removeObject(T pObject, bool bDeleteObject = true); + + void removeObjectsInArray(CCMutableArray* pDeleteArray); + + void removeObjectAtIndex(unsigned int uIndex, bool bDeleteObject = true); + void removeAllObjects(bool bDeleteObject = true); + + void replaceObjectAtIndex(unsigned int uIndex, T pObject, bool bDeleteObject = true); + + + std::vector::iterator begin(void); + + std::vector::reverse_iterator rbegin(void); + + std::vector::iterator endToLua(void); + std::vector::reverse_iterator rend(void); + CCMutableArray* copy(void); + + //static CCMutableArray* arrayWithObjects(T pObject1, ...); + + static CCMutableArray* arrayWithArray(CCMutableArray *pArray); + +}; + +}//namespace cocos2d + + diff --git a/tools/tolua++/CCMutableDictionary.pkg b/tools/tolua++/CCMutableDictionary.pkg new file mode 100644 index 0000000000..074ab49769 --- /dev/null +++ b/tools/tolua++/CCMutableDictionary.pkg @@ -0,0 +1,35 @@ + +namespace cocos2d { + +class CCMutableDictionary : public CCObject +{ + TOLUA_TEMPLATE_BIND(K V, std::string CCObject*) + + CCMutableDictionary(void); + ~CCMutableDictionary(void); + /// return the number of items + unsigned int count(); + /// return all the keys + std::vector allKeys(); + + /** @warning : We use '==' to compare two objects*/ + std::vector allKeysForObject(V object); + + V objectForKey(K key); ///< + + bool setObject(V pObject, K key); + void removeObjectForKey(K key); + bool begin(); + + V next(K* key = NULL); + + void endToLua(); + + void removeAllObjects(); + static CCMutableDictionary* dictionaryWithDictionary(CCMutableDictionary* srcDict); +}; + + +typedef CCMutableDictionary CCStringToStringDictionary; +}//namespace cocos2d + diff --git a/tools/tolua++/CCNode.pkg b/tools/tolua++/CCNode.pkg new file mode 100644 index 0000000000..1466f9c261 --- /dev/null +++ b/tools/tolua++/CCNode.pkg @@ -0,0 +1,105 @@ +namespace cocos2d { +enum { + kCCNodeTagInvalid = -1, +}; + +class CCNode : public CCObject, public SelectorProtocol +{ + int getZOrder(); + float getVertexZ(); + void setVertexZ(float var); + float getRotation(); + void setRotation(float newRotation); + float getScale(); + void setScale(float scale); + void setScale(float scale); + float getScaleX(); + void setScaleX(float newScaleX); + float getScaleY(); + void setScaleY(float newScaleY); + CCPoint getPosition(); + void setPosition(CCPoint newPosition); + CCMutableArray * getChildren(); + CCCamera* getCamera(); + CCGridBase* getGrid(); + void setGrid(CCGridBase* pGrid); + bool getIsVisible(); + void setIsVisible(bool var); + CCPoint getAnchorPoint(); + void setAnchorPoint(CCPoint point); + CCPoint getAnchorPointInPixels(); + CCSize getContentSize(); + void setContentSize(CCSize size); + bool getIsRunning(); + CCNode * getParent(); + void setParent(CCNode * var); + bool getIsRelativeAnchorPoint(); + void setIsRelativeAnchorPoint(bool newValue); + int getTag(); + void setTag(int var); + void* getUserData(); + void setUserData(void *var); + void onEnter(); + void onEnterTransitionDidFinish(); + void onExit(); + void addChild(CCNode * child); + void addChild(CCNode * child, int zOrder); + void addChild(CCNode * child, int zOrder, int tag); + void removeChild(CCNode* child, bool cleanup); + void removeAllChildrenWithCleanup(bool cleanup); + void reorderChild(CCNode * child, int zOrder); + void cleanup(void); + void draw(void); + void visit(void); + void selectorProtocolRetain(void); + void selectorProtocolRelease(void); + CCRGBAProtocol* convertToRGBAProtocol(void); + CCLabelProtocol* convertToLabelProtocol(void); + void transform(void); + void transformAncestors(void); + CCRect boundingBox(void); + CCAction* runAction(CCAction* action); + void stopAllActions(void); + void stopAction(CCAction* action); + void stopActionByTag(int tag); + CCAction* getActionByTag(int tag); + char * description(void); + CCNode* getChildByTag(int tag); + int numberOfRunningActions(void); + //bool isScheduled(SEL_SCHEDULE selector); + void scheduleUpdate(void); + void scheduleUpdateWithPriority(int priority); + void unscheduleUpdate(void); + //void schedule(SEL_SCHEDULE selector); + //void schedule(SEL_SCHEDULE selector, ccTime interval); + //void unschedule(SEL_SCHEDULE selector); + void schedule(const char* selector); + void schedule(const char* selector, ccTime interval); + void unschedule(const char* selector); + void unscheduleAllSelectors(void); + void resumeSchedulerAndActions(void); + void pauseSchedulerAndActions(void); + CCAffineTransform nodeToParentTransform(void); + CCAffineTransform parentToNodeTransform(void); + CCAffineTransform nodeToWorldTransform(void); + CCAffineTransform worldToNodeTransform(void); + CCPoint convertToNodeSpace(CCPoint worldPoint); + CCPoint convertToWorldSpace(CCPoint nodePoint); + CCPoint convertToNodeSpaceAR(CCPoint worldPoint); + CCPoint convertToWorldSpaceAR(CCPoint nodePoint); + CCPoint convertTouchToNodeSpace(CCTouch * touch); + CCPoint convertTouchToNodeSpaceAR(CCTouch * touch); + void removeFromParentAndCleanup(bool cleanup); + void removeChildByTag(int tag, bool cleanup); + + bool registerScriptSelector(const char* szType, const char* szSeletor); + static CCNode * node(void); + + + +}; +}//namespace cocos2d + + + + diff --git a/tools/tolua++/CCObject.pkg b/tools/tolua++/CCObject.pkg new file mode 100644 index 0000000000..1692744a0b --- /dev/null +++ b/tools/tolua++/CCObject.pkg @@ -0,0 +1,26 @@ +namespace cocos2d { + +class CCCopying +{ + + CCObject* copyWithZone(CCZone* pZone); +}; + +class CCObject : public CCCopying +{ + + CCObject(void); + ~CCObject(void); + + void release(void); + void retain(void); + CCObject* autorelease(void); + CCObject* copy(void); + bool isSingleRefrence(void); + unsigned int retainCount(void); + bool isEqual(const CCObject* pObject); + +}; +}//namespace cocos2d + + diff --git a/tools/tolua++/CCParallaxNode.pkg b/tools/tolua++/CCParallaxNode.pkg new file mode 100644 index 0000000000..860aef496a --- /dev/null +++ b/tools/tolua++/CCParallaxNode.pkg @@ -0,0 +1,26 @@ +namespace cocos2d { + struct _ccArray; + class CCParallaxNode : public CCNode + { + + struct _ccArray * getParallaxArray(); + void setParallaxArray(struct _ccArray * pval); + + + CCParallaxNode(); + ~CCParallaxNode(); + static CCParallaxNode * node(); + void addChild(CCNode * child, int z, CCPoint parallaxRatio, CCPoint positionOffset); + void addChild(CCNode * child, int zOrder, int tag); + void removeChild(CCNode* child, bool cleanup); + void removeAllChildrenWithCleanup(bool cleanup); + void visit(void); + struct _ccArray * getParallaxArray(); + void setParallaxArray(struct _ccArray * val); + + }; + +} // namespace cocos2d + + + diff --git a/tools/tolua++/CCPointExtension.pkg b/tools/tolua++/CCPointExtension.pkg new file mode 100644 index 0000000000..6cb1262ca5 --- /dev/null +++ b/tools/tolua++/CCPointExtension.pkg @@ -0,0 +1,68 @@ +namespace cocos2d { + +static CCPoint ccpNeg(const CCPoint& v); + +static CCPoint ccpAdd(const CCPoint& v1, const CCPoint& v2); + +static CCPoint ccpSub(const CCPoint& v1, const CCPoint& v2); + +static CCPoint ccpMult(const CCPoint& v, const CGFloat s); + +static CCPoint ccpMidpoint(const CCPoint& v1, const CCPoint& v2); + +static CGFloat ccpDot(const CCPoint& v1, const CCPoint& v2); + + +static CGFloat ccpCross(const CCPoint& v1, const CCPoint& v2); + +static CCPoint ccpPerp(const CCPoint& v); + +static CCPoint ccpRPerp(const CCPoint& v); + +static CCPoint ccpProject(const CCPoint& v1, const CCPoint& v2); + +static CCPoint ccpRotate(const CCPoint& v1, const CCPoint& v2); + +static CCPoint ccpUnrotate(const CCPoint& v1, const CCPoint& v2); + +static CGFloat ccpLengthSQ(const CCPoint& v); + +CGFloat ccpLength(const CCPoint& v); + +CGFloat ccpDistance(const CCPoint& v1, const CCPoint& v2); + +CCPoint ccpNormalize(const CCPoint& v); + +CCPoint ccpForAngle(const CGFloat a); + +CGFloat ccpToAngle(const CCPoint& v); + +float clampf(float value, float min_inclusive, float max_inclusive); + +CCPoint ccpClamp(const CCPoint& p, const CCPoint& from, const CCPoint& to); + +CCPoint ccpFromSize(const CCSize& s); + +//CCPoint ccpCompOp(const CCPoint& p, float (*opFunc)(float)); + +CCPoint ccpLerp(const CCPoint& a, const CCPoint& b, float alpha); + + +bool ccpFuzzyEqual(const CCPoint& a, const CCPoint& b, float variance); + + +CCPoint ccpCompMult(const CCPoint& a, const CCPoint& b); + +float ccpAngleSigned(const CCPoint& a, const CCPoint& b); + +float ccpAngle(const CCPoint& a, const CCPoint& b); + +CCPoint ccpRotateByAngle(const CCPoint& v, const CCPoint& pivot, float angle); + + +bool ccpLineIntersect(const CCPoint& p1, const CCPoint& p2, const CCPoint& p3, const CCPoint& p4, float *s, float *t); + +}//namespace cocos2d + + + diff --git a/tools/tolua++/CCProgressTimer.pkg b/tools/tolua++/CCProgressTimer.pkg new file mode 100644 index 0000000000..fbadf80d35 --- /dev/null +++ b/tools/tolua++/CCProgressTimer.pkg @@ -0,0 +1,46 @@ +namespace cocos2d +{ + +typedef enum { + /// Radial Counter-Clockwise + kCCProgressTimerTypeRadialCCW, + /// Radial ClockWise + kCCProgressTimerTypeRadialCW, + /// Horizontal Left-Right + kCCProgressTimerTypeHorizontalBarLR, + /// Horizontal Right-Left + kCCProgressTimerTypeHorizontalBarRL, + /// Vertical Bottom-top + kCCProgressTimerTypeVerticalBarBT, + /// Vertical Top-Bottom + kCCProgressTimerTypeVerticalBarTB, +} CCProgressTimerType; + + +class CCProgressTimer : public CCNode +{ + + ~CCProgressTimer(void); + CCProgressTimerType getType(void); + float getPercentage(void); + + /** The image to show the progress percentage, retain */ + CCSprite* getSprite(void); + + bool initWithFile(const char *pszFileName); + bool initWithTexture(CCTexture2D *pTexture); + + void setPercentage(float fPercentage); + void setSprite(CCSprite *pSprite); + void setType(CCProgressTimerType type); + + void draw(void); + + static CCProgressTimer* progressWithFile(const char *pszFileName); + static CCProgressTimer* progressWithTexture(CCTexture2D *pTexture); + + +}; + +} + diff --git a/tools/tolua++/CCProtocols.pkg b/tools/tolua++/CCProtocols.pkg new file mode 100644 index 0000000000..fa2b1a5af8 --- /dev/null +++ b/tools/tolua++/CCProtocols.pkg @@ -0,0 +1,98 @@ +namespace cocos2d { + +//! @brief CC RGBA protocol +class CCRGBAProtocol +{ +public: + /** sets Color + @since v0.8 + */ + void setColor(ccColor3B color); + + /** returns the color + @since v0.8 + */ + ccColor3B getColor(void); + + // returns the opacity + GLubyte getOpacity(void); + + /** sets the opacity. + @warning If the the texture has premultiplied alpha then, the R, G and B channels will be modifed. + Values goes from 0 to 255, where 255 means fully opaque. + */ + void setOpacity(GLubyte opacity); + + // optional + + /** sets the premultipliedAlphaOpacity property. + If set to NO then opacity will be applied as: glColor(R,G,B,opacity); + If set to YES then oapcity will be applied as: glColor(opacity, opacity, opacity, opacity ); + Textures with premultiplied alpha will have this property by default on YES. Otherwise the default value is NO + @since v0.8 + */ + void setIsOpacityModifyRGB(bool bValue); + + /** returns whether or not the opacity will be applied using glColor(R,G,B,opacity) or glColor(opacity, opacity, opacity, opacity); + @since v0.8 + */ + bool getIsOpacityModifyRGB(void); +}; + +/** + @brief You can specify the blending fuction. + @since v0.99.0 + */ +class CCBlendProtocol +{ + + // set the source blending function for the texture + void setBlendFunc(ccBlendFunc blendFunc); + + // returns the blending function used for the texture + ccBlendFunc getBlendFunc(void); +}; + +/** @brief CCNode objects that uses a Texture2D to render the images. + The texture can have a blending function. + If the texture has alpha premultiplied the default blending function is: + src=GL_ONE dst= GL_ONE_MINUS_SRC_ALPHA + else + src=GL_SRC_ALPHA dst= GL_ONE_MINUS_SRC_ALPHA + But you can change the blending funtion at any time. + @since v0.8.0 + */ +class CCTextureProtocol : public CCBlendProtocol +{ + + // returns the used texture + CCTexture2D* getTexture(void); + + // sets a new texture. it will be retained + void setTexture(CCTexture2D *texture); +}; + +//! @brief Common interface for Labels +class CCLabelProtocol +{ + + // sets a new label using an string + void setString(const char *label); + + /** returns the string that is rendered */ + const char* getString(void); +}; + +/** OpenGL projection protocol */ +class CCProjectionProtocol : public CCObject +{ + + /** Called by CCDirector when the porjection is updated, and "custom" projection is used + @since v0.99.5 + */ + void updateProjection(void); +}; + +}//namespace cocos2d + + diff --git a/tools/tolua++/CCRenderTexture.pkg b/tools/tolua++/CCRenderTexture.pkg new file mode 100644 index 0000000000..cf3d15b372 --- /dev/null +++ b/tools/tolua++/CCRenderTexture.pkg @@ -0,0 +1,55 @@ + +namespace cocos2d { + +typedef enum eImageFormat +{ + kCCImageFormatJPG = 0, + kCCImageFormatPNG = 1, + kCCImageFormatRawData = 2 +} tImageFormat; + +class CCRenderTexture : public CCNode +{ + /** The CCSprite being used. + The sprite, by default, will use the following blending function: GL_ONE, GL_ONE_MINUS_SRC_ALPHA. + The blending function can be changed in runtime by calling: + - [[renderTexture sprite] setBlendFunc:(ccBlendFunc){GL_ONE, GL_ONE_MINUS_SRC_ALPHA}]; + */ + CCSprite* getSprite(); + void setSprite(CCSprite* psprite); + + CCRenderTexture(); + ~CCRenderTexture(); + /** creates a RenderTexture object with width and height in Points and a pixel format, only RGB and RGBA formats are valid */ + static CCRenderTexture * renderTextureWithWidthAndHeight(int w, int h, CCTexture2DPixelFormat eFormat); + + /** creates a RenderTexture object with width and height in Points, pixel format is RGBA8888 */ + static CCRenderTexture * renderTextureWithWidthAndHeight(int w, int h); + + /** initializes a RenderTexture object with width and height in Points and a pixel format, only RGB and RGBA formats are valid */ + bool initWithWidthAndHeight(int w, int h, CCTexture2DPixelFormat eFormat); + + /** starts grabbing */ + void begin(); + + /** starts rendering to the texture while clearing the texture first. + This is more efficient then calling -clear first and then -begin */ + void beginWithClear(float r, float g, float b, float a); + + /** ends grabbing */ + void endToLua(); + + /** clears the texture with a color */ + void clear(float r, float g, float b, float a); + + /** saves the texture into a file */ + bool saveBuffer(const char *name); + /** saves the texture into a file. The format can be JPG or PNG */ + bool saveBuffer(const char *name, int format); + + /* get buffer as UIImage, can only save a render buffer which has a RGBA8888 pixel format */ + CCData *getUIImageAsDataFromBuffer(int format); + +}; + +} // namespace cocos2d diff --git a/tools/tolua++/CCRibbon.pkg b/tools/tolua++/CCRibbon.pkg new file mode 100644 index 0000000000..e170e83d2c --- /dev/null +++ b/tools/tolua++/CCRibbon.pkg @@ -0,0 +1,46 @@ +namespace cocos2d { + +class CCRibbon: public CCNode +{ + + CCRibbon(); + ~CCRibbon(); + void setTexture(CCTexture2D* val); + CCTexture2D* getTexture(); + /** Texture lengths in pixels */ + float getTextureLength(); + void setTextureLength(float val); + + void setBlendFunc(ccBlendFunc val); + ccBlendFunc getBlendFunc(); + + void setColor(ccColor4B val); + ccColor4B getColor(); + + + static CCRibbon * ribbonWithWidth(float w, const char *path, float length, ccColor4B color, float fade); + + bool initWithWidth(float w, const char *path, float length, ccColor4B color, float fade); + + void addPointAt(CCPoint location, float width); + + void update(ccTime delta); + + float sideOfLine(CCPoint p, CCPoint l1, CCPoint l2); + void draw(); + +}; + +/** @brief object to hold ribbon segment data */ +class CCRibbonSegment: public CCObject +{ + CCRibbonSegment(); + ~CCRibbonSegment(); + char * description(); + bool init(); + void reset(); + void draw(float curTime, float fadeTime, ccColor4B color); +}; + +} // namespace cocos2d + diff --git a/tools/tolua++/CCScene.pkg b/tools/tolua++/CCScene.pkg new file mode 100644 index 0000000000..fbfb4c665d --- /dev/null +++ b/tools/tolua++/CCScene.pkg @@ -0,0 +1,23 @@ +namespace cocos2d { + +typedef enum +{ + ccNormalScene = 1 << 0, + ccTransitionScene = 1 << 1, +} ccSceneFlag; + + +class CCScene : public CCNode +{ + + CCScene(); + virtual ~CCScene(); + bool init(); + static CCScene *node(void); + ccSceneFlag getSceneType(void); + + +}; +}//namespace cocos2d + + diff --git a/tools/tolua++/CCScheduler.pkg b/tools/tolua++/CCScheduler.pkg new file mode 100644 index 0000000000..3554290d96 --- /dev/null +++ b/tools/tolua++/CCScheduler.pkg @@ -0,0 +1,82 @@ +namespace cocos2d { + +class CCTimer : public CCObject +{ + + CCTimer(void); + + + ccTime getInterval(void); + + void setInterval(ccTime fInterval); + + //bool initWithTarget(SelectorProtocol *pTarget, SEL_SCHEDULE pfnSelector); + + //bool initWithTarget(SelectorProtocol *pTarget, SEL_SCHEDULE pfnSelector, ccTime fSeconds); + + void update(ccTime dt); + + //static CCTimer* timerWithTarget(SelectorProtocol *pTarget, SEL_SCHEDULE pfnSelector); + + //static CCTimer* timerWithTarget(SelectorProtocol *pTarget, SEL_SCHEDULE pfnSelector, ccTime fSeconds); + + static CCTimer* timerWithScript(SelectorProtocol* pTarget, const char* szFuncName, ccTime fSeconds); + bool initWithScript(SelectorProtocol* pTarget, const char* szFuncName, ccTime fSeconds); + bool isScriptFuncExist( const char* szFuncName); + + //SEL_SCHEDULE m_pfnSelector; + ccTime m_fInterval; + std::string m_scriptFunc; + +}; + + +class CCScheduler : public CCObject +{ + ~CCScheduler(void); + + ccTime getTimeScale(void); + + void setTimeScale(ccTime fTimeScale); + + + void tick(ccTime dt); + + void scheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget, ccTime fInterval, bool bPaused, const char* szScriptFunc); + void scheduleUpdateForTarget(SelectorProtocol *pTarget, int nPriority, bool bPaused); + + void unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget, const char* szScriptFunc); + + void unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget); + + void unscheduleUpdateForTarget(const SelectorProtocol *pTarget); + + void unscheduleAllSelectorsForTarget(SelectorProtocol *pTarget); + + void unscheduleAllSelectors(void); + + + void pauseTarget(SelectorProtocol *pTarget); + + void resumeTarget(SelectorProtocol *pTarget); + + void scheduleTimer(CCTimer *pTimer); + + + void unscheduleTimer(CCTimer *pTimer); + + void unscheduleAllTimers(void); + + + static CCScheduler* sharedScheduler(void); + + /** purges the shared scheduler. It releases the retained instance. + @since v0.99.0 + */ + static void purgeSharedScheduler(void); + + +}; +}//namespace cocos2d + + diff --git a/tools/tolua++/CCSet.pkg b/tools/tolua++/CCSet.pkg new file mode 100644 index 0000000000..7f672bc666 --- /dev/null +++ b/tools/tolua++/CCSet.pkg @@ -0,0 +1,28 @@ +namespace cocos2d { + +typedef std::set::iterator CCSetIterator; + +class CCSet : public CCObject +{ +public: + CCSet(void); + CCSet(const CCSet &rSetObject); + ~CCSet(void); + + CCSet* copy(); + CCSet* mutableCopy(); + int count(); + void addObject(CCObject *pObject); + void removeObject(CCObject *pObject); + bool containsObject(CCObject *pObject); + CCSetIterator begin(); + CCSetIterator end(); + CCObject* anyObject(); + +}; + +typedef CCSet NSMutableSet; +}//namespace cocos2d + + + diff --git a/tools/tolua++/CCSprite.pkg b/tools/tolua++/CCSprite.pkg new file mode 100644 index 0000000000..6c20890d3b --- /dev/null +++ b/tools/tolua++/CCSprite.pkg @@ -0,0 +1,169 @@ + +namespace cocos2d { + +enum { + /// CCSprite invalid index on the CCSpriteBatchNode + CCSpriteIndexNotInitialized = 0xffffffff, +}; + +typedef enum { + //! Translate with it's parent + CC_HONOR_PARENT_TRANSFORM_TRANSLATE = 1 << 0, + //! Rotate with it's parent + CC_HONOR_PARENT_TRANSFORM_ROTATE = 1 << 1, + //! Scale with it's parent + CC_HONOR_PARENT_TRANSFORM_SCALE = 1 << 2, + + //! All possible transformation enabled. Default value. + CC_HONOR_PARENT_TRANSFORM_ALL = CC_HONOR_PARENT_TRANSFORM_TRANSLATE | CC_HONOR_PARENT_TRANSFORM_ROTATE | CC_HONOR_PARENT_TRANSFORM_SCALE, + +} ccHonorParentTransform; + +class CCSprite : public CCNode, public CCTextureProtocol, public CCRGBAProtocol +{ + + void draw(void); + + bool isDirty(void); + /** make the Sprite to be updated in the Atlas. */ + void setDirty(bool bDirty); + + /** get the quad (tex coords, vertex coords and color) information */ + ccV3F_C4B_T2F_Quad getQuad(void); + + /** returns whether or not the texture rectangle is rotated */ + bool isTextureRectRotated(void); + + /** Set the index used on the TextureAtlas. */ + unsigned int getAtlasIndex(void); + + void setAtlasIndex(unsigned int uAtlasIndex); + + CCRect getTextureRect(void); + + bool isUsesBatchNode(void); + + void setUsesSpriteBatchNode(bool bUsesSpriteBatchNode); + + CCTextureAtlas* getTextureAtlas(void); + void setTextureAtlas(CCTextureAtlas *pobTextureAtlas); + + CCSpriteBatchNode* getSpriteBatchNode(void); + void setSpriteBatchNode(CCSpriteBatchNode *pobSpriteBatchNode); + + ccHonorParentTransform getHornorParentTransform(void); + void setHornorParentTransform(ccHonorParentTransform eHonorParentTransform); + + CCPoint getOffsetPositionInPixels(void); + + ccBlendFunc getBlendFunc(void); + void setBlendFunc(ccBlendFunc blendFunc); + + + static CCSprite* spriteWithTexture(CCTexture2D *pTexture); + + + static CCSprite* spriteWithTexture(CCTexture2D *pTexture, CCRect rect); + + static CCSprite* spriteWithTexture(CCTexture2D *pTexture, CCRect rect, CCPoint offset); + + + static CCSprite* spriteWithSpriteFrame(CCSpriteFrame *pSpriteFrame); + + static CCSprite* spriteWithSpriteFrameName(const char *pszSpriteFrameName); + + + static CCSprite* spriteWithFile(const char *pszFileName); + + static CCSprite* spriteWithFile(const char *pszFileName, CCRect rect); + + static CCSprite* spriteWithBatchNode(CCSpriteBatchNode *batchNode, CCRect rect); + + static CCSprite* spriteWithSpriteSheet(CCSpriteSheetInternalOnly *pSpriteSheet, CCRect rect); + + + bool init(void); + ~CCSprite(void); + CCSprite(); + + void removeChild(CCNode* pChild, bool bCleanup); + void removeAllChildrenWithCleanup(bool bCleanup); + void reorderChild(CCNode *pChild, int zOrder); + void addChild(CCNode *pChild); + void addChild(CCNode *pChild, int zOrder); + void addChild(CCNode *pChild, int zOrder, int tag); + + void setDirtyRecursively(bool bValue); + void setPosition(CCPoint pos); + void setPositionInPixels(CCPoint pos); + void setRotation(float fRotation); + void setScaleX(float fScaleX); + void setScaleY(float fScaleY); + void setScale(float fScale); + void setVertexZ(float fVertexZ); + void setAnchorPoint(CCPoint anchor); + void setIsRelativeAnchorPoint(bool bRelative); + void setIsVisible(bool bVisible); + void setFlipX(bool bFlipX); + void setFlipY(bool bFlipY); + + bool isFlipX(void); + + bool isFlipY(void); + + void updateColor(void); + + GLubyte getOpacity(void); + void setOpacity(GLubyte opacity); + /** RGB colors: conforms to CCRGBAProtocol protocol */ + ccColor3B getColor(void); + void setColor(ccColor3B color3); + void setIsOpacityModifyRGB(bool bValue); + bool getIsOpacityModifyRGB(void); + + CCRGBAProtocol* convertToRGBAProtocol() { return (CCRGBAProtocol *)this; } + void setTexture(CCTexture2D *texture); + CCTexture2D* getTexture(void); + + bool initWithTexture(CCTexture2D *pTexture); + + bool initWithTexture(CCTexture2D *pTexture, CCRect rect); + + bool initWithSpriteFrame(CCSpriteFrame *pSpriteFrame); + + bool initWithSpriteFrameName(const char *pszSpriteFrameName); + + bool initWithFile(const char *pszFilename); + + bool initWithFile(const char *pszFilename, CCRect rect); + + bool initWithBatchNode(CCSpriteBatchNode *batchNode, CCRect rect); + bool initWithSpriteSheet(CCSpriteSheetInternalOnly *pSpriteSheet, CCRect rect); + + bool initWithBatchNodeRectInPixels(CCSpriteBatchNode *batchNode, CCRect rect); + + void updateTransform(void); + + void useSelfRender(void); + + void setTextureRect(CCRect rect); + + void setTextureRectInPixels(CCRect rect, bool rotated, CCSize size); + + void useBatchNode(CCSpriteBatchNode *batchNode); + void useSpriteSheetRender(CCSpriteSheetInternalOnly *pSpriteSheet); + void setDisplayFrame(CCSpriteFrame *pNewFrame); + bool isFrameDisplayed(CCSpriteFrame *pFrame); + CCSpriteFrame* displayedFrame(void); + + void addAnimation(CCAnimation *pAnimation); + + CCAnimation* animationByName(const char *pszAnimationName); + + void setDisplayFrame(const char *pszAnimationName, int nFrameIndex); + + void setDisplayFrameWithAnimationName(const char *animationName, int frameIndex); + +}; +}//namespace cocos2d + diff --git a/tools/tolua++/CCSpriteBatchNode.pkg b/tools/tolua++/CCSpriteBatchNode.pkg new file mode 100644 index 0000000000..d0dd9d2819 --- /dev/null +++ b/tools/tolua++/CCSpriteBatchNode.pkg @@ -0,0 +1,64 @@ +namespace cocos2d +{ + + class CCSpriteBatchNode : public CCNode, public CCTextureProtocol + { + + ~CCSpriteBatchNode(); + + + CCTextureAtlas* getTextureAtlas(void); + void setTextureAtlas(CCTextureAtlas* textureAtlas); + CCArray* getDescendants(void); + + static CCSpriteBatchNode* batchNodeWithTexture(CCTexture2D *tex); + static CCSpriteBatchNode* spriteSheetWithTexture(CCTexture2D *tex); // deprecated + + static CCSpriteBatchNode* batchNodeWithTexture(CCTexture2D* tex, unsigned int capacity); + static CCSpriteBatchNode* spriteSheetWithTexture(CCTexture2D *tex, unsigned int capacity); // deprecated + static CCSpriteBatchNode* batchNodeWithFile(const char* fileImage); + static CCSpriteBatchNode* spriteSheetWithFile(const char* fileImage); // deprecated + static CCSpriteBatchNode* batchNodeWithFile(const char* fileImage, unsigned int capacity); + static CCSpriteBatchNode* spriteSheetWithFile(const char* fileImage, unsigned int capacity); // deprecated + bool initWithTexture(CCTexture2D *tex, unsigned int capacity); + + bool initWithFile(const char* fileImage, unsigned int capacity); + + void increaseAtlasCapacity(); + + CCSprite* createSpriteWithRect(CCRect rect); + + void initSprite(CCSprite *sprite, CCRect rect); + + void removeChildAtIndex(unsigned int index, bool doCleanup); + + void insertChild(CCSprite *child, unsigned int index); + void removeSpriteFromAtlas(CCSprite *sprite); + + unsigned int rebuildIndexInOrder(CCSprite *parent, unsigned int index); + unsigned int highestAtlasIndexInChild(CCSprite *sprite); + unsigned int lowestAtlasIndexInChild(CCSprite *sprite); + unsigned int atlasIndexForChild(CCSprite *sprite, int z); + + // CCTextureProtocol + CCTexture2D* getTexture(void); + void setTexture(CCTexture2D *texture); + void setBlendFunc(ccBlendFunc blendFunc); + ccBlendFunc getBlendFunc(void); + + void visit(void); + void addChild(CCNode * child); + void addChild(CCNode * child, int zOrder); + void addChild(CCNode * child, int zOrder, int tag); + void reorderChild(CCNode * child, int zOrder); + + void removeChild(CCNode* child, bool cleanup); + void removeAllChildrenWithCleanup(bool cleanup); + void draw(void); + + + + + }; +} + diff --git a/tools/tolua++/CCSpriteFrame.pkg b/tools/tolua++/CCSpriteFrame.pkg new file mode 100644 index 0000000000..0b3dc4effc --- /dev/null +++ b/tools/tolua++/CCSpriteFrame.pkg @@ -0,0 +1,49 @@ +namespace cocos2d { + +class CCSpriteFrame : public CCObject +{ + + CCRect getRectInPixels(void); + void setRectInPixels(CCRect rectInPixels); + + bool isRotated(void); + void setRotated(bool bRotated); + + CCRect getRect(void); + void setRect(CCRect rect); + + CCPoint getOffsetInPixels(void); + void setOffsetInPixels(CCPoint offsetInPixels); + + CCSize getOriginalSizeInPixels(void); + void setOriginalSizeInPixels(CCSize sizeInPixels); + + CCTexture2D* getTexture(void); + void setTexture(CCTexture2D* pobTexture); + + ~CCSpriteFrame(void); + virtual CCObject* copyWithZone(CCZone *pZone); + + /** Create a CCSpriteFrame with a texture, rect in points. + It is assumed that the frame was not trimmed. + */ + static CCSpriteFrame* frameWithTexture(CCTexture2D* pobTexture, CCRect rect); + + /** Create a CCSpriteFrame with a texture, rect, rotated, offset and originalSize in pixels. + The originalSize is the size in points of the frame before being trimmed. + */ + static CCSpriteFrame* frameWithTexture(CCTexture2D* pobTexture, CCRect rect, bool rotated, CCPoint offset, CCSize originalSize); + + + bool initWithTexture(CCTexture2D* pobTexture, CCRect rect); + + /** Initializes a CCSpriteFrame with a texture, rect, rotated, offset and originalSize in pixels. + The originalSize is the size in points of the frame before being trimmed. + */ + bool initWithTexture(CCTexture2D* pobTexture, CCRect rect, bool rotated, CCPoint offset, CCSize originalSize); + +}; + +}//namespace cocos2d + + diff --git a/tools/tolua++/CCSpriteFrameCache.pkg b/tools/tolua++/CCSpriteFrameCache.pkg new file mode 100644 index 0000000000..480cffbf99 --- /dev/null +++ b/tools/tolua++/CCSpriteFrameCache.pkg @@ -0,0 +1,51 @@ +namespace cocos2d { + +class CCSpriteFrameCache : public CCObject +{ + + bool init(void); + ~CCSpriteFrameCache(void); + + void addSpriteFramesWithDictionary(CCDictionary *pobDictionary, CCTexture2D *pobTexture); + + void addSpriteFramesWithFile(const char *pszPlist); + + + void addSpriteFramesWithFile(const char* plist, const char* textureFileName); + + /** Adds multiple Sprite Frames from a plist file. The texture will be associated with the created sprite frames. */ + void addSpriteFramesWithFile(const char *pszPlist, CCTexture2D *pobTexture); + + void addSpriteFrame(CCSpriteFrame *pobFrame, const char *pszFrameName); + + + void removeSpriteFrames(void); + + void removeUnusedSpriteFrames(void); + + /** Deletes an sprite frame from the sprite frame cache. */ + void removeSpriteFrameByName(const char *pszName); + + void removeSpriteFramesFromFile(const char* plist); + + void removeSpriteFramesFromDictionary(CCDictionary *dictionary); + + + void removeSpriteFramesFromTexture(CCTexture2D* texture); + + CCSpriteFrame* spriteFrameByName(const char *pszName); + + CCSprite* createSpriteWithFrameName(const char *pszName); + + + /** Returns the shared instance of the Sprite Frame cache */ + static CCSpriteFrameCache* sharedSpriteFrameCache(void); + + /** Purges the cache. It releases all the Sprite Frames and the retained instance. */ + static void purgeSharedSpriteFrameCache(void); + + +}; +}//namespace cocos2d + + diff --git a/tools/tolua++/CCSpriteSheet.pkg b/tools/tolua++/CCSpriteSheet.pkg new file mode 100644 index 0000000000..eb9ccdde72 --- /dev/null +++ b/tools/tolua++/CCSpriteSheet.pkg @@ -0,0 +1,14 @@ +namespace cocos2d { + + class CCSpriteSheetInternalOnly : public CCSpriteBatchNode + { + }; + + + class CCSpriteSheet: public CCSpriteSheetInternalOnly + { + }; + +}//namespace cocos2d + + diff --git a/tools/tolua++/CCString.pkg b/tools/tolua++/CCString.pkg new file mode 100644 index 0000000000..293c7aac12 --- /dev/null +++ b/tools/tolua++/CCString.pkg @@ -0,0 +1,16 @@ + +namespace cocos2d { + + class CCString : public CCObject + { + + CCString(); + CCString(const char * str); + ~CCString(); + int toInt(); + unsigned int toUInt(); + float toFloat(); + + bool isEmpty(); + }; +}// namespace cocos2d diff --git a/tools/tolua++/CCTMXLayer.pkg b/tools/tolua++/CCTMXLayer.pkg new file mode 100644 index 0000000000..af528348e7 --- /dev/null +++ b/tools/tolua++/CCTMXLayer.pkg @@ -0,0 +1,85 @@ +namespace cocos2d { + class CCTMXLayer : public CCSpriteBatchNode + { + /** size of the layer in tiles */ + CCSize getLayerSize(); + void setLayerSize(CCSize val); + /** size of the map's tile (could be differnt from the tile's size) */ + CCSize getMapTileSize(); + void setMapTileSize(CCSize val); + /** pointer to the map of tiles */ + unsigned int* getTiles(); + void setTiles(unsigned int* pval); + + /** Tilset information for the layer */ + CCTMXTilesetInfo* getTileSet(); + void setTileSet(CCTMXTilesetInfo* pval); + + /** Layer orientation, which is the same as the map orientation */ + void setLayerOrientation(int val); + int getLayerOrientation(); + /** properties from the layer. They can be added using Tiled */ + CCStringToStringDictionary* getProperties(); + void setProperties(CCStringToStringDictionary* pval); + + CCTMXLayer(); + ~CCTMXLayer(); + /** creates a CCTMXLayer with an tileset info, a layer info and a map info */ + static CCTMXLayer * layerWithTilesetInfo(CCTMXTilesetInfo *tilesetInfo, CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo); + /** initializes a CCTMXLayer with a tileset info, a layer info and a map info */ + bool initWithTilesetInfo(CCTMXTilesetInfo *tilesetInfo, CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo); + + /** dealloc the map that contains the tile position from memory. + Unless you want to know at runtime the tiles positions, you can safely call this method. + If you are going to call layer->tileGIDAt() then, don't release the map + */ + void releaseMap(); + + /** returns the tile (CCSprite) at a given a tile coordinate. + The returned CCSprite will be already added to the CCTMXLayer. Don't add it again. + The CCSprite can be treated like any other CCSprite: rotated, scaled, translated, opacity, color, etc. + You can remove either by calling: + - layer->removeChild(sprite, cleanup); + - or layer->removeTileAt(ccp(x,y)); + */ + CCSprite* tileAt(CCPoint tileCoordinate); + + /** returns the tile gid at a given tile coordinate. + if it returns 0, it means that the tile is empty. + This method requires the the tile map has not been previously released (eg. don't call layer->releaseMap()) + */ + unsigned int tileGIDAt(CCPoint tileCoordinate); + + /** sets the tile gid (gid = tile global id) at a given tile coordinate. + The Tile GID can be obtained by using the method "tileGIDAt" or by using the TMX editor -> Tileset Mgr +1. + If a tile is already placed at that position, then it will be removed. + */ + void setTileGID(unsigned int gid, CCPoint tileCoordinate); + + /** removes a tile at given tile coordinate */ + void removeTileAt(CCPoint tileCoordinate); + + /** returns the position in pixels of a given tile coordinate */ + CCPoint positionAt(CCPoint tileCoordinate); + + /** return the value for the specific property name */ + CCString *propertyNamed(const char *propertyName); + + /** Creates the tiles */ + void setupTiles(); + + /** CCTMXLayer doesn't support adding a CCSprite manually. + @warning addchild(z, tag); is not supported on CCTMXLayer. Instead of setTileGID. + */ + virtual void addChild(CCNode * child, int zOrder, int tag); + // super method + void removeChild(CCNode* child, bool cleanup); + void draw(); + + const char* getLayerName(); + void setLayerName(const char *layerName); + }; + +}// namespace cocos2d + + diff --git a/tools/tolua++/CCTMXObjectGroup.pkg b/tools/tolua++/CCTMXObjectGroup.pkg new file mode 100644 index 0000000000..38504285d9 --- /dev/null +++ b/tools/tolua++/CCTMXObjectGroup.pkg @@ -0,0 +1,35 @@ +namespace cocos2d { + + /** @brief CCTMXObjectGroup represents the TMX object group. + @since v0.99.0 + */ + class CCTMXObjectGroup : public CCObject + { + /** offset position of child objects */ + CCPoint getPositionOffset(); + void setPositionOffset(CCPoint pt); + /** list of properties stored in a dictionary */ + CCStringToStringDictionary* getProperties(); + void setProperties(CCStringToStringDictionary* pval); + /** array of the objects */ + + CCMutableArray* getObjects(); + void setObjects(CCMutableArray* val); + + CCTMXObjectGroup(); + ~CCTMXObjectGroup(); + + const char* getGroupName(); + void setGroupName(const char *groupName); + + /** return the value for the specific property name */ + CCString *propertyNamed(const char* propertyName); + + /** return the dictionary for the specific object name. + It will return the 1st object found on the array for the given name. + */ + CCStringToStringDictionary *objectNamed(const char *objectName); + + }; + +}// namespace cocos2d diff --git a/tools/tolua++/CCTMXTiledMap.pkg b/tools/tolua++/CCTMXTiledMap.pkg new file mode 100644 index 0000000000..00bc004f53 --- /dev/null +++ b/tools/tolua++/CCTMXTiledMap.pkg @@ -0,0 +1,65 @@ +namespace cocos2d { + enum + { + /** Orthogonal orientation */ + CCTMXOrientationOrtho, + + /** Hexagonal orientation */ + CCTMXOrientationHex, + + /** Isometric orientation */ + CCTMXOrientationIso, + }; + + + class CCTMXTiledMap : public CCNode + { + /** the map's size property measured in tiles */ + CCSize getMapSize(); + void setMapSize(CCSize sz); + /** the tiles's size property measured in pixels */ + CCSize getTileSize(); + void setTileSize(CCSize sz); + /** map orientation */ + int getMapOrientation(); + void setMapOrientation(int val); + /** object groups */ + + CCMutableArray* getObjectGroups(); + void setObjectGroups(CCMutableArray* pval); + /** properties */ + CCStringToStringDictionary* getProperties(); + void setProperties(CCStringToStringDictionary* pval); + + CCTMXTiledMap(); + ~CCTMXTiledMap(); + + /** creates a TMX Tiled Map with a TMX file.*/ + static CCTMXTiledMap * tiledMapWithTMXFile(const char *tmxFile); + + /** initializes a TMX Tiled Map with a TMX file */ + bool initWithTMXFile(const char *tmxFile); + + /** return the TMXLayer for the specific layer */ + CCTMXLayer* layerNamed(const char *layerName); + + /** return the TMXObjectGroup for the secific group */ + CCTMXObjectGroup* objectGroupNamed(const char *groupName); + + /** return the TMXObjectGroup for the secific group + @deprecated Use map#objectGroupNamed instead + */ + CCTMXObjectGroup* groupNamed(const char *groupName); + + /** return the value for the specific property name */ + CCString *propertyNamed(const char *propertyName); + + /** return properties dictionary for tile GID */ + CCDictionary *propertiesForGID(int GID); + + }; + +}// namespace cocos2d + + + diff --git a/tools/tolua++/CCTMXXMLParser.pkg b/tools/tolua++/CCTMXXMLParser.pkg new file mode 100644 index 0000000000..145baacc37 --- /dev/null +++ b/tools/tolua++/CCTMXXMLParser.pkg @@ -0,0 +1,117 @@ +namespace cocos2d { + + enum { + TMXLayerAttribNone = 1 << 0, + TMXLayerAttribBase64 = 1 << 1, + TMXLayerAttribGzip = 1 << 2, + }; + + enum { + TMXPropertyNone, + TMXPropertyMap, + TMXPropertyLayer, + TMXPropertyObjectGroup, + TMXPropertyObject, + TMXPropertyTile + }; + + class CCTMXLayerInfo : public CCObject + { + CCStringToStringDictionary* getProperties(); + void setProperties(CCStringToStringDictionary* pval); + + CCTMXLayerInfo(); + ~CCTMXLayerInfo(); + }; + + + class CCTMXTilesetInfo : public CCObject + { + + CCTMXTilesetInfo(); + ~CCTMXTilesetInfo(); + CCRect rectForGID(unsigned int gid); + }; + + /** @brief CCTMXMapInfo contains the information about the map like: + - Map orientation (hexagonal, isometric or orthogonal) + - Tile size + - Map size + + And it also contains: + - Layers (an array of TMXLayerInfo objects) + - Tilesets (an array of TMXTilesetInfo objects) + - ObjectGroups (an array of TMXObjectGroupInfo objects) + + This information is obtained from the TMX file. + + */ + class CCTMXMapInfo : public CCObject, public CCSAXDelegator + { + public: + /// map orientation + int getOrientation(); + void setOrientation(int val); + /// map width & height + CCSize getMapSize(); + void setMapSize(CCSize sz); + /// tiles width & height + + CCSize getTileSize(); + void setTileSize(CCSize sz); + /// Layers + CCMutableArray* getLayers(); + void setLayers(CCMutableArray* pval); + /// tilesets + CCMutableArray* getTilesets(); + void setTilesets(CCMutableArray* pval); + + /// ObjectGroups + CCMutableArray* getObjectGroups(); + void setObjectGroups(CCMutableArray* val); + /// parent element + int getParentElement(); + void setParentElement(int val); + /// parent GID + unsigned int getParentGID(); + void setParentGID(unsigned int val); + + /// layer attribs + int getLayerAttribs(); + void setLayerAttribs(int val); + /// is stroing characters? + bool getStoringCharacters(); + void setStoringCharacters(bool val); + + /// properties + CCStringToStringDictionary* getProperties(); + void setProperties(CCStringToStringDictionary* pval); + + CCTMXMapInfo(); + ~CCTMXMapInfo(); + /** creates a TMX Format with a tmx file */ + static CCTMXMapInfo * formatWithTMXFile(const char *tmxFile); + /** initializes a TMX format witha tmx file */ + bool initWithTMXFile(const char *tmxFile); + /** initalises parsing of an XML file, either a tmx (Map) file or tsx (Tileset) file */ + bool parseXMLFile(const char *xmlFilename); + + CCDictionary * getTileProperties(); + void setTileProperties(CCDictionary * tileProperties); + + // implement pure virtual methods of CCSAXDelegator + void startElement(void *ctx, const char *name, const char **atts); + void endElement(void *ctx, const char *name); + void textHandler(void *ctx, const char *ch, int len); + + const char* getCurrentString(); + void setCurrentString(const char *currentString); + const char* getTMXFileName(); + void setTMXFileName(const char *fileName); + + }; + +}// namespace cocos2d + + + diff --git a/tools/tolua++/CCTextFieldTTF.pkg b/tools/tolua++/CCTextFieldTTF.pkg new file mode 100644 index 0000000000..7088c3e857 --- /dev/null +++ b/tools/tolua++/CCTextFieldTTF.pkg @@ -0,0 +1,79 @@ +namespace cocos2d { + + +class CCTextFieldDelegate +{ + + /** + @brief If the sender doesn't want to attach with IME, return true; + */ + bool onTextFieldAttachWithIME(CCTextFieldTTF * sender); + + /** + @brief If the sender doesn't want to detach with IME, return true; + */ + bool onTextFieldDetachWithIME(CCTextFieldTTF * sender); + + /** + @brief If the sender doesn't want to insert the text, return true; + */ + bool onTextFieldInsertText(CCTextFieldTTF * sender, const char * text, int nLen); + + /** + @brief If the sender doesn't want to delete the delText, return true; + */ + bool onTextFieldDeleteBackward(CCTextFieldTTF * sender, const char * delText, int nLen); + /** + @brief If doesn't want draw sender as default, return true. + */ + bool onDraw(CCTextFieldTTF * sender); +}; + +/** +@brief A simple text input field with TTF font. +*/ +class CCTextFieldTTF : public CCLabelTTF, public CCIMEDelegate +{ + CCTextFieldTTF(); + ~CCTextFieldTTF(); + + //char * description(); + + /** creates a CCTextFieldTTF from a fontname, alignment, dimension and font size */ + static CCTextFieldTTF * textFieldWithPlaceHolder(const char *placeholder, CCSize dimensions, CCTextAlignment alignment, const char *fontName, float fontSize); + /** creates a CCLabelTTF from a fontname and font size */ + static CCTextFieldTTF * textFieldWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize); + /** initializes the CCTextFieldTTF with a font name, alignment, dimension and font size */ + bool initWithPlaceHolder(const char *placeholder, CCSize dimensions, CCTextAlignment alignment, const char *fontName, float fontSize); + /** initializes the CCTextFieldTTF with a font name and font size */ + bool initWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize); + + /** + @brief Open keyboard and receive input text. + */ + bool attachWithIME(); + + /** + @brief End text input and close keyboard. + */ + bool detachWithIME(); + + ////////////////////////////////////////////////////////////////////////// + // properties + ////////////////////////////////////////////////////////////////////////// + + CCTextFieldDelegate* getDelegate(); + void setDelegate(CCTextFieldDelegate *pVal); + + int getCharCount(); + ccColor3B getColorSpaceHolder(); + void setColorSpaceHolder(ccColor3B val); + // input text property + void setString(const char *text); + const char* getString(void); + + void setPlaceHolder(const char * text); + const char * getPlaceHolder(void); + +}; +} \ No newline at end of file diff --git a/tools/tolua++/CCTexture2D.pkg b/tools/tolua++/CCTexture2D.pkg new file mode 100644 index 0000000000..a0d0ce86ef --- /dev/null +++ b/tools/tolua++/CCTexture2D.pkg @@ -0,0 +1,109 @@ +namespace cocos2d { + +class CCImage; +typedef enum { + kCCTexture2DPixelFormat_Automatic = 0, + //! 32-bit texture: RGBA8888 + kCCTexture2DPixelFormat_RGBA8888, + //! 24-bit texture: RGBA888 + kCCTexture2DPixelFormat_RGB888, + //! 16-bit texture without Alpha channel + kCCTexture2DPixelFormat_RGB565, + //! 8-bit textures used as masks + kCCTexture2DPixelFormat_A8, + //! 16-bit textures: RGBA4444 + kCCTexture2DPixelFormat_RGBA4444, + //! 16-bit textures: RGB5A1 + kCCTexture2DPixelFormat_RGB5A1, + + //! Default texture format: RGBA8888 + kCCTexture2DPixelFormat_Default = kCCTexture2DPixelFormat_RGBA8888, + + // backward compatibility stuff + kTexture2DPixelFormat_Automatic = kCCTexture2DPixelFormat_Automatic, + kTexture2DPixelFormat_RGBA8888 = kCCTexture2DPixelFormat_RGBA8888, + kTexture2DPixelFormat_RGB888 = kCCTexture2DPixelFormat_RGB888, + kTexture2DPixelFormat_RGB565 = kCCTexture2DPixelFormat_RGB565, + kTexture2DPixelFormat_A8 = kCCTexture2DPixelFormat_A8, + kTexture2DPixelFormat_RGBA4444 = kCCTexture2DPixelFormat_RGBA4444, + kTexture2DPixelFormat_RGB5A1 = kCCTexture2DPixelFormat_RGB5A1, + kTexture2DPixelFormat_Default = kCCTexture2DPixelFormat_Default + +} CCTexture2DPixelFormat; + +/** +Extension to set the Min / Mag filter +*/ +typedef struct _ccTexParams { + GLuint minFilter; + GLuint magFilter; + GLuint wrapS; + GLuint wrapT; +} ccTexParams; + + +class CCTexture2D : public CCObject +{ + /** pixel format of the texture */ + CCTexture2DPixelFormat getPixelFormat(); + /** width in pixels */ + unsigned int getPixelsWide(); + unsigned int getPixelsHigh(); + + /** texture name */ + GLuint getName(); + + /** content size */ + CCSize getContentSizeInPixels(); + /** texture max S */ + void setMaxS(GLfloat val); + GLfloat getMaxS(); + /** texture max T */ + GLfloat getMaxT(); + void setMaxT(GLfloat val); + + bool getHasPremultipliedAlpha(); + + CCTexture2D(); + ~CCTexture2D(); + + char * description(void); + + /** These functions are needed to create mutable textures */ + void releaseData(void *data); + void* keepData(void *data, unsigned int length); + + /** Intializes with a texture2d with data */ + bool initWithData(const void* data, CCTexture2DPixelFormat pixelFormat, unsigned int pixelsWide, unsigned int pixelsHigh, CCSize contentSize); + + + /** draws a texture at a given point */ + void drawAtPoint(CCPoint point); + /** draws a texture inside a rect */ + void drawInRect(CCRect rect); + + /** Initializes a texture from a UIImage object */ + bool initWithImage(CCImage * uiImage); + /** Initializes a texture from a string with dimensions, alignment, font name and font size */ + bool initWithString(const char *text, CCSize dimensions, CCTextAlignment alignment, const char *fontName, float fontSize); + /** Initializes a texture from a string with font name and font size */ + bool initWithString(const char *text, const char *fontName, float fontSize); + + /** returns the content size of the texture in points */ + CCSize getContentSize(void); + + + void setTexParameters(ccTexParams* texParams); + + void setAntiAliasTexParameters(); + + void setAliasTexParameters(); + + void generateMipmap(); + + static void setDefaultAlphaPixelFormat(CCTexture2DPixelFormat format); + static CCTexture2DPixelFormat defaultAlphaPixelFormat(); + +}; +}//namespace cocos2d + diff --git a/tools/tolua++/CCTextureAtlas.pkg b/tools/tolua++/CCTextureAtlas.pkg new file mode 100644 index 0000000000..48ad867443 --- /dev/null +++ b/tools/tolua++/CCTextureAtlas.pkg @@ -0,0 +1,57 @@ +namespace cocos2d { + +class CCTextureAtlas : public CCObject +{ + unsigned int getTotalQuads(); + unsigned int getCapacity(); + + CCTexture2D* getTexture(); + void setTexture(CCTexture2D* val); + /** Quads that are going to be rendered */ + + void setQuads(ccV3F_C4B_T2F_Quad* val); + ccV3F_C4B_T2F_Quad* getQuads(); + + CCTextureAtlas(); + ~CCTextureAtlas(); + + char * description(); + + static CCTextureAtlas * textureAtlasWithFile(const char* file , unsigned int capacity); + + bool initWithFile(const char* file, unsigned int capacity); + + static CCTextureAtlas * textureAtlasWithTexture(CCTexture2D *texture, unsigned int capacity); + + + bool initWithTexture(CCTexture2D *texture, unsigned int capacity); + + + void updateQuad(ccV3F_C4B_T2F_Quad* quad, unsigned int index); + + + void insertQuad(ccV3F_C4B_T2F_Quad* quad, unsigned int index); + + + void insertQuadFromIndex(unsigned int fromIndex, unsigned int newIndex); + + void removeQuadAtIndex(unsigned int index); + + + void removeAllQuads(); + + bool resizeCapacity(unsigned int n); + + + void drawNumberOfQuads(unsigned int n); + + /** draws all the Atlas's Quads + */ + void drawQuads(); + +}; +}//namespace cocos2d + + + + diff --git a/tools/tolua++/CCTextureCache.pkg b/tools/tolua++/CCTextureCache.pkg new file mode 100644 index 0000000000..a56bc5667d --- /dev/null +++ b/tools/tolua++/CCTextureCache.pkg @@ -0,0 +1,74 @@ +namespace cocos2d { + +class CCTextureCache : public CCObject +{ + + CCTextureCache(); + ~CCTextureCache(); + + char * description(void); + + /** Retruns ths shared instance of the cache */ + static CCTextureCache * sharedTextureCache(); + + static void purgeSharedTextureCache(); + + CCTexture2D* addImage(const char* fileimage); + + + CCTexture2D* addUIImage(CCImage *image, const char *key); + + + CCTexture2D* textureForKey(const char* key); + + void removeAllTextures(); + + + void removeUnusedTextures(); + + void removeTexture(CCTexture2D* texture); + + void removeTextureForKey(const char *textureKeyName); + + static void reloadAllTextures(); +}; +/* +#if CC_ENABLE_CACHE_TEXTTURE_DATA + +class VolatileTexture +{ +public: + VolatileTexture(CCTexture2D *t); + ~VolatileTexture(); + + static void addImageTexture(CCTexture2D *tt, const char* imageFileName, CCImage::EImageFormat format); + static void addStringTexture(CCTexture2D *tt, const char* text, CCSize dimensions, CCTextAlignment alignment, const char *fontName, float fontSize); + + static void removeTexture(CCTexture2D *t); + static void reloadAllTextures(); + +public: + static std::list textures; + static bool isReloading; + +protected: + CCTexture2D *texture; + + bool m_bIsString; + + std::string m_strFileName; + CCImage::EImageFormat m_FmtImage; + + CCSize m_size; + CCTextAlignment m_alignment; + std::string m_strFontName; + std::string m_strText; + float m_fFontSize; +}; + +#endif +*/ + +}//namespace cocos2d + + diff --git a/tools/tolua++/CCTileMapAtlas.pkg b/tools/tolua++/CCTileMapAtlas.pkg new file mode 100644 index 0000000000..49f7ae540a --- /dev/null +++ b/tools/tolua++/CCTileMapAtlas.pkg @@ -0,0 +1,29 @@ + +namespace cocos2d { + typedef std::map StringToIntegerDictionary; + typedef std::pair StringToIntegerPair; + struct sImageTGA; + class CCTileMapAtlas : public CCAtlasNode + { + + /** TileMap info */ + struct sImageTGA* getTGAInfo(); + void setTGAInfo(struct sImageTGA* val); + + CCTileMapAtlas(); + ~CCTileMapAtlas(); + + static CCTileMapAtlas * tileMapAtlasWithTileFile(const char *tile, const char *mapFile, int tileWidth, int tileHeight); + + bool initWithTileFile(const char *tile, const char *mapFile, int tileWidth, int tileHeight); + + + void setTile(ccColor3B tile, ccGridSize position); + /** dealloc the map from memory */ + void releaseMap(); + }; + + +}// namespace cocos2d + + diff --git a/tools/tolua++/CCTouch.pkg b/tools/tolua++/CCTouch.pkg new file mode 100644 index 0000000000..790144968f --- /dev/null +++ b/tools/tolua++/CCTouch.pkg @@ -0,0 +1,22 @@ +namespace cocos2d { + +class CCTouch : public CCObject +{ + + CCTouch(); + CCTouch(int nViewId, float x, float y); + + CCPoint locationInView(int nViewId); + CCPoint previousLocationInView(int nViewId); + int view() { return m_nViewId; } + + void SetTouchInfo(int nViewId, float x, float y); +}; + +class CCEvent : public CCObject +{ +}; + +} // end of namespace cocos2d + + diff --git a/tools/tolua++/CCTouchDelegateProtocol.pkg b/tools/tolua++/CCTouchDelegateProtocol.pkg new file mode 100644 index 0000000000..c632dfcd28 --- /dev/null +++ b/tools/tolua++/CCTouchDelegateProtocol.pkg @@ -0,0 +1,88 @@ +namespace cocos2d { + +typedef enum +{ + ccTouchDelegateStandardBit = 1 << 0, + ccTouchDelegateTargetedBit = 1 << 1, + ccTouchDelegateAllBit = (ccTouchDelegateStandardBit | ccTouchDelegateTargetedBit), +} ccTouchDelegateFlag; + +class CCTouch; +class CCEvent; +class CCSet; +class CCTouchDispatcher; + +class CCTouchDelegate +{ + +public: + + ccTouchDelegateFlag getTouchDelegateType(void); + + //! call the release() in child(layer or menu) + virtual void destroy(void); + //! call the retain() in child (layer or menu) + virtual void keep(void); + + virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); + // optional + + virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent); + virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); + virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent); + + // optional + virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent); + virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent); + virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent); + virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent); + + CCTouchDelegate(); + void registerLuaTouchEvent(const char* szEventName, const char* fn); +}; +/** + @brief + Using this type of delegate results in two benefits: + - 1. You don't need to deal with CCSets, the dispatcher does the job of splitting + them. You get exactly one UITouch per call. + - 2. You can *claim* a UITouch by returning YES in ccTouchBegan. Updates of claimed + touches are sent only to the delegate(s) that claimed them. So if you get a move/ + ended/cancelled update you're sure it's your touch. This frees you from doing a + lot of checks when doing multi-touch. + + (The name TargetedTouchDelegate relates to updates "targeting" their specific + handler, without bothering the other handlers.) + @since v0.8 + */ + class CCTargetedTouchDelegate : public CCTouchDelegate + { + public: + CCTargetedTouchDelegate(); + /** Return YES to claim the touch. + @since v0 + */ + virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); + + // optional + virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent); + virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); + virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent); + }; + +/** @brief + This type of delegate is the same one used by CocoaTouch. You will receive all the events (Began,Moved,Ended,Cancelled). + @since v0.8 + */ + class CCStandardTouchDelegate : public CCTouchDelegate + { + public: + CCStandardTouchDelegate(); + // optional + virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent); + virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent); + virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent); + virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent); + }; + +}//namespace cocos2d + diff --git a/tools/tolua++/CCTouchDispatcher.pkg b/tools/tolua++/CCTouchDispatcher.pkg new file mode 100644 index 0000000000..ad35af03bf --- /dev/null +++ b/tools/tolua++/CCTouchDispatcher.pkg @@ -0,0 +1,111 @@ +namespace cocos2d { + +typedef enum +{ + ccTouchSelectorBeganBit = 1 << 0, + ccTouchSelectorMovedBit = 1 << 1, + ccTouchSelectorEndedBit = 1 << 2, + ccTouchSelectorCancelledBit = 1 << 3, + ccTouchSelectorAllBits = ( ccTouchSelectorBeganBit | ccTouchSelectorMovedBit | ccTouchSelectorEndedBit | ccTouchSelectorCancelledBit), +} ccTouchSelectorFlag; + + +enum { + ccTouchBegan, + ccTouchMoved, + ccTouchEnded, + ccTouchCancelled, + + ccTouchMax, +}; + +class CCSet; +class CCEvent; + +struct ccTouchHandlerHelperData { + // we only use the type +// void (StandardTouchDelegate::*touchesSel)(CCSet*, CCEvent*); +// void (TargetedTouchDelegate::*touchSel)(NSTouch*, CCEvent*); + int m_type; +}; + + +class EGLTouchDelegate +{ +public: + void touchesBegan(CCSet* touches, CCEvent* pEvent); + void touchesMoved(CCSet* touches, CCEvent* pEvent) ; + void touchesEnded(CCSet* touches, CCEvent* pEvent) ; + void touchesCancelled(CCSet* touches, CCEvent* pEvent) ; + + ~EGLTouchDelegate() {} +}; + +class CCTouchHandler; +struct _ccCArray; +/** @brief CCTouchDispatcher. + Singleton that handles all the touch events. + The dispatcher dispatches events to the registered TouchHandlers. + There are 2 different type of touch handlers: + - Standard Touch Handlers + - Targeted Touch Handlers + + The Standard Touch Handlers work like the CocoaTouch touch handler: a set of touches is passed to the delegate. + On the other hand, the Targeted Touch Handlers only receive 1 touch at the time, and they can "swallow" touches (avoid the propagation of the event). + + Firstly, the dispatcher sends the received touches to the targeted touches. + These touches can be swallowed by the Targeted Touch Handlers. If there are still remaining touches, then the remaining touches will be sent + to the Standard Touch Handlers. + + @since v0.8.0 + */ +class CCTouchDispatcher : public CCObject, public EGLTouchDelegate +{ + + ~CCTouchDispatcher(); + bool init(void); + CCTouchDispatcher(); + + + /** Whether or not the events are going to be dispatched. Default: true */ + bool isDispatchEvents(void); + void setDispatchEvents(bool bDispatchEvents); + + /** Adds a standard touch delegate to the dispatcher's list. + See StandardTouchDelegate description. + IMPORTANT: The delegate will be retained. + */ + void addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority); + + /** Adds a targeted touch delegate to the dispatcher's list. + See TargetedTouchDelegate description. + IMPORTANT: The delegate will be retained. + */ + void addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches); + + /** Removes a touch delegate. + The delegate will be released + */ + void removeDelegate(CCTouchDelegate *pDelegate); + + /** Removes all touch delegates, releasing all the delegates */ + void removeAllDelegates(void); + + /** Changes the priority of a previously added delegate. The lower the number, + the higher the priority */ + void setPriority(int nPriority, CCTouchDelegate *pDelegate); + + void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex); + + void touchesBegan(CCSet* touches, CCEvent* pEvent); + void touchesMoved(CCSet* touches, CCEvent* pEvent); + void touchesEnded(CCSet* touches, CCEvent* pEvent); + void touchesCancelled(CCSet* touches, CCEvent* pEvent); + + + /** singleton of the CCTouchDispatcher */ + static CCTouchDispatcher* sharedDispatcher(); + +}; +}//namespace cocos2d + diff --git a/tools/tolua++/CCTransition.pkg b/tools/tolua++/CCTransition.pkg new file mode 100644 index 0000000000..658151894f --- /dev/null +++ b/tools/tolua++/CCTransition.pkg @@ -0,0 +1,460 @@ + +namespace cocos2d { + +//static creation function macro +//c/c++ don't support object creation of using class name +//so, all classes need creation method. + + + +/** Orientation Type used by some transitions +*/ +typedef enum { + /// An horizontal orientation where the Left is nearer + kOrientationLeftOver = 0, + /// An horizontal orientation where the Right is nearer + kOrientationRightOver = 1, + /// A vertical orientation where the Up is nearer + kOrientationUpOver = 0, + /// A vertical orientation where the Bottom is nearer + kOrientationDownOver = 1, +} tOrientation; + +/** @brief Base class for CCTransition scenes +*/ +class CCTransitionScene : public CCScene +{ + + CCTransitionScene(); + ~CCTransitionScene(); + void draw(); + void onEnter(); + void onExit(); + void cleanup(); + + /** creates a base transition with duration and incoming scene */ + static CCTransitionScene * transitionWithDuration(ccTime t, CCScene *scene); + + /** initializes a transition with duration and incoming scene */ + bool initWithDuration(ccTime t,CCScene* scene); + + /** called after the transition finishes */ + void finish(void); + + /** used by some transitions to hide the outter scene */ + void hideOutShowIn(void); + + + +}; + +/** @brief A CCTransition that supports orientation like. +* Possible orientation: LeftOver, RightOver, UpOver, DownOver +*/ +class CCTransitionSceneOriented : public CCTransitionScene +{ + + CCTransitionSceneOriented(); + ~CCTransitionSceneOriented(); + + /** creates a base transition with duration and incoming scene */ + static CCTransitionSceneOriented * transitionWithDuration(ccTime t,CCScene* scene, tOrientation orientation); + /** initializes a transition with duration and incoming scene */ + bool initWithDuration(ccTime t,CCScene* scene,tOrientation orientation); +}; + +/** @brief CCTransitionRotoZoom: +Rotate and zoom out the outgoing scene, and then rotate and zoom in the incoming +*/ +class CCTransitionRotoZoom : public CCTransitionScene +{ + + CCTransitionRotoZoom(); + ~CCTransitionRotoZoom(); + void onEnter(); + static CCTransitionRotoZoom* transitionWithDuration(ccTime t, CCScene* scene); + +}; + +/** @brief CCTransitionJumpZoom: +Zoom out and jump the outgoing scene, and then jump and zoom in the incoming +*/ +class CCTransitionJumpZoom : public CCTransitionScene +{ + CCTransitionJumpZoom(); + ~CCTransitionJumpZoom(); + void onEnter(); + static CCTransitionJumpZoom* transitionWithDuration(ccTime t, CCScene* scene); + +}; + +/** @brief CCTransitionMoveInL: +Move in from to the left the incoming scene. +*/ +class CCTransitionMoveInL : public CCTransitionScene, public CCTransitionEaseScene +{ +public: + CCTransitionMoveInL(); + ~CCTransitionMoveInL(); + /** initializes the scenes */ + void initScenes(void); + /** returns the action that will be performed */ + CCActionInterval* action(void); + + CCActionInterval* easeActionWithAction(CCActionInterval * action); + + void onEnter(); + static CCTransitionMoveInL* transitionWithDuration(ccTime t, CCScene* scene); +}; + +/** @brief CCTransitionMoveInR: +Move in from to the right the incoming scene. +*/ +class CCTransitionMoveInR : public CCTransitionMoveInL +{ +public: + CCTransitionMoveInR(); + ~CCTransitionMoveInR(); + void initScenes(); + static CCTransitionMoveInR* transitionWithDuration(ccTime t, CCScene* scene); +}; + +/** @brief CCTransitionMoveInT: +Move in from to the top the incoming scene. +*/ +class CCTransitionMoveInT : public CCTransitionMoveInL +{ +public: + CCTransitionMoveInT(); + ~CCTransitionMoveInT(); + void initScenes(); + static CCTransitionMoveInT* transitionWithDuration(ccTime t, CCScene* scene); +}; + +/** @brief CCTransitionMoveInB: +Move in from to the bottom the incoming scene. +*/ +class CCTransitionMoveInB : public CCTransitionMoveInL +{ + CCTransitionMoveInB(); + ~CCTransitionMoveInB(); + void initScenes(); + static CCTransitionMoveInB* transitionWithDuration(ccTime t, CCScene* scene); + +}; + +/** @brief CCTransitionSlideInL: +Slide in the incoming scene from the left border. +*/ +class CCTransitionSlideInL : public CCTransitionScene, public CCTransitionEaseScene +{ + + CCTransitionSlideInL(); + ~CCTransitionSlideInL(); + + /** initializes the scenes */ + void initScenes(void); + /** returns the action that will be performed by the incomming and outgoing scene */ + CCActionInterval* action(void); + + void onEnter(); + + CCActionInterval* easeActionWithAction(CCActionInterval * action); + + + static CCTransitionSlideInL* transitionWithDuration(ccTime t, CCScene* scene); + +}; + +/** @brief CCTransitionSlideInR: +Slide in the incoming scene from the right border. +*/ +class CCTransitionSlideInR : public CCTransitionSlideInL +{ +public: + CCTransitionSlideInR(); + ~CCTransitionSlideInR(); + + /** initializes the scenes */ + void initScenes(void); + /** returns the action that will be performed by the incomming and outgoing scene */ + CCActionInterval* action(void); + static CCTransitionSlideInR* transitionWithDuration(ccTime t, CCScene* scene); + + +}; + +/** @brief CCTransitionSlideInB: +Slide in the incoming scene from the bottom border. +*/ +class CCTransitionSlideInB : public CCTransitionSlideInL +{ + + CCTransitionSlideInB(); + ~CCTransitionSlideInB(); + + /** initializes the scenes */ + void initScenes(void); + /** returns the action that will be performed by the incomming and outgoing scene */ + CCActionInterval* action(void); + + static CCTransitionSlideInB* transitionWithDuration(ccTime t, CCScene* scene); + + +}; + +/** @brief CCTransitionSlideInT: +Slide in the incoming scene from the top border. +*/ +class CCTransitionSlideInT : public CCTransitionSlideInL +{ + + CCTransitionSlideInT(); + ~CCTransitionSlideInT(); + + /** initializes the scenes */ + void initScenes(void); + /** returns the action that will be performed by the incomming and outgoing scene */ + CCActionInterval* action(void); + static CCTransitionSlideInT* transitionWithDuration(ccTime t, CCScene* scene); + +}; + +/** +@brief Shrink the outgoing scene while grow the incoming scene +*/ +class CCTransitionShrinkGrow : public CCTransitionScene , public CCTransitionEaseScene +{ + + CCTransitionShrinkGrow(); + ~CCTransitionShrinkGrow(); + + void onEnter(); + CCActionInterval* easeActionWithAction(CCActionInterval * action); + static CCTransitionShrinkGrow* transitionWithDuration(ccTime t, CCScene* scene); + +}; + +/** @brief CCTransitionFlipX: +Flips the screen horizontally. +The front face is the outgoing scene and the back face is the incoming scene. +*/ +class CCTransitionFlipX : public CCTransitionSceneOriented +{ + CCTransitionFlipX(); + ~CCTransitionFlipX(); + void onEnter(); + + static CCTransitionFlipX* transitionWithDuration(ccTime t, CCScene* s, tOrientation o = kOrientationRightOver); +}; + +/** @brief CCTransitionFlipY: +Flips the screen vertically. +The front face is the outgoing scene and the back face is the incoming scene. +*/ +class CCTransitionFlipY : public CCTransitionSceneOriented +{ + CCTransitionFlipY(); + ~CCTransitionFlipY(); + + void onEnter(); + + static CCTransitionFlipY* transitionWithDuration(ccTime t, CCScene* s, tOrientation o = kOrientationUpOver); +}; + +/** @brief CCTransitionFlipAngular: +Flips the screen half horizontally and half vertically. +The front face is the outgoing scene and the back face is the incoming scene. +*/ +class CCTransitionFlipAngular : public CCTransitionSceneOriented +{ + CCTransitionFlipAngular(); + ~CCTransitionFlipAngular(); + + void onEnter(); + + static CCTransitionFlipAngular* transitionWithDuration(ccTime t, CCScene* s, tOrientation o = kOrientationRightOver); +}; + +/** @brief CCTransitionZoomFlipX: +Flips the screen horizontally doing a zoom out/in +The front face is the outgoing scene and the back face is the incoming scene. +*/ +class CCTransitionZoomFlipX : public CCTransitionSceneOriented +{ + CCTransitionZoomFlipX(); + ~CCTransitionZoomFlipX(); + + void onEnter(); + + static CCTransitionZoomFlipX* transitionWithDuration(ccTime t, CCScene* s, tOrientation o = kOrientationRightOver); +}; + +/** @brief CCTransitionZoomFlipY: +Flips the screen vertically doing a little zooming out/in +The front face is the outgoing scene and the back face is the incoming scene. +*/ +class CCTransitionZoomFlipY : public CCTransitionSceneOriented +{ + CCTransitionZoomFlipY(); + ~CCTransitionZoomFlipY(); + + void onEnter(); + + static CCTransitionZoomFlipY* transitionWithDuration(ccTime t, CCScene* s, tOrientation o = kOrientationUpOver); +}; + +/** @brief CCTransitionZoomFlipAngular: +Flips the screen half horizontally and half vertically doing a little zooming out/in. +The front face is the outgoing scene and the back face is the incoming scene. +*/ +class CCTransitionZoomFlipAngular : public CCTransitionSceneOriented +{ + CCTransitionZoomFlipAngular(); + ~CCTransitionZoomFlipAngular(); + + void onEnter(); + + static CCTransitionZoomFlipAngular* transitionWithDuration(ccTime t, CCScene* s, tOrientation o = kOrientationRightOver); +}; + +/** @brief CCTransitionFade: +Fade out the outgoing scene and then fade in the incoming scene.''' +*/ +class CCTransitionFade : public CCTransitionScene +{ + CCTransitionFade(); + ~CCTransitionFade(); + + /** creates the transition with a duration and with an RGB color + * Example: FadeTransition::transitionWithDuration(2, scene, ccc3(255,0,0); // red color + */ + static CCTransitionFade* transitionWithDuration(ccTime duration,CCScene* scene, ccColor3B color = ccBLACK); + /** initializes the transition with a duration and with an RGB color */ + bool initWithDuration(ccTime t, CCScene*scene ,ccColor3B color); + + bool initWithDuration(ccTime t,CCScene* scene); + void onEnter(); + void onExit(); +}; + +/** +@brief CCTransitionCrossFade: +Cross fades two scenes using the CCRenderTexture object. +*/ +class CCTransitionCrossFade : public CCTransitionScene +{ + + CCTransitionCrossFade(); + ~CCTransitionCrossFade(); + + void draw(); + void onEnter(); + void onExit(); + static CCTransitionCrossFade * transitionWithDuration(ccTime t, CCScene* scene); + + +}; + +/** @brief CCTransitionTurnOffTiles: +Turn off the tiles of the outgoing scene in random order +*/ +class CCTransitionTurnOffTiles : public CCTransitionScene ,public CCTransitionEaseScene +{ + + CCTransitionTurnOffTiles(); + ~CCTransitionTurnOffTiles(); + + void onEnter(); + CCActionInterval * easeActionWithAction(CCActionInterval * action); + + static CCTransitionTurnOffTiles * transitionWithDuration(ccTime t, CCScene* scene); + +}; + +/** @brief CCTransitionSplitCols: +The odd columns goes upwards while the even columns goes downwards. +*/ +class CCTransitionSplitCols : public CCTransitionScene , public CCTransitionEaseScene +{ + + CCTransitionSplitCols(); + ~CCTransitionSplitCols(); + + CCActionInterval* action(void); + void onEnter(); + CCActionInterval * easeActionWithAction(CCActionInterval * action); + + static CCTransitionSplitCols * transitionWithDuration(ccTime t, CCScene* scene); +}; + +/** @brief CCTransitionSplitRows: +The odd rows goes to the left while the even rows goes to the right. +*/ +class CCTransitionSplitRows : public CCTransitionSplitCols +{ + + CCTransitionSplitRows(); + ~CCTransitionSplitRows(); + + CCActionInterval* action(void); + static CCTransitionSplitRows * transitionWithDuration(ccTime t, CCScene* scene); + +}; + +/** @brief CCTransitionFadeTR: +Fade the tiles of the outgoing scene from the left-bottom corner the to top-right corner. +*/ +class CCTransitionFadeTR : public CCTransitionScene , public CCTransitionEaseScene +{ + + CCTransitionFadeTR(); + ~CCTransitionFadeTR(); + CCActionInterval* actionWithSize(ccGridSize size); + void onEnter(); + CCActionInterval* easeActionWithAction(CCActionInterval * action); + + static CCTransitionFadeTR * transitionWithDuration(ccTime t, CCScene* scene); + + +}; + +/** @brief CCTransitionFadeBL: +Fade the tiles of the outgoing scene from the top-right corner to the bottom-left corner. +*/ +class CCTransitionFadeBL : public CCTransitionFadeTR +{ + + CCTransitionFadeBL(); + ~CCTransitionFadeBL(); + CCActionInterval* actionWithSize(ccGridSize size); + + static CCTransitionFadeBL * transitionWithDuration(ccTime t, CCScene* scene); +}; + +/** @brief CCTransitionFadeUp: +* Fade the tiles of the outgoing scene from the bottom to the top. +*/ +class CCTransitionFadeUp : public CCTransitionFadeTR +{ + + CCTransitionFadeUp(); + ~CCTransitionFadeUp(); + CCActionInterval* actionWithSize(ccGridSize size); + static CCTransitionFadeUp * transitionWithDuration(ccTime t, CCScene* scene); + +}; + +/** @brief CCTransitionFadeDown: +* Fade the tiles of the outgoing scene from the top to the bottom. +*/ +class CCTransitionFadeDown : public CCTransitionFadeTR +{ + CCTransitionFadeDown(); + ~CCTransitionFadeDown(); + CCActionInterval* actionWithSize(ccGridSize size); + + static CCTransitionFadeDown * transitionWithDuration(ccTime t, CCScene* scene); +}; +}//namespace cocos2d + diff --git a/tools/tolua++/CCTransitionPageTurn.pkg b/tools/tolua++/CCTransitionPageTurn.pkg new file mode 100644 index 0000000000..5ec0584d35 --- /dev/null +++ b/tools/tolua++/CCTransitionPageTurn.pkg @@ -0,0 +1,25 @@ +namespace cocos2d { + +class CCTransitionPageTurn : public CCTransitionScene +{ + + CCTransitionPageTurn(); + ~CCTransitionPageTurn(); + + /** + * Creates a base transition with duration and incoming scene. + * If back is true then the effect is reversed to appear as if the incoming + * scene is being turned from left over the outgoing scene. + */ + static CCTransitionPageTurn* transitionWithDuration(ccTime t,CCScene* scene,bool backwards); + + + bool initWithDuration(ccTime t,CCScene* scene,bool backwards); + + CCActionInterval* actionWithSize(ccGridSize vector); + + void onEnter(); + + +}; +}//namespace cocos2d diff --git a/tools/tolua++/CCTransitionRadial.pkg b/tools/tolua++/CCTransitionRadial.pkg new file mode 100644 index 0000000000..7081951786 --- /dev/null +++ b/tools/tolua++/CCTransitionRadial.pkg @@ -0,0 +1,31 @@ +namespace cocos2d { + + +class CCTransitionRadialCCW : public CCTransitionScene +{ + + CCTransitionRadialCCW(){} + ~CCTransitionRadialCCW(){} + + void onEnter(); + void onExit(); + + static CCTransitionRadialCCW* transitionWithDuration(ccTime t, CCScene* scene); + +}; + +/** + @brief A counter colock-wise radial transition to the next scene + */ +class CCTransitionRadialCW : public CCTransitionRadialCCW +{ + + CCTransitionRadialCW(){} + ~CCTransitionRadialCW(){} + static CCTransitionRadialCW* transitionWithDuration(ccTime t, CCScene* scene); + + +}; + +}//namespace cocos2d + diff --git a/tools/tolua++/CCUserDefault.pkg b/tools/tolua++/CCUserDefault.pkg new file mode 100644 index 0000000000..39d381462a --- /dev/null +++ b/tools/tolua++/CCUserDefault.pkg @@ -0,0 +1,29 @@ +namespace cocos2d { + +class CCUserDefault +{ + + ~CCUserDefault(); + + // get value methods + bool getBoolForKey(const char* pKey); + int getIntegerForKey(const char* pKey); + float getFloatForKey(const char* pKey); + double getDoubleForKey(const char* pKey); + std::string getStringForKey(const char* pKey); + + // set value methods + void setBoolForKey(const char* pKey, bool value); + void setIntegerForKey(const char* pKey, int value); + void setFloatForKey(const char* pKey, float value); + void setDoubleForKey(const char* pKey, double value); + void setStringForKey(const char* pKey, std::string value); + + static CCUserDefault* sharedUserDefault(); + static void purgeSharedUserDefault(); + const static std::string& getXMLFilePath(); + +}; + +} + diff --git a/tools/tolua++/Cocos2d.pkg b/tools/tolua++/Cocos2d.pkg new file mode 100644 index 0000000000..5d76cac236 --- /dev/null +++ b/tools/tolua++/Cocos2d.pkg @@ -0,0 +1,119 @@ +$#include "LuaCocos2d.h" +$pfile "CCNode.pkg" + +$pfile "CCObject.pkg" + +$pfile "CCParallaxNode.pkg" + +$pfile "CCPointExtension.pkg" + +$pfile "CCProgressTimer.pkg" + +$pfile "CCRenderTexture.pkg" + +$pfile "CCRibbon.pkg" + +$pfile "CCScene.pkg" + +$pfile "CCScheduler.pkg" + +$pfile "CCSprite.pkg" + +$pfile "CCSpriteBatchNode.pkg" + +$pfile "CCSpriteFrame.pkg" + +$pfile "CCSpriteFrameCache.pkg" + +$pfile "CCSpriteSheet.pkg" + +$pfile "CCString.pkg" + +$pfile "CCTextFieldTTF.pkg" + +$pfile "CCTexture2D.pkg" + +$pfile "CCTextureAtlas.pkg" + +$pfile "CCTextureCache.pkg" + +$pfile "CCTileMapAtlas.pkg" + +$pfile "CCTMXLayer.pkg" + +$pfile "CCTMXObjectGroup.pkg" + +$pfile "CCTMXTiledMap.pkg" + +$pfile "CCTMXXMLParser.pkg" + +$pfile "CCTouch.pkg" + +$pfile "CCTouchDispatcher.pkg" + +$pfile "CCTransition.pkg" + +$pfile "CCTransitionPageTurn.pkg" + +$pfile "CCTransitionRadial.pkg" + +$pfile "ccTypes.pkg" + +$pfile "CCUserDefault.pkg" + +$pfile "CCAccelerometer.pkg" + +$pfile "CCAccelerometerDelegate.pkg" + +$pfile "CCAction.pkg" + +$pfile "CCProtocols.pkg" + +$pfile "selector_protocol.pkg" +$pfile "CCSet.pkg" + +$pfile "CCMutableArray.pkg" +$pfile "CCMutableDictionary.pkg" + + +$pfile "CCTouchDelegateProtocol.pkg" + + + +$pfile "CCActionCamera.pkg" +$pfile "CCActionEase.pkg" +$pfile "CCActionGrid3D.pkg" +$pfile "CCActionGrid.pkg" +$pfile "CCActionInstant.pkg" +$pfile "CCActionInterval.pkg" +$pfile "CCActionManager.pkg" +$pfile "CCActionPageTurn3D.pkg" +$pfile "CCActionProgressTimer.pkg" +$pfile "CCActionTiledGrid.pkg" + +$pfile "CCAnimation.pkg" +$pfile "CCAnimationCache.pkg" +$pfile "CCApplication.pkg" +$pfile "CCArray.pkg" +$pfile "CCAtlasNode.pkg" +$pfile "CCAutoreleasePool.pkg" +$pfile "CCCamera.pkg" +$pfile "ccConfig.pkg" +$pfile "CCDirector.pkg" +$pfile "CCDrawingPrimitives.pkg" +$pfile "CCEGLView.pkg" +$pfile "CCGeometry.pkg" +$pfile "CCGL.pkg" +$pfile "CCIMEDelegate.pkg" +$pfile "CCIMEDispatcher.pkg" +$pfile "CCKeypadDelegate.pkg" +$pfile "CCKeypadDispatcher.pkg" +$pfile "CCLabelAtlas.pkg" +$pfile "CCLabelBMFont.pkg" +$pfile "CCLabelTTF.pkg" +$pfile "CCLayer.pkg" +$pfile "CCMenu.pkg" +$pfile "CCMenuItem.pkg" +$pfile "CCMotionStreak.pkg" + +$pfile "CCCommon.pkg" diff --git a/tools/tolua++/README b/tools/tolua++/README new file mode 100644 index 0000000000..9492d4e09e --- /dev/null +++ b/tools/tolua++/README @@ -0,0 +1,28 @@ +1. The usage of tolua++ + You can use the command to generate the LuaCocos2d.cpp: +tolua++.exe -tCocos2d -o LuaCocos2d.cpp Cocos2d.pkg + +2. Modify the generated file +After you run the command, the generated file under the +directory the same as tolua++.exe. cocos2dx/lua_support/LuaCocos2d.cpp +is generate by this way. But here are some differents between them, because +tolua++.exe generates some error codes about the template. The errors are: + +------------------------------------------------------------------------------------------- + genereated code | correct code | +------------------------------------------------------------------------------------------- +CCMutableArray | cocos2d::CCMutableArray | +------------------------------------------------------------------------------------------- +CCMutableArray | cocos2d::CCMutableArray| +-------------------------------------------------------------------------------------------- +CCMutableArray | cocos2d::CCMutableArray | +-------------------------------------------------------------------------------------------- + +3. The regular to write .pkg +1) enum keeps the same +2) remove CC_DLL for the class defines, pay attention to multi inherites +3) remove inline keyword for declaration and implementation +4) remove public protect and private +5) remove the decalration of class member variable +6) keep static keyword +7) remove memeber functions that declared as private or protected \ No newline at end of file diff --git a/tools/tolua++/ccConfig.pkg b/tools/tolua++/ccConfig.pkg new file mode 100644 index 0000000000..776244a5a7 --- /dev/null +++ b/tools/tolua++/ccConfig.pkg @@ -0,0 +1,76 @@ + +#include "CCPlatformConfig.h" + +#define CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 0 + + +#define CC_FONT_LABEL_SUPPORT 1 + + +#define CC_DIRECTOR_FAST_FPS 1 + +#define CC_DIRECTOR_FPS_INTERVAL (0.5f) + + + #define CC_DIRECTOR_DISPATCH_FAST_EVENTS 0 + + +#define CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD 1 + +#define CC_COCOSNODE_RENDER_SUBPIXEL 1 + + +#define CC_SPRITEBATCHNODE_RENDER_SUBPIXEL 1 + + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_AIRPLAY) +#define CC_USES_VBO 0 +#else +#define CC_USES_VBO 1 +#endif + + +#define CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 1 + +#define CC_OPTIMIZE_BLEND_FUNC_FOR_PREMULTIPLIED_ALPHA 1 + + +#define CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP 0 + + +#define CC_TEXTURE_NPOT_SUPPORT 0 + + +#define CC_RETINA_DISPLAY_SUPPORT 1 + + +//#define CC_RETINA_DISPLAY_FILENAME_SUFFIX "-hd" + + +#define CC_USE_RGBA32_LABELS_ON_NEON_ARCH 0 + + +#define CC_SPRITE_DEBUG_DRAW 0 + + +#define CC_SPRITEBATCHNODE_DEBUG_DRAW 0 + + +#define CC_BITMAPFONTATLAS_DEBUG_DRAW 0 + + +#define CC_LABELATLAS_DEBUG_DRAW 0 + + +#define CC_ENABLE_PROFILERS 0 + + +#define CC_COMPATIBILITY_WITH_0_8 0 + +#if CC_RETINA_DISPLAY_SUPPORT +#define CC_IS_RETINA_DISPLAY_SUPPORTED 1 +#else +#define CC_IS_RETINA_DISPLAY_SUPPORTED 0 +#endif + + diff --git a/tools/tolua++/ccTypes.pkg b/tools/tolua++/ccTypes.pkg new file mode 100644 index 0000000000..8840eb3138 --- /dev/null +++ b/tools/tolua++/ccTypes.pkg @@ -0,0 +1,231 @@ +typedef unsigned char GLubyte; +typedef int GLint; +typedef int GLsizei; +typedef unsigned char GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef float GLfloat; +namespace cocos2d { + +/** RGB color composed of bytes 3 bytes +@since v0.8 + */ + + +typedef float ccTime; +typedef struct _ccColor3B +{ + GLubyte r; + GLubyte g; + GLubyte b; +} ccColor3B; + +//! helper macro that creates an ccColor3B type +static ccColor3B ccc3(const GLubyte r, const GLubyte g, const GLubyte b); +/* +//ccColor3B predefined colors +//! White color (255,255,255) +const ccColor3B ccWHITE; +//! Yellow color (255,255,0) +const ccColor3B ccYELLOW; +//! Blue color (0,0,255) +const ccColor3B ccBLUE; +//! Green Color (0,255,0) +const ccColor3B ccGREEN; +//! Red Color (255,0,0,) +const ccColor3B ccRED; +//! Magenta Color (255,0,255) +const ccColor3B ccMAGENTA; +//! Black Color (0,0,0) +const ccColor3B ccBLACK; +//! Orange Color (255,127,0) +const ccColor3B ccORANGE; +//! Gray Color (166,166,166) +const ccColor3B ccGRAY; +*/ + +/** RGBA color composed of 4 bytes +@since v0.8 +*/ +typedef struct _ccColor4B +{ + GLubyte r; + GLubyte g; + GLubyte b; + GLubyte a; +} ccColor4B; +//! helper macro that creates an ccColor4B type +static ccColor4B ccc4(const GLubyte r, const GLubyte g, const GLubyte b, const GLubyte o); + + +/** RGBA color composed of 4 floats +@since v0.8 +*/ +typedef struct _ccColor4F { + GLfloat r; + GLfloat g; + GLfloat b; + GLfloat a; +} ccColor4F; + +/** Returns a ccColor4F from a ccColor3B. Alpha will be 1. + @since v0.99.1 + */ +static ccColor4F ccc4FFromccc3B(ccColor3B c); +/** Returns a ccColor4F from a ccColor4B. + @since v0.99.1 + */ +static ccColor4F ccc4FFromccc4B(ccColor4B c); + +/** returns YES if both ccColor4F are equal. Otherwise it returns NO. + @since v0.99.1 + */ +static bool ccc4FEqual(ccColor4F a, ccColor4F b); + +/** A vertex composed of 2 floats: x, y + @since v0.8 + */ +typedef struct _ccVertex2F +{ + GLfloat x; + GLfloat y; +} ccVertex2F; + +static ccVertex2F vertex2(const float x, const float y); + + +/** A vertex composed of 2 floats: x, y + @since v0.8 + */ +typedef struct _ccVertex3F +{ + GLfloat x; + GLfloat y; + GLfloat z; +} ccVertex3F; + +static ccVertex3F vertex3(const float x, const float y, const float z); + +/** A texcoord composed of 2 floats: u, y + @since v0.8 + */ +typedef struct _ccTex2F { + GLfloat u; + GLfloat v; +} ccTex2F; + +static ccTex2F tex2(const float u, const float v); + + + +//! Point Sprite component +typedef struct _ccPointSprite +{ + ccVertex2F pos; // 8 bytes + ccColor4F colors; // 16 bytes + GLfloat size; // 4 bytes +} ccPointSprite; + +//! A 2D Quad. 4 * 2 floats +typedef struct _ccQuad2 { + ccVertex2F tl; + ccVertex2F tr; + ccVertex2F bl; + ccVertex2F br; +} ccQuad2; + + +//! A 3D Quad. 4 * 3 floats +typedef struct _ccQuad3 { + ccVertex3F bl; + ccVertex3F br; + ccVertex3F tl; + ccVertex3F tr; +} ccQuad3; + +//! A 2D grid size +typedef struct _ccGridSize +{ + int x; + int y; +} ccGridSize; + +//! helper function to create a ccGridSize +static ccGridSize ccg(const int x, const int y); + +//! a Point with a vertex point, a tex coord point and a color 4F +typedef struct _ccV2F_C4F_T2F +{ + //! vertices (2F) + ccVertex2F vertices; + //! colors (4F) + ccColor4F colors; + //! tex coords (2F) + ccTex2F texCoords; +} ccV2F_C4F_T2F; + +//! a Point with a vertex point, a tex coord point and a color 4B +typedef struct _ccV3F_C4B_T2F +{ + //! vertices (3F) + ccVertex3F vertices; // 12 bytes +// char __padding__[4]; + + //! colors (4B) + ccColor4B colors; // 4 bytes +// char __padding2__[4]; + + // tex coords (2F) + ccTex2F texCoords; // 8 byts +} ccV3F_C4B_T2F; + +//! 4 ccVertex3FTex2FColor4B +typedef struct _ccV3F_C4B_T2F_Quad +{ + //! top left + ccV3F_C4B_T2F tl; + //! bottom left + ccV3F_C4B_T2F bl; + //! top right + ccV3F_C4B_T2F tr; + //! bottom right + ccV3F_C4B_T2F br; +} ccV3F_C4B_T2F_Quad; + +//! 4 ccVertex2FTex2FColor4F Quad +typedef struct _ccV2F_C4F_T2F_Quad +{ + //! bottom left + ccV2F_C4F_T2F bl; + //! bottom right + ccV2F_C4F_T2F br; + //! top left + ccV2F_C4F_T2F tl; + //! top right + ccV2F_C4F_T2F tr; +} ccV2F_C4F_T2F_Quad; + +//! Blend Function used for textures +typedef struct _ccBlendFunc +{ + //! source blend function + GLenum src; + //! destination blend function + GLenum dst; +} ccBlendFunc; + +//! delta time type +//! if you want more resolution redefine it as a double + +//typedef double ccTime; + +typedef enum +{ + CCTextAlignmentLeft, + CCTextAlignmentCenter, + CCTextAlignmentRight, +} CCTextAlignment; + +}//namespace cocos2d + + diff --git a/tools/tolua++/selector_protocol.pkg b/tools/tolua++/selector_protocol.pkg new file mode 100644 index 0000000000..9cc20af7f5 --- /dev/null +++ b/tools/tolua++/selector_protocol.pkg @@ -0,0 +1,57 @@ +namespace cocos2d { +class CCNode; +class CCEvent; + +class CCScriptSelector +{ + std::string m_scriptFunc[ccSEL_Max]; + //szType ={"SEL_Update", "SEL_Tick", "SEL_CallFunc", "SEL_CallFuncN", \ + // "SEL_CallFuncND", "SEL_CallFuncO", "SEL_MenuHandler", "SEL_EventHandler"}; + + bool registerScriptSelector(const char* szType, const char* szSeletor); +}; +class SelectorProtocol:public CCScriptSelector +{ +public: + SelectorProtocol(); + void update(ccTime dt); + void tick(ccTime dt); + void callfunc(); + void callfunc(CCNode* pSender); + void callfunc(CCNode* pSender, void* pData); + void menuHandler(CCObject* pSender); + void eventHandler(CCEvent* pEvent); + + // the child call responding retain/release function + void selectorProtocolRetain(void); + void selectorProtocolRelease(void); +}; +/* +class CCNode; +typedef void (SelectorProtocol::*SEL_SCHEDULE)(ccTime); + +typedef void (SelectorProtocol::*SEL_CallFunc)(); +typedef void (SelectorProtocol::*SEL_CallFuncN)(CCNode*); +typedef void (SelectorProtocol::*SEL_CallFuncND)(CCNode*, void*); +typedef void (SelectorProtocol::*SEL_CallFuncO)(CCObject*); +typedef void (SelectorProtocol::*SEL_MenuHandler)(CCObject*); +typedef void (SelectorProtocol::*SEL_EventHandler)(CCEvent*); + +// #define schedule_selector(_SELECTOR) (SEL_SCHEDULE)(*((SEL_SCHEDULE*)(&(&_SELECTOR))) ) +// #define callfunc_selector(_SELECTOR) (SEL_CallFunc)(*((SEL_CallFunc*)(&(&_SELECTOR))) ) +// #define callfuncN_selector(_SELECTOR) (SEL_CallFuncN)(*((SEL_CallFuncN*)(&(&_SELECTOR))) ) +// #define callfuncND_selector(_SELECTOR) (SEL_CallFuncND)(*((SEL_CallFuncND*)(&(&_SELECTOR))) ) +// #define menu_selector(_SELECTOR) (SEL_MenuHandler)(*((SEL_MenuHandler*)(&(&_SELECTOR))) + + #define schedule_selector(_SELECTOR) (SEL_SCHEDULE)(&_SELECTOR) + #define callfunc_selector(_SELECTOR) (SEL_CallFunc)(&_SELECTOR) + #define callfuncN_selector(_SELECTOR) (SEL_CallFuncN)(&_SELECTOR) + #define callfuncND_selector(_SELECTOR) (SEL_CallFuncND)(&_SELECTOR) + #define callfuncO_selector(_SELECTOR) (SEL_CallFuncO)(&_SELECTOR) + #define menu_selector(_SELECTOR) (SEL_MenuHandler)(&_SELECTOR) + #define event_selector(_SELECTOR) (SEL_EventHandler)(&_SELECTOR) + + */ +}//namespace cocos2d + +