64 changed files with 22625 additions and 21 deletions
@ -1,46 +1,53 @@ |
|||
CC=gcc |
|||
CFLAGS=-g -Isrc/lib/lua -Iinclude |
|||
SRCDIR=src/c |
|||
CFLAGS=-g -std=c99 -Isrc/lib/lua -Iinclude |
|||
|
|||
BUILD = bin/ |
|||
SOURCE = src/c/ |
|||
|
|||
CORELUA = src/lua/core |
|||
LIBS=-llua |
|||
LIBS=-lm |
|||
|
|||
GENERATED=include/luares.h src/c/gen/luares.c |
|||
LUAPARAMS = $(CORELUA) include/luares.h src/c/gen/luares.c lua_ |
|||
LFLAGS=$(LIBS) |
|||
OBJ=\
|
|||
$(SRCDIR)/main.o \ |
|||
$(SRCDIR)/gen/luares.o |
|||
LDFLAGS=-static |
|||
|
|||
SRCDIRECTORIES = $(shell find $(SOURCE) -type d) |
|||
BUILDDIRECTORIES = $(patsubst $(SOURCE)%, $(BUILD)%, $(SRCDIRECTORIES)) |
|||
|
|||
CFILES = $(shell find $(SOURCE) -type f -name '*.c') |
|||
OBJECTS := $(patsubst $(SOURCE)%.c, $(BUILD)%.c.o, $(CFILES)) |
|||
|
|||
#Rules
|
|||
#Prepare
|
|||
$(BUILDDIRECTORIES): |
|||
mkdir $@ |
|||
|
|||
#Clean
|
|||
|
|||
#Build
|
|||
all: smallclean $(BUILDDIRECTORIES) luaresources lupi |
|||
all: smallclean $(BUILDDIRECTORIES) luaresources $(BUILD)lupi |
|||
|
|||
smallclean: |
|||
find . -name '*~' -type f -exec rm {} \; |
|||
|
|||
build: clean all |
|||
|
|||
lupi: $(OBJ) |
|||
$(CC) $(LFLAGS) $^ -o $@ |
|||
$(BUILD)lupi: $(OBJECTS) |
|||
$(CC) $(LDFLAGS) $(OBJECTS) -o $@ $(LIBS) |
|||
|
|||
$(OBJ): %.o: %.c |
|||
$(CC) -c $(CFLAGS) $< -o $@ |
|||
$(BUILD)%.c.o: $(SOURCE)%.c $(BUILD) |
|||
$(CC) -c $(CFLAGS) -I src/c -I src/c/lib/lua $< -o $@ |
|||
|
|||
#Resources
|
|||
luaresources: cleanresourcues |
|||
scripts/txt2c $(LUAPARAMS) |
|||
|
|||
$(BUILDDIRECTORIES): |
|||
mkdir $@ |
|||
|
|||
#Clean rules
|
|||
cleanresourcues: |
|||
-rm -f $(GENERATED) |
|||
|
|||
mkdir -p src/c/gen/ |
|||
touch src/c/gen/luares.c |
|||
touch include/luares.h |
|||
|
|||
clean : cleanresourcues |
|||
-rm -f $(OBJ) |
|||
clean: cleanresourcues |
|||
-rm -rf $(BUILD) |
|||
|
@ -0,0 +1,4 @@ |
|||
#ifndef LUARES_H |
|||
#define LUARES_H |
|||
extern char lua_init[]; |
|||
#endif |
File diff suppressed because it is too large
@ -0,0 +1,24 @@ |
|||
/*
|
|||
** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $ |
|||
** Auxiliary functions from Lua API |
|||
** See Copyright Notice in lua.h |
|||
*/ |
|||
|
|||
#ifndef lapi_h |
|||
#define lapi_h |
|||
|
|||
|
|||
#include "llimits.h" |
|||
#include "lstate.h" |
|||
|
|||
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ |
|||
"stack overflow");} |
|||
|
|||
#define adjustresults(L,nres) \ |
|||
{ if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } |
|||
|
|||
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ |
|||
"not enough elements in the stack") |
|||
|
|||
|
|||
#endif |
File diff suppressed because it is too large
@ -0,0 +1,256 @@ |
|||
/*
|
|||
** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $ |
|||
** Auxiliary functions for building Lua libraries |
|||
** See Copyright Notice in lua.h |
|||
*/ |
|||
|
|||
|
|||
#ifndef lauxlib_h |
|||
#define lauxlib_h |
|||
|
|||
|
|||
#include <stddef.h> |
|||
#include <stdio.h> |
|||
|
|||
#include "lua.h" |
|||
|
|||
|
|||
|
|||
/* extra error code for 'luaL_load' */ |
|||
#define LUA_ERRFILE (LUA_ERRERR+1) |
|||
|
|||
|
|||
typedef struct luaL_Reg { |
|||
const char *name; |
|||
lua_CFunction func; |
|||
} luaL_Reg; |
|||
|
|||
|
|||
#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) |
|||
|
|||
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); |
|||
#define luaL_checkversion(L) \ |
|||
luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) |
|||
|
|||
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 const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); |
|||
LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); |
|||
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, |
|||
size_t *l); |
|||
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, |
|||
const char *def, size_t *l); |
|||
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); |
|||
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); |
|||
|
|||
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); |
|||
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, |
|||
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 arg, int t); |
|||
LUALIB_API void (luaL_checkany) (lua_State *L, int arg); |
|||
|
|||
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); |
|||
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); |
|||
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, 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 arg, const char *def, |
|||
const char *const lst[]); |
|||
|
|||
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); |
|||
LUALIB_API int (luaL_execresult) (lua_State *L, int stat); |
|||
|
|||
/* predefined references */ |
|||
#define LUA_NOREF (-2) |
|||
#define LUA_REFNIL (-1) |
|||
|
|||
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_loadfilex) (lua_State *L, const char *filename, |
|||
const char *mode); |
|||
|
|||
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) |
|||
|
|||
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, |
|||
const char *name, const char *mode); |
|||
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); |
|||
|
|||
LUALIB_API lua_State *(luaL_newstate) (void); |
|||
|
|||
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); |
|||
|
|||
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, |
|||
const char *r); |
|||
|
|||
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); |
|||
|
|||
LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); |
|||
|
|||
LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, |
|||
const char *msg, int level); |
|||
|
|||
LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, |
|||
lua_CFunction openf, int glb); |
|||
|
|||
/*
|
|||
** =============================================================== |
|||
** some useful macros |
|||
** =============================================================== |
|||
*/ |
|||
|
|||
|
|||
#define luaL_newlibtable(L,l) \ |
|||
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) |
|||
|
|||
#define luaL_newlib(L,l) \ |
|||
(luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) |
|||
|
|||
#define luaL_argcheck(L, cond,arg,extramsg) \ |
|||
((void)((cond) || luaL_argerror(L, (arg), (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_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))) |
|||
|
|||
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) |
|||
|
|||
|
|||
/*
|
|||
** {====================================================== |
|||
** Generic Buffer manipulation |
|||
** ======================================================= |
|||
*/ |
|||
|
|||
typedef struct luaL_Buffer { |
|||
char *b; /* buffer address */ |
|||
size_t size; /* buffer size */ |
|||
size_t n; /* number of characters in buffer */ |
|||
lua_State *L; |
|||
char initb[LUAL_BUFFERSIZE]; /* initial buffer */ |
|||
} luaL_Buffer; |
|||
|
|||
|
|||
#define luaL_addchar(B,c) \ |
|||
((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ |
|||
((B)->b[(B)->n++] = (c))) |
|||
|
|||
#define luaL_addsize(B,s) ((B)->n += (s)) |
|||
|
|||
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); |
|||
LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); |
|||
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); |
|||
LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); |
|||
LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); |
|||
|
|||
#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) |
|||
|
|||
/* }====================================================== */ |
|||
|
|||
|
|||
|
|||
/*
|
|||
** {====================================================== |
|||
** File handles for IO library |
|||
** ======================================================= |
|||
*/ |
|||
|
|||
/*
|
|||
** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and |
|||
** initial structure 'luaL_Stream' (it may contain other fields |
|||
** after that initial structure). |
|||
*/ |
|||
|
|||
#define LUA_FILEHANDLE "FILE*" |
|||
|
|||
|
|||
typedef struct luaL_Stream { |
|||
FILE *f; /* stream (NULL for incompletely created streams) */ |
|||
lua_CFunction closef; /* to close stream (NULL for closed streams) */ |
|||
} luaL_Stream; |
|||
|
|||
/* }====================================================== */ |
|||
|
|||
|
|||
|
|||
/* compatibility with old module system */ |
|||
#if defined(LUA_COMPAT_MODULE) |
|||
|
|||
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname, |
|||
int sizehint); |
|||
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, |
|||
const luaL_Reg *l, int nup); |
|||
|
|||
#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) |
|||
|
|||
#endif |
|||
|
|||
|
|||
/*
|
|||
** {================================================================== |
|||
** "Abstraction Layer" for basic report of messages and errors |
|||
** =================================================================== |
|||
*/ |
|||
|
|||
/* print a string */ |
|||
#if !defined(lua_writestring) |
|||
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) |
|||
#endif |
|||
|
|||
/* print a newline and flush the output */ |
|||
#if !defined(lua_writeline) |
|||
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) |
|||
#endif |
|||
|
|||
/* print an error message */ |
|||
#if !defined(lua_writestringerror) |
|||
#define lua_writestringerror(s,p) \ |
|||
(fprintf(stderr, (s), (p)), fflush(stderr)) |
|||
#endif |
|||
|
|||
/* }================================================================== */ |
|||
|
|||
|
|||
/*
|
|||
** {============================================================ |
|||
** Compatibility with deprecated conversions |
|||
** ============================================================= |
|||
*/ |
|||
#if defined(LUA_COMPAT_APIINTCASTS) |
|||
|
|||
#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) |
|||
#define luaL_optunsigned(L,a,d) \ |
|||
((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) |
|||
|
|||
#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))) |
|||
|
|||
#endif |
|||
/* }============================================================ */ |
|||
|
|||
|
|||
|
|||
#endif |
|||
|
|||
|
@ -0,0 +1,499 @@ |
|||
/*
|
|||
** $Id: lbaselib.c,v 1.312 2015/10/29 15:21:04 roberto Exp $ |
|||
** Basic library |
|||
** See Copyright Notice in lua.h |
|||
*/ |
|||
|
|||
#define lbaselib_c |
|||
#define LUA_LIB |
|||
|
|||
#include "lprefix.h" |
|||
|
|||
|
|||
#include <ctype.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#include "lua.h" |
|||
|
|||
#include "lauxlib.h" |
|||
#include "lualib.h" |
|||
|
|||
|
|||
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; |
|||
size_t l; |
|||
lua_pushvalue(L, -1); /* function to be called */ |
|||
lua_pushvalue(L, i); /* value to print */ |
|||
lua_call(L, 1, 1); |
|||
s = lua_tolstring(L, -1, &l); /* get result */ |
|||
if (s == NULL) |
|||
return luaL_error(L, "'tostring' must return a string to 'print'"); |
|||
if (i>1) lua_writestring("\t", 1); |
|||
lua_writestring(s, l); |
|||
lua_pop(L, 1); /* pop result */ |
|||
} |
|||
lua_writeline(); |
|||
return 0; |
|||
} |
|||
|
|||
|
|||
#define SPACECHARS " \f\n\r\t\v" |
|||
|
|||
static const char *b_str2int (const char *s, int base, lua_Integer *pn) { |
|||
lua_Unsigned n = 0; |
|||
int neg = 0; |
|||
s += strspn(s, SPACECHARS); /* skip initial spaces */ |
|||
if (*s == '-') { s++; neg = 1; } /* handle signal */ |
|||
else if (*s == '+') s++; |
|||
if (!isalnum((unsigned char)*s)) /* no digit? */ |
|||
return NULL; |
|||
do { |
|||
int digit = (isdigit((unsigned char)*s)) ? *s - '0' |
|||
: (toupper((unsigned char)*s) - 'A') + 10; |
|||
if (digit >= base) return NULL; /* invalid numeral */ |
|||
n = n * base + digit; |
|||
s++; |
|||
} while (isalnum((unsigned char)*s)); |
|||
s += strspn(s, SPACECHARS); /* skip trailing spaces */ |
|||
*pn = (lua_Integer)((neg) ? (0u - n) : n); |
|||
return s; |
|||
} |
|||
|
|||
|
|||
static int luaB_tonumber (lua_State *L) { |
|||
if (lua_isnoneornil(L, 2)) { /* standard conversion? */ |
|||
luaL_checkany(L, 1); |
|||
if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ |
|||
lua_settop(L, 1); /* yes; return it */ |
|||
return 1; |
|||
} |
|||
else { |
|||
size_t l; |
|||
const char *s = lua_tolstring(L, 1, &l); |
|||
if (s != NULL && lua_stringtonumber(L, s) == l + 1) |
|||
return 1; /* successful conversion to number */ |
|||
/* else not a number */ |
|||
} |
|||
} |
|||
else { |
|||
size_t l; |
|||
const char *s; |
|||
lua_Integer n = 0; /* to avoid warnings */ |
|||
lua_Integer base = luaL_checkinteger(L, 2); |
|||
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ |
|||
s = lua_tolstring(L, 1, &l); |
|||
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); |
|||
if (b_str2int(s, (int)base, &n) == s + l) { |
|||
lua_pushinteger(L, n); |
|||
return 1; |
|||
} /* else not a number */ |
|||
} /* else not a number */ |
|||
lua_pushnil(L); /* not a number */ |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static int luaB_error (lua_State *L) { |
|||
int level = (int)luaL_optinteger(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") != LUA_TNIL) |
|||
return luaL_error(L, "cannot change a protected metatable"); |
|||
lua_settop(L, 2); |
|||
lua_setmetatable(L, 1); |
|||
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_rawlen (lua_State *L) { |
|||
int t = lua_type(L, 1); |
|||
luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, |
|||
"table or string expected"); |
|||
lua_pushinteger(L, lua_rawlen(L, 1)); |
|||
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_collectgarbage (lua_State *L) { |
|||
static const char *const opts[] = {"stop", "restart", "collect", |
|||
"count", "step", "setpause", "setstepmul", |
|||
"isrunning", NULL}; |
|||
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, |
|||
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, |
|||
LUA_GCISRUNNING}; |
|||
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; |
|||
int ex = (int)luaL_optinteger(L, 2, 0); |
|||
int res = lua_gc(L, o, ex); |
|||
switch (o) { |
|||
case LUA_GCCOUNT: { |
|||
int b = lua_gc(L, LUA_GCCOUNTB, 0); |
|||
lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024)); |
|||
return 1; |
|||
} |
|||
case LUA_GCSTEP: case LUA_GCISRUNNING: { |
|||
lua_pushboolean(L, res); |
|||
return 1; |
|||
} |
|||
default: { |
|||
lua_pushinteger(L, res); |
|||
return 1; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
static int luaB_type (lua_State *L) { |
|||
int t = lua_type(L, 1); |
|||
luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); |
|||
lua_pushstring(L, lua_typename(L, t)); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static int pairsmeta (lua_State *L, const char *method, int iszero, |
|||
lua_CFunction iter) { |
|||
if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */ |
|||
luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */ |
|||
lua_pushcfunction(L, iter); /* will return generator, */ |
|||
lua_pushvalue(L, 1); /* state, */ |
|||
if (iszero) lua_pushinteger(L, 0); /* and initial value */ |
|||
else lua_pushnil(L); |
|||
} |
|||
else { |
|||
lua_pushvalue(L, 1); /* argument 'self' to metamethod */ |
|||
lua_call(L, 1, 3); /* get 3 values from metamethod */ |
|||
} |
|||
return 3; |
|||
} |
|||
|
|||
|
|||
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) { |
|||
return pairsmeta(L, "__pairs", 0, luaB_next); |
|||
} |
|||
|
|||
|
|||
/*
|
|||
** Traversal function for 'ipairs' |
|||
*/ |
|||
static int ipairsaux (lua_State *L) { |
|||
lua_Integer i = luaL_checkinteger(L, 2) + 1; |
|||
lua_pushinteger(L, i); |
|||
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; |
|||
} |
|||
|
|||
|
|||
/*
|
|||
** This function will use either 'ipairsaux' or 'ipairsaux_raw' to |
|||
** traverse a table, depending on whether the table has metamethods |
|||
** that can affect the traversal. |
|||
*/ |
|||
static int luaB_ipairs (lua_State *L) { |
|||
#if defined(LUA_COMPAT_IPAIRS) |
|||
return pairsmeta(L, "__ipairs", 1, ipairsaux); |
|||
#else |
|||
luaL_checkany(L, 1); |
|||
lua_pushcfunction(L, ipairsaux); /* iteration function */ |
|||
lua_pushvalue(L, 1); /* state */ |
|||
lua_pushinteger(L, 0); /* initial value */ |
|||
return 3; |
|||
#endif |
|||
} |
|||
|
|||
|
|||
static int load_aux (lua_State *L, int status, int envidx) { |
|||
if (status == LUA_OK) { |
|||
if (envidx != 0) { /* 'env' parameter? */ |
|||
lua_pushvalue(L, envidx); /* environment for loaded function */ |
|||
if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ |
|||
lua_pop(L, 1); /* remove 'env' if not used by previous call */ |
|||
} |
|||
return 1; |
|||
} |
|||
else { /* error (message is on top of the stack) */ |
|||
lua_pushnil(L); |
|||
lua_insert(L, -2); /* put before error message */ |
|||
return 2; /* return nil plus error message */ |
|||
} |
|||
} |
|||
|
|||
|
|||
static int luaB_loadfile (lua_State *L) { |
|||
const char *fname = luaL_optstring(L, 1, NULL); |
|||
const char *mode = luaL_optstring(L, 2, NULL); |
|||
int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ |
|||
int status = luaL_loadfilex(L, fname, mode); |
|||
return load_aux(L, status, env); |
|||
} |
|||
|
|||
|
|||
/*
|
|||
** {====================================================== |
|||
** Generic Read function |
|||
** ======================================================= |
|||
*/ |
|||
|
|||
|
|||
/*
|
|||
** reserved slot, above all arguments, to hold a copy of the returned |
|||
** string to avoid it being collected while parsed. 'load' has four |
|||
** optional arguments (chunk, source name, mode, and environment). |
|||
*/ |
|||
#define RESERVEDSLOT 5 |
|||
|
|||
|
|||
/*
|
|||
** 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); /* not used */ |
|||
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)) { |
|||
lua_pop(L, 1); /* pop result */ |
|||
*size = 0; |
|||
return NULL; |
|||
} |
|||
else if (!lua_isstring(L, -1)) |
|||
luaL_error(L, "reader function must return a string"); |
|||
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ |
|||
return lua_tolstring(L, RESERVEDSLOT, size); |
|||
} |
|||
|
|||
|
|||
static int luaB_load (lua_State *L) { |
|||
int status; |
|||
size_t l; |
|||
const char *s = lua_tolstring(L, 1, &l); |
|||
const char *mode = luaL_optstring(L, 3, "bt"); |
|||
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ |
|||
if (s != NULL) { /* loading a string? */ |
|||
const char *chunkname = luaL_optstring(L, 2, s); |
|||
status = luaL_loadbufferx(L, s, l, chunkname, mode); |
|||
} |
|||
else { /* loading from a reader function */ |
|||
const char *chunkname = luaL_optstring(L, 2, "=(load)"); |
|||
luaL_checktype(L, 1, LUA_TFUNCTION); |
|||
lua_settop(L, RESERVEDSLOT); /* create reserved slot */ |
|||
status = lua_load(L, generic_reader, NULL, chunkname, mode); |
|||
} |
|||
return load_aux(L, status, env); |
|||
} |
|||
|
|||
/* }====================================================== */ |
|||
|
|||
|
|||
static int dofilecont (lua_State *L, int d1, lua_KContext d2) { |
|||
(void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ |
|||
return lua_gettop(L) - 1; |
|||
} |
|||
|
|||
|
|||
static int luaB_dofile (lua_State *L) { |
|||
const char *fname = luaL_optstring(L, 1, NULL); |
|||
lua_settop(L, 1); |
|||
if (luaL_loadfile(L, fname) != LUA_OK) |
|||
return lua_error(L); |
|||
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); |
|||
return dofilecont(L, 0, 0); |
|||
} |
|||
|
|||
|
|||
static int luaB_assert (lua_State *L) { |
|||
if (lua_toboolean(L, 1)) /* condition is true? */ |
|||
return lua_gettop(L); /* return all arguments */ |
|||
else { /* error */ |
|||
luaL_checkany(L, 1); /* there must be a condition */ |
|||
lua_remove(L, 1); /* remove it */ |
|||
lua_pushliteral(L, "assertion failed!"); /* default message */ |
|||
lua_settop(L, 1); /* leave only message (default if no other one) */ |
|||
return luaB_error(L); /* call 'error' */ |
|||
} |
|||
} |
|||
|
|||
|
|||
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 { |
|||
lua_Integer i = luaL_checkinteger(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 - (int)i; |
|||
} |
|||
} |
|||
|
|||
|
|||
/*
|
|||
** Continuation function for 'pcall' and 'xpcall'. Both functions |
|||
** already pushed a 'true' before doing the call, so in case of success |
|||
** 'finishpcall' only has to return everything in the stack minus |
|||
** 'extra' values (where 'extra' is exactly the number of items to be |
|||
** ignored). |
|||
*/ |
|||
static int finishpcall (lua_State *L, int status, lua_KContext extra) { |
|||
if (status != LUA_OK && status != LUA_YIELD) { /* error? */ |
|||
lua_pushboolean(L, 0); /* first result (false) */ |
|||
lua_pushvalue(L, -2); /* error message */ |
|||
return 2; /* return false, msg */ |
|||
} |
|||
else |
|||
return lua_gettop(L) - (int)extra; /* return all results */ |
|||
} |
|||
|
|||
|
|||
static int luaB_pcall (lua_State *L) { |
|||
int status; |
|||
luaL_checkany(L, 1); |
|||
lua_pushboolean(L, 1); /* first result if no errors */ |
|||
lua_insert(L, 1); /* put it in place */ |
|||
status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); |
|||
return finishpcall(L, status, 0); |
|||
} |
|||
|
|||
|
|||
/*
|
|||
** Do a protected call with error handling. After 'lua_rotate', the |
|||
** stack will have <f, err, true, f, [args...]>; so, the function passes |
|||
** 2 to 'finishpcall' to skip the 2 first values when returning results. |
|||
*/ |
|||
static int luaB_xpcall (lua_State *L) { |
|||
int status; |
|||
int n = lua_gettop(L); |
|||
luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ |
|||
lua_pushboolean(L, 1); /* first result */ |
|||
lua_pushvalue(L, 1); /* function */ |
|||
lua_rotate(L, 3, 2); /* move them below function's arguments */ |
|||
status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); |
|||
return finishpcall(L, status, 2); |
|||
} |
|||
|
|||
|
|||
static int luaB_tostring (lua_State *L) { |
|||
luaL_checkany(L, 1); |
|||
luaL_tolstring(L, 1, NULL); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static const luaL_Reg base_funcs[] = { |
|||
{"assert", luaB_assert}, |
|||
{"collectgarbage", luaB_collectgarbage}, |
|||
{"dofile", luaB_dofile}, |
|||
{"error", luaB_error}, |
|||
{"getmetatable", luaB_getmetatable}, |
|||
{"ipairs", luaB_ipairs}, |
|||
{"loadfile", luaB_loadfile}, |
|||
{"load", luaB_load}, |
|||
#if defined(LUA_COMPAT_LOADSTRING) |
|||
{"loadstring", luaB_load}, |
|||
#endif |
|||
{"next", luaB_next}, |
|||
{"pairs", luaB_pairs}, |
|||
{"pcall", luaB_pcall}, |
|||
{"print", luaB_print}, |
|||
{"rawequal", luaB_rawequal}, |
|||
{"rawlen", luaB_rawlen}, |
|||
{"rawget", luaB_rawget}, |
|||
{"rawset", luaB_rawset}, |
|||
{"select", luaB_select}, |
|||
{"setmetatable", luaB_setmetatable}, |
|||
{"tonumber", luaB_tonumber}, |
|||
{"tostring", luaB_tostring}, |
|||
{"type", luaB_type}, |
|||
{"xpcall", luaB_xpcall}, |
|||
/* placeholders */ |
|||
{"_G", NULL}, |
|||
{"_VERSION", NULL}, |
|||
{NULL, NULL} |
|||
}; |
|||
|
|||
|
|||
LUAMOD_API int luaopen_base (lua_State *L) { |
|||
/* open lib into global table */ |
|||
lua_pushglobaltable(L); |
|||
luaL_setfuncs(L, base_funcs, 0); |
|||
/* set global _G */ |
|||
lua_pushvalue(L, -1); |
|||
lua_setfield(L, -2, "_G"); |
|||
/* set global _VERSION */ |
|||
lua_pushliteral(L, LUA_VERSION); |
|||
lua_setfield(L, -2, "_VERSION"); |
|||
return 1; |
|||
} |
|||
|
@ -0,0 +1,233 @@ |
|||
/*
|
|||
** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $ |
|||
** Standard library for bitwise operations |
|||
** See Copyright Notice in lua.h |
|||
*/ |
|||
|
|||
#define lbitlib_c |
|||
#define LUA_LIB |
|||
|
|||
#include "lprefix.h" |
|||
|
|||
|
|||
#include "lua.h" |
|||
|
|||
#include "lauxlib.h" |
|||
#include "lualib.h" |
|||
|
|||
|
|||
#if defined(LUA_COMPAT_BITLIB) /* { */ |
|||
|
|||
|
|||
#define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) |
|||
#define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i)) |
|||
|
|||
|
|||
/* number of bits to consider in a number */ |
|||
#if !defined(LUA_NBITS) |
|||
#define LUA_NBITS 32 |
|||
#endif |
|||
|
|||
|
|||
/*
|
|||
** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must |
|||
** be made in two parts to avoid problems when LUA_NBITS is equal to the |
|||
** number of bits in a lua_Unsigned.) |
|||
*/ |
|||
#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) |
|||
|
|||
|
|||
/* macro to trim extra bits */ |
|||
#define trim(x) ((x) & ALLONES) |
|||
|
|||
|
|||
/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ |
|||
#define mask(n) (~((ALLONES << 1) << ((n) - 1))) |
|||
|
|||
|
|||
|
|||
static lua_Unsigned andaux (lua_State *L) { |
|||
int i, n = lua_gettop(L); |
|||
lua_Unsigned r = ~(lua_Unsigned)0; |
|||
for (i = 1; i <= n; i++) |
|||
r &= checkunsigned(L, i); |
|||
return trim(r); |
|||
} |
|||
|
|||
|
|||
static int b_and (lua_State *L) { |
|||
lua_Unsigned r = andaux(L); |
|||
pushunsigned(L, r); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static int b_test (lua_State *L) { |
|||
lua_Unsigned r = andaux(L); |
|||
lua_pushboolean(L, r != 0); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static int b_or (lua_State *L) { |
|||
int i, n = lua_gettop(L); |
|||
lua_Unsigned r = 0; |
|||
for (i = 1; i <= n; i++) |
|||
r |= checkunsigned(L, i); |
|||
pushunsigned(L, trim(r)); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static int b_xor (lua_State *L) { |
|||
int i, n = lua_gettop(L); |
|||
lua_Unsigned r = 0; |
|||
for (i = 1; i <= n; i++) |
|||
r ^= checkunsigned(L, i); |
|||
pushunsigned(L, trim(r)); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static int b_not (lua_State *L) { |
|||
lua_Unsigned r = ~checkunsigned(L, 1); |
|||
pushunsigned(L, trim(r)); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { |
|||
if (i < 0) { /* shift right? */ |
|||
i = -i; |
|||
r = trim(r); |
|||
if (i >= LUA_NBITS) r = 0; |
|||
else r >>= i; |
|||
} |
|||
else { /* shift left */ |
|||
if (i >= LUA_NBITS) r = 0; |
|||
else r <<= i; |
|||
r = trim(r); |
|||
} |
|||
pushunsigned(L, r); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static int b_lshift (lua_State *L) { |
|||
return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); |
|||
} |
|||
|
|||
|
|||
static int b_rshift (lua_State *L) { |
|||
return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); |
|||
} |
|||
|
|||
|
|||
static int b_arshift (lua_State *L) { |
|||
lua_Unsigned r = checkunsigned(L, 1); |
|||
lua_Integer i = luaL_checkinteger(L, 2); |
|||
if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) |
|||
return b_shift(L, r, -i); |
|||
else { /* arithmetic shift for 'negative' number */ |
|||
if (i >= LUA_NBITS) r = ALLONES; |
|||
else |
|||
r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ |
|||
pushunsigned(L, r); |
|||
return 1; |
|||
} |
|||
} |
|||
|
|||
|
|||
static int b_rot (lua_State *L, lua_Integer d) { |
|||
lua_Unsigned r = checkunsigned(L, 1); |
|||
int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ |
|||
r = trim(r); |
|||
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ |
|||
r = (r << i) | (r >> (LUA_NBITS - i)); |
|||
pushunsigned(L, trim(r)); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static int b_lrot (lua_State *L) { |
|||
return b_rot(L, luaL_checkinteger(L, 2)); |
|||
} |
|||
|
|||
|
|||
static int b_rrot (lua_State *L) { |
|||
return b_rot(L, -luaL_checkinteger(L, 2)); |
|||
} |
|||
|
|||
|
|||
/*
|
|||
** get field and width arguments for field-manipulation functions, |
|||
** checking whether they are valid. |
|||
** ('luaL_error' called without 'return' to avoid later warnings about |
|||
** 'width' being used uninitialized.) |
|||
*/ |
|||
static int fieldargs (lua_State *L, int farg, int *width) { |
|||
lua_Integer f = luaL_checkinteger(L, farg); |
|||
lua_Integer w = luaL_optinteger(L, farg + 1, 1); |
|||
luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); |
|||
luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); |
|||
if (f + w > LUA_NBITS) |
|||
luaL_error(L, "trying to access non-existent bits"); |
|||
*width = (int)w; |
|||
return (int)f; |
|||
} |
|||
|
|||
|
|||
static int b_extract (lua_State *L) { |
|||
int w; |
|||
lua_Unsigned r = trim(checkunsigned(L, 1)); |
|||
int f = fieldargs(L, 2, &w); |
|||
r = (r >> f) & mask(w); |
|||
pushunsigned(L, r); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static int b_replace (lua_State *L) { |
|||
int w; |
|||
lua_Unsigned r = trim(checkunsigned(L, 1)); |
|||
lua_Unsigned v = trim(checkunsigned(L, 2)); |
|||
int f = fieldargs(L, 3, &w); |
|||
lua_Unsigned m = mask(w); |
|||
r = (r & ~(m << f)) | ((v & m) << f); |
|||
pushunsigned(L, r); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
static const luaL_Reg bitlib[] = { |
|||
{"arshift", b_arshift}, |
|||
{"band", b_and}, |
|||
{"bnot", b_not}, |
|||
{"bor", b_or}, |
|||
{"bxor", b_xor}, |
|||
{"btest", b_test}, |
|||
{"extract", b_extract}, |
|||
{"lrotate", b_lrot}, |
|||
{"lshift", b_lshift}, |
|||
{"replace", b_replace}, |
|||
{"rrotate", b_rrot}, |
|||
{"rshift", b_rshift}, |
|||
{NULL, NULL} |
|||
}; |
|||
|
|||
|
|||
|
|||
LUAMOD_API int luaopen_bit32 (lua_State *L) { |
|||
luaL_newlib(L, bitlib); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
#else /* }{ */ |
|||
|
|||
|
|||
LUAMOD_API int luaopen_bit32 (lua_State *L) { |
|||
return luaL_error(L, "library 'bit32' has been deprecated"); |
|||
} |
|||
|
|||
#endif /* } */ |
@ -0,0 +1,955 @@ |
|||
/*
|
|||
** $Id: lcode.c,v 2.103 2015/11/19 19:16:22 roberto Exp $ |
|||
** Code generator for Lua |
|||
** See Copyright Notice in lua.h |
|||
*/ |
|||
|
|||
#define lcode_c |
|||
#define LUA_CORE |
|||
|
|||
#include "lprefix.h" |
|||
|
|||
|
|||
#include <math.h> |
|||
#include <stdlib.h> |
|||
|
|||
#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 "lstring.h" |
|||
#include "ltable.h" |
|||
#include "lvm.h" |
|||
|
|||
|
|||
/* Maximum number of registers in a Lua function (must fit in 8 bits) */ |
|||
#define MAXREGS 255 |
|||
|
|||
|
|||
#define hasjumps(e) ((e)->t != (e)->f) |
|||
|
|||
|
|||
static int tonumeral(expdesc *e, TValue *v) { |
|||
if (hasjumps(e)) |
|||
return 0; /* not a numeral */ |
|||
switch (e->k) { |
|||
case VKINT: |
|||
if (v) setivalue(v, e->u.ival); |
|||
return 1; |
|||
case VKFLT: |
|||
if (v) setfltvalue(v, e->u.nval); |
|||
return 1; |
|||
default: return 0; |
|||
} |
|||
} |
|||
|
|||
|
|||
void luaK_nil (FuncState *fs, int from, int n) { |
|||
Instruction *previous; |
|||
int l = from + n - 1; /* last register to set nil */ |
|||
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ |
|||
previous = &fs->f->code[fs->pc-1]; |
|||
if (GET_OPCODE(*previous) == OP_LOADNIL) { |
|||
int pfrom = GETARG_A(*previous); |
|||
int pl = pfrom + GETARG_B(*previous); |
|||
if ((pfrom <= from && from <= pl + 1) || |
|||
(from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ |
|||
if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ |
|||
if (pl > l) l = pl; /* l = max(l, pl) */ |
|||
SETARG_A(*previous, from); |
|||
SETARG_B(*previous, l - from); |
|||
return; |
|||
} |
|||
} /* else go through */ |
|||
} |
|||
luaK_codeABC(fs, OP_LOADNIL, 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_patchclose (FuncState *fs, int list, int level) { |
|||
level++; /* argument is +1 to reserve 0 as non-op */ |
|||
while (list != NO_JUMP) { |
|||
int next = getjump(fs, list); |
|||
lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && |
|||
(GETARG_A(fs->f->code[list]) == 0 || |
|||
GETARG_A(fs->f->code[list]) >= level)); |
|||
SETARG_A(fs->f->code[list], level); |
|||
list = next; |
|||
} |
|||
} |
|||
|
|||
|
|||
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); |
|||
} |
|||
} |
|||
|
|||
|
|||
static int luaK_code (FuncState *fs, Instruction i) { |
|||
Proto *f = fs->f; |
|||
dischargejpc(fs); /* 'pc' will change */ |
|||
/* put new instruction in code array */ |
|||
luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, |
|||
MAX_INT, "opcodes"); |
|||
f->code[fs->pc] = i; |
|||
/* save corresponding line information */ |
|||
luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int, |
|||
MAX_INT, "opcodes"); |
|||
f->lineinfo[fs->pc] = fs->ls->lastline; |
|||
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); |
|||
lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); |
|||
return luaK_code(fs, CREATE_ABC(o, a, b, c)); |
|||
} |
|||
|
|||
|
|||
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); |
|||
lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); |
|||
return luaK_code(fs, CREATE_ABx(o, a, bc)); |
|||
} |
|||
|
|||
|
|||
static int codeextraarg (FuncState *fs, int a) { |
|||
lua_assert(a <= MAXARG_Ax); |
|||
return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); |
|||
} |
|||
|
|||
|
|||
int luaK_codek (FuncState *fs, int reg, int k) { |
|||
if (k <= MAXARG_Bx) |
|||
return luaK_codeABx(fs, OP_LOADK, reg, k); |
|||
else { |
|||
int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); |
|||
codeextraarg(fs, k); |
|||
return p; |
|||
} |
|||
} |
|||
|
|||
|
|||
void luaK_checkstack (FuncState *fs, int n) { |
|||
int newstack = fs->freereg + n; |
|||
if (newstack > fs->f->maxstacksize) { |
|||
if (newstack >= MAXREGS) |
|||
luaX_syntaxerror(fs->ls, |
|||
"function or expression needs too many registers"); |
|||
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.info); |
|||
} |
|||
|
|||
|
|||
/*
|
|||
** Use scanner's table to cache position of constants in constant list |
|||
** and try to reuse constants |
|||
*/ |
|||
static int addk (FuncState *fs, TValue *key, TValue *v) { |
|||
lua_State *L = fs->ls->L; |
|||
Proto *f = fs->f; |
|||
TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ |
|||
int k, oldsize; |
|||
if (ttisinteger(idx)) { /* is there an index there? */ |
|||
k = cast_int(ivalue(idx)); |
|||
/* correct value? (warning: must distinguish floats from integers!) */ |
|||
if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && |
|||
luaV_rawequalobj(&f->k[k], v)) |
|||
return k; /* reuse index */ |
|||
} |
|||
/* constant not found; create a new entry */ |
|||
oldsize = f->sizek; |
|||
k = fs->nk; |
|||
/* numerical value does not need GC barrier;
|
|||
table has no metatable, so it does not need to invalidate cache */ |
|||
setivalue(idx, k); |
|||
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); |
|||
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); |
|||
setobj(L, &f->k[k], v); |
|||
fs->nk++; |
|||
luaC_barrier(L, f, v); |
|||
return k; |
|||
} |
|||
|
|||
|
|||
int luaK_stringK (FuncState *fs, TString *s) { |
|||
TValue o; |
|||
setsvalue(fs->ls->L, &o, s); |
|||
return addk(fs, &o, &o); |
|||
} |
|||
|
|||
|
|||
/*
|
|||
** Integers use userdata as keys to avoid collision with floats with same |
|||
** value; conversion to 'void*' used only for hashing, no "precision" |
|||
** problems |
|||
*/ |
|||
int luaK_intK (FuncState *fs, lua_Integer n) { |
|||
TValue k, o; |
|||
setpvalue(&k, cast(void*, cast(size_t, n))); |
|||
setivalue(&o, n); |
|||
return addk(fs, &k, &o); |
|||
} |
|||
|
|||
|
|||
static int luaK_numberK (FuncState *fs, lua_Number r) { |
|||
TValue o; |
|||
setfltvalue(&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->ls->L, &k, fs->ls->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.info = GETARG_A(getcode(fs, e)); |