+
+
+#include "llimits.h"
+#include "lua.h"
+
+
+/*
+** Extra types for collectable non-values
+*/
+#define LUA_TUPVAL LUA_NUMTYPES /* upvalues */
+#define LUA_TPROTO (LUA_NUMTYPES+1) /* function prototypes */
+#define LUA_TDEADKEY (LUA_NUMTYPES+2) /* removed keys in tables */
+
+
+
+/*
+** number of all possible types (including LUA_TNONE but excluding DEADKEY)
+*/
+#define LUA_TOTALTYPES (LUA_TPROTO + 2)
+
+
+/*
+** tags for Tagged Values have the following use of bits:
+** bits 0-3: actual tag (a LUA_T* constant)
+** bits 4-5: variant bits
+** bit 6: whether value is collectable
+*/
+
+/* add variant bits to a type */
+#define makevariant(t,v) ((t) | ((v) << 4))
+
+
+
+/*
+** Union of all Lua values
+*/
+typedef union Value {
+ struct GCObject *gc; /* collectable objects */
+ void *p; /* light userdata */
+ lua_CFunction f; /* light C functions */
+ lua_Integer i; /* integer numbers */
+ lua_Number n; /* float numbers */
+} Value;
+
+
+/*
+** Tagged Values. This is the basic representation of values in Lua:
+** an actual value plus a tag with its type.
+*/
+
+#define TValuefields Value value_; lu_byte tt_
+
+typedef struct TValue {
+ TValuefields;
+} TValue;
+
+
+#define val_(o) ((o)->value_)
+#define valraw(o) (val_(o))
+
+
+/* raw type tag of a TValue */
+#define rawtt(o) ((o)->tt_)
+
+/* tag with no variants (bits 0-3) */
+#define novariant(t) ((t) & 0x0F)
+
+/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
+#define withvariant(t) ((t) & 0x3F)
+#define ttypetag(o) withvariant(rawtt(o))
+
+/* type of a TValue */
+#define ttype(o) (novariant(rawtt(o)))
+
+
+/* Macros to test type */
+#define checktag(o,t) (rawtt(o) == (t))
+#define checktype(o,t) (ttype(o) == (t))
+
+
+/* Macros for internal tests */
+
+/* collectable object has the same tag as the original value */
+#define righttt(obj) (ttypetag(obj) == gcvalue(obj)->tt)
+
+/*
+** Any value being manipulated by the program either is non
+** collectable, or the collectable object has the right tag
+** and it is not dead. The option 'L == NULL' allows other
+** macros using this one to be used where L is not available.
+*/
+#define checkliveness(L,obj) \
+ ((void)L, lua_longassert(!iscollectable(obj) || \
+ (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj))))))
+
+
+/* Macros to set values */
+
+/* set a value's tag */
+#define settt_(o,t) ((o)->tt_=(t))
+
+
+/* main macro to copy values (from 'obj2' to 'obj1') */
+#define setobj(L,obj1,obj2) \
+ { TValue *io1=(obj1); const TValue *io2=(obj2); \
+ io1->value_ = io2->value_; settt_(io1, io2->tt_); \
+ checkliveness(L,io1); lua_assert(!isnonstrictnil(io1)); }
+
+/*
+** Different types of assignments, according to source and destination.
+** (They are mostly equal now, but may be different in the future.)
+*/
+
+/* from stack to stack */
+#define setobjs2s(L,o1,o2) setobj(L,s2v(o1),s2v(o2))
+/* to stack (not from same stack) */
+#define setobj2s(L,o1,o2) setobj(L,s2v(o1),o2)
+/* from table to same table */
+#define setobjt2t setobj
+/* to new object */
+#define setobj2n setobj
+/* to table */
+#define setobj2t setobj
+
+
+/*
+** Entries in a Lua stack. Field 'tbclist' forms a list of all
+** to-be-closed variables active in this stack. Dummy entries are
+** used when the distance between two tbc variables does not fit
+** in an unsigned short. They are represented by delta==0, and
+** their real delta is always the maximum value that fits in
+** that field.
+*/
+typedef union StackValue {
+ TValue val;
+ struct {
+ TValuefields;
+ unsigned short delta;
+ } tbclist;
+} StackValue;
+
+
+/* index to stack elements */
+typedef StackValue *StkId;
+
+/* convert a 'StackValue' to a 'TValue' */
+#define s2v(o) (&(o)->val)
+
+
+
+/*
+** {==================================================================
+** Nil
+** ===================================================================
+*/
+
+/* Standard nil */
+#define LUA_VNIL makevariant(LUA_TNIL, 0)
+
+/* Empty slot (which might be different from a slot containing nil) */
+#define LUA_VEMPTY makevariant(LUA_TNIL, 1)
+
+/* Value returned for a key not found in a table (absent key) */
+#define LUA_VABSTKEY makevariant(LUA_TNIL, 2)
+
+
+/* macro to test for (any kind of) nil */
+#define ttisnil(v) checktype((v), LUA_TNIL)
+
+
+/* macro to test for a standard nil */
+#define ttisstrictnil(o) checktag((o), LUA_VNIL)
+
+
+#define setnilvalue(obj) settt_(obj, LUA_VNIL)
+
+
+#define isabstkey(v) checktag((v), LUA_VABSTKEY)
+
+
+/*
+** macro to detect non-standard nils (used only in assertions)
+*/
+#define isnonstrictnil(v) (ttisnil(v) && !ttisstrictnil(v))
+
+
+/*
+** By default, entries with any kind of nil are considered empty.
+** (In any definition, values associated with absent keys must also
+** be accepted as empty.)
+*/
+#define isempty(v) ttisnil(v)
+
+
+/* macro defining a value corresponding to an absent key */
+#define ABSTKEYCONSTANT {NULL}, LUA_VABSTKEY
+
+
+/* mark an entry as empty */
+#define setempty(v) settt_(v, LUA_VEMPTY)
+
+
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Booleans
+** ===================================================================
+*/
+
+
+#define LUA_VFALSE makevariant(LUA_TBOOLEAN, 0)
+#define LUA_VTRUE makevariant(LUA_TBOOLEAN, 1)
+
+#define ttisboolean(o) checktype((o), LUA_TBOOLEAN)
+#define ttisfalse(o) checktag((o), LUA_VFALSE)
+#define ttistrue(o) checktag((o), LUA_VTRUE)
+
+
+#define l_isfalse(o) (ttisfalse(o) || ttisnil(o))
+
+
+#define setbfvalue(obj) settt_(obj, LUA_VFALSE)
+#define setbtvalue(obj) settt_(obj, LUA_VTRUE)
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Threads
+** ===================================================================
+*/
+
+#define LUA_VTHREAD makevariant(LUA_TTHREAD, 0)
+
+#define ttisthread(o) checktag((o), ctb(LUA_VTHREAD))
+
+#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc))
+
+#define setthvalue(L,obj,x) \
+ { TValue *io = (obj); lua_State *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VTHREAD)); \
+ checkliveness(L,io); }
+
+#define setthvalue2s(L,o,t) setthvalue(L,s2v(o),t)
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Collectable Objects
+** ===================================================================
+*/
+
+/*
+** Common Header for all collectable objects (in macro form, to be
+** included in other objects)
+*/
+#define CommonHeader struct GCObject *next; lu_byte tt; lu_byte marked
+
+
+/* Common type for all collectable objects */
+typedef struct GCObject {
+ CommonHeader;
+} GCObject;
+
+
+/* Bit mark for collectable types */
+#define BIT_ISCOLLECTABLE (1 << 6)
+
+#define iscollectable(o) (rawtt(o) & BIT_ISCOLLECTABLE)
+
+/* mark a tag as collectable */
+#define ctb(t) ((t) | BIT_ISCOLLECTABLE)
+
+#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc)
+
+#define gcvalueraw(v) ((v).gc)
+
+#define setgcovalue(L,obj,x) \
+ { TValue *io = (obj); GCObject *i_g=(x); \
+ val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); }
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Numbers
+** ===================================================================
+*/
+
+/* Variant tags for numbers */
+#define LUA_VNUMINT makevariant(LUA_TNUMBER, 0) /* integer numbers */
+#define LUA_VNUMFLT makevariant(LUA_TNUMBER, 1) /* float numbers */
+
+#define ttisnumber(o) checktype((o), LUA_TNUMBER)
+#define ttisfloat(o) checktag((o), LUA_VNUMFLT)
+#define ttisinteger(o) checktag((o), LUA_VNUMINT)
+
+#define nvalue(o) check_exp(ttisnumber(o), \
+ (ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o)))
+#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n)
+#define ivalue(o) check_exp(ttisinteger(o), val_(o).i)
+
+#define fltvalueraw(v) ((v).n)
+#define ivalueraw(v) ((v).i)
+
+#define setfltvalue(obj,x) \
+ { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_VNUMFLT); }
+
+#define chgfltvalue(obj,x) \
+ { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); }
+
+#define setivalue(obj,x) \
+ { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_VNUMINT); }
+
+#define chgivalue(obj,x) \
+ { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); }
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Strings
+** ===================================================================
+*/
+
+/* Variant tags for strings */
+#define LUA_VSHRSTR makevariant(LUA_TSTRING, 0) /* short strings */
+#define LUA_VLNGSTR makevariant(LUA_TSTRING, 1) /* long strings */
+
+#define ttisstring(o) checktype((o), LUA_TSTRING)
+#define ttisshrstring(o) checktag((o), ctb(LUA_VSHRSTR))
+#define ttislngstring(o) checktag((o), ctb(LUA_VLNGSTR))
+
+#define tsvalueraw(v) (gco2ts((v).gc))
+
+#define tsvalue(o) check_exp(ttisstring(o), gco2ts(val_(o).gc))
+
+#define setsvalue(L,obj,x) \
+ { TValue *io = (obj); TString *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \
+ checkliveness(L,io); }
+
+/* set a string to the stack */
+#define setsvalue2s(L,o,s) setsvalue(L,s2v(o),s)
+
+/* set a string to a new object */
+#define setsvalue2n setsvalue
+
+
+/*
+** Header for a string value.
+*/
+typedef struct TString {
+ CommonHeader;
+ lu_byte extra; /* reserved words for short strings; "has hash" for longs */
+ lu_byte shrlen; /* length for short strings */
+ unsigned int hash;
+ union {
+ size_t lnglen; /* length for long strings */
+ struct TString *hnext; /* linked list for hash table */
+ } u;
+ char contents[1];
+} TString;
+
+
+
+/*
+** Get the actual string (array of bytes) from a 'TString'.
+*/
+#define getstr(ts) ((ts)->contents)
+
+
+/* get the actual string (array of bytes) from a Lua value */
+#define svalue(o) getstr(tsvalue(o))
+
+/* get string length from 'TString *s' */
+#define tsslen(s) ((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen)
+
+/* get string length from 'TValue *o' */
+#define vslen(o) tsslen(tsvalue(o))
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Userdata
+** ===================================================================
+*/
+
+
+/*
+** Light userdata should be a variant of userdata, but for compatibility
+** reasons they are also different types.
+*/
+#define LUA_VLIGHTUSERDATA makevariant(LUA_TLIGHTUSERDATA, 0)
+
+#define LUA_VUSERDATA makevariant(LUA_TUSERDATA, 0)
+
+#define ttislightuserdata(o) checktag((o), LUA_VLIGHTUSERDATA)
+#define ttisfulluserdata(o) checktag((o), ctb(LUA_VUSERDATA))
+
+#define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p)
+#define uvalue(o) check_exp(ttisfulluserdata(o), gco2u(val_(o).gc))
+
+#define pvalueraw(v) ((v).p)
+
+#define setpvalue(obj,x) \
+ { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_VLIGHTUSERDATA); }
+
+#define setuvalue(L,obj,x) \
+ { TValue *io = (obj); Udata *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VUSERDATA)); \
+ checkliveness(L,io); }
+
+
+/* Ensures that addresses after this type are always fully aligned. */
+typedef union UValue {
+ TValue uv;
+ LUAI_MAXALIGN; /* ensures maximum alignment for udata bytes */
+} UValue;
+
+
+/*
+** Header for userdata with user values;
+** memory area follows the end of this structure.
+*/
+typedef struct Udata {
+ CommonHeader;
+ unsigned short nuvalue; /* number of user values */
+ size_t len; /* number of bytes */
+ struct Table *metatable;
+ GCObject *gclist;
+ UValue uv[1]; /* user values */
+} Udata;
+
+
+/*
+** Header for userdata with no user values. These userdata do not need
+** to be gray during GC, and therefore do not need a 'gclist' field.
+** To simplify, the code always use 'Udata' for both kinds of userdata,
+** making sure it never accesses 'gclist' on userdata with no user values.
+** This structure here is used only to compute the correct size for
+** this representation. (The 'bindata' field in its end ensures correct
+** alignment for binary data following this header.)
+*/
+typedef struct Udata0 {
+ CommonHeader;
+ unsigned short nuvalue; /* number of user values */
+ size_t len; /* number of bytes */
+ struct Table *metatable;
+ union {LUAI_MAXALIGN;} bindata;
+} Udata0;
+
+
+/* compute the offset of the memory area of a userdata */
+#define udatamemoffset(nuv) \
+ ((nuv) == 0 ? offsetof(Udata0, bindata) \
+ : offsetof(Udata, uv) + (sizeof(UValue) * (nuv)))
+
+/* get the address of the memory block inside 'Udata' */
+#define getudatamem(u) (cast_charp(u) + udatamemoffset((u)->nuvalue))
+
+/* compute the size of a userdata */
+#define sizeudata(nuv,nb) (udatamemoffset(nuv) + (nb))
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Prototypes
+** ===================================================================
+*/
+
+#define LUA_VPROTO makevariant(LUA_TPROTO, 0)
+
+
+/*
+** Description of an upvalue for function prototypes
+*/
+typedef struct Upvaldesc {
+ TString *name; /* upvalue name (for debug information) */
+ lu_byte instack; /* whether it is in stack (register) */
+ lu_byte idx; /* index of upvalue (in stack or in outer function's list) */
+ lu_byte kind; /* kind of corresponding variable */
+} Upvaldesc;
+
+
+/*
+** Description of a local variable for function prototypes
+** (used for debug information)
+*/
+typedef struct LocVar {
+ TString *varname;
+ int startpc; /* first point where variable is active */
+ int endpc; /* first point where variable is dead */
+} LocVar;
+
+
+/*
+** Associates the absolute line source for a given instruction ('pc').
+** The array 'lineinfo' gives, for each instruction, the difference in
+** lines from the previous instruction. When that difference does not
+** fit into a byte, Lua saves the absolute line for that instruction.
+** (Lua also saves the absolute line periodically, to speed up the
+** computation of a line number: we can use binary search in the
+** absolute-line array, but we must traverse the 'lineinfo' array
+** linearly to compute a line.)
+*/
+typedef struct AbsLineInfo {
+ int pc;
+ int line;
+} AbsLineInfo;
+
+/*
+** Function Prototypes
+*/
+typedef struct Proto {
+ CommonHeader;
+ lu_byte numparams; /* number of fixed (named) parameters */
+ lu_byte is_vararg;
+ lu_byte maxstacksize; /* number of registers needed by this function */
+ int sizeupvalues; /* size of 'upvalues' */
+ int sizek; /* size of 'k' */
+ int sizecode;
+ int sizelineinfo;
+ int sizep; /* size of 'p' */
+ int sizelocvars;
+ int sizeabslineinfo; /* size of 'abslineinfo' */
+ int linedefined; /* debug information */
+ int lastlinedefined; /* debug information */
+ TValue *k; /* constants used by the function */
+ Instruction *code; /* opcodes */
+ struct Proto **p; /* functions defined inside the function */
+ Upvaldesc *upvalues; /* upvalue information */
+ ls_byte *lineinfo; /* information about source lines (debug information) */
+ AbsLineInfo *abslineinfo; /* idem */
+ LocVar *locvars; /* information about local variables (debug information) */
+ TString *source; /* used for debug information */
+ GCObject *gclist;
+} Proto;
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Functions
+** ===================================================================
+*/
+
+#define LUA_VUPVAL makevariant(LUA_TUPVAL, 0)
+
+
+/* Variant tags for functions */
+#define LUA_VLCL makevariant(LUA_TFUNCTION, 0) /* Lua closure */
+#define LUA_VLCF makevariant(LUA_TFUNCTION, 1) /* light C function */
+#define LUA_VCCL makevariant(LUA_TFUNCTION, 2) /* C closure */
+
+#define ttisfunction(o) checktype(o, LUA_TFUNCTION)
+#define ttisLclosure(o) checktag((o), ctb(LUA_VLCL))
+#define ttislcf(o) checktag((o), LUA_VLCF)
+#define ttisCclosure(o) checktag((o), ctb(LUA_VCCL))
+#define ttisclosure(o) (ttisLclosure(o) || ttisCclosure(o))
+
+
+#define isLfunction(o) ttisLclosure(o)
+
+#define clvalue(o) check_exp(ttisclosure(o), gco2cl(val_(o).gc))
+#define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc))
+#define fvalue(o) check_exp(ttislcf(o), val_(o).f)
+#define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc))
+
+#define fvalueraw(v) ((v).f)
+
+#define setclLvalue(L,obj,x) \
+ { TValue *io = (obj); LClosure *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VLCL)); \
+ checkliveness(L,io); }
+
+#define setclLvalue2s(L,o,cl) setclLvalue(L,s2v(o),cl)
+
+#define setfvalue(obj,x) \
+ { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_VLCF); }
+
+#define setclCvalue(L,obj,x) \
+ { TValue *io = (obj); CClosure *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VCCL)); \
+ checkliveness(L,io); }
+
+
+/*
+** Upvalues for Lua closures
+*/
+typedef struct UpVal {
+ CommonHeader;
+ lu_byte tbc; /* true if it represents a to-be-closed variable */
+ TValue *v; /* points to stack or to its own value */
+ union {
+ struct { /* (when open) */
+ struct UpVal *next; /* linked list */
+ struct UpVal **previous;
+ } open;
+ TValue value; /* the value (when closed) */
+ } u;
+} UpVal;
+
+
+
+#define ClosureHeader \
+ CommonHeader; lu_byte nupvalues; GCObject *gclist
+
+typedef struct CClosure {
+ ClosureHeader;
+ lua_CFunction f;
+ TValue upvalue[1]; /* list of upvalues */
+} CClosure;
+
+
+typedef struct LClosure {
+ ClosureHeader;
+ struct Proto *p;
+ UpVal *upvals[1]; /* list of upvalues */
+} LClosure;
+
+
+typedef union Closure {
+ CClosure c;
+ LClosure l;
+} Closure;
+
+
+#define getproto(o) (clLvalue(o)->p)
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Tables
+** ===================================================================
+*/
+
+#define LUA_VTABLE makevariant(LUA_TTABLE, 0)
+
+#define ttistable(o) checktag((o), ctb(LUA_VTABLE))
+
+#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc))
+
+#define sethvalue(L,obj,x) \
+ { TValue *io = (obj); Table *x_ = (x); \
+ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VTABLE)); \
+ checkliveness(L,io); }
+
+#define sethvalue2s(L,o,h) sethvalue(L,s2v(o),h)
+
+
+/*
+** Nodes for Hash tables: A pack of two TValue's (key-value pairs)
+** plus a 'next' field to link colliding entries. The distribution
+** of the key's fields ('key_tt' and 'key_val') not forming a proper
+** 'TValue' allows for a smaller size for 'Node' both in 4-byte
+** and 8-byte alignments.
+*/
+typedef union Node {
+ struct NodeKey {
+ TValuefields; /* fields for value */
+ lu_byte key_tt; /* key type */
+ int next; /* for chaining */
+ Value key_val; /* key value */
+ } u;
+ TValue i_val; /* direct access to node's value as a proper 'TValue' */
+} Node;
+
+
+/* copy a value into a key */
+#define setnodekey(L,node,obj) \
+ { Node *n_=(node); const TValue *io_=(obj); \
+ n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \
+ checkliveness(L,io_); }
+
+
+/* copy a value from a key */
+#define getnodekey(L,obj,node) \
+ { TValue *io_=(obj); const Node *n_=(node); \
+ io_->value_ = n_->u.key_val; io_->tt_ = n_->u.key_tt; \
+ checkliveness(L,io_); }
+
+
+/*
+** About 'alimit': if 'isrealasize(t)' is true, then 'alimit' is the
+** real size of 'array'. Otherwise, the real size of 'array' is the
+** smallest power of two not smaller than 'alimit' (or zero iff 'alimit'
+** is zero); 'alimit' is then used as a hint for #t.
+*/
+
+#define BITRAS (1 << 7)
+#define isrealasize(t) (!((t)->flags & BITRAS))
+#define setrealasize(t) ((t)->flags &= cast_byte(~BITRAS))
+#define setnorealasize(t) ((t)->flags |= BITRAS)
+
+
+typedef struct Table {
+ CommonHeader;
+ lu_byte flags; /* 1<u.key_tt)
+#define keyval(node) ((node)->u.key_val)
+
+#define keyisnil(node) (keytt(node) == LUA_TNIL)
+#define keyisinteger(node) (keytt(node) == LUA_VNUMINT)
+#define keyival(node) (keyval(node).i)
+#define keyisshrstr(node) (keytt(node) == ctb(LUA_VSHRSTR))
+#define keystrval(node) (gco2ts(keyval(node).gc))
+
+#define setnilkey(node) (keytt(node) = LUA_TNIL)
+
+#define keyiscollectable(n) (keytt(n) & BIT_ISCOLLECTABLE)
+
+#define gckey(n) (keyval(n).gc)
+#define gckeyN(n) (keyiscollectable(n) ? gckey(n) : NULL)
+
+
+/*
+** Dead keys in tables have the tag DEADKEY but keep their original
+** gcvalue. This distinguishes them from regular keys but allows them to
+** be found when searched in a special way. ('next' needs that to find
+** keys removed from a table during a traversal.)
+*/
+#define setdeadkey(node) (keytt(node) = LUA_TDEADKEY)
+#define keyisdead(node) (keytt(node) == LUA_TDEADKEY)
+
+/* }================================================================== */
+
+
+
+/*
+** 'module' operation for hashing (size is always a power of 2)
+*/
+#define lmod(s,size) \
+ (check_exp((size&(size-1))==0, (cast_int((s) & ((size)-1)))))
+
+
+#define twoto(x) (1<<(x))
+#define sizenode(t) (twoto((t)->lsizenode))
+
+
+/* size of buffer for 'luaO_utf8esc' function */
+#define UTF8BUFFSZ 8
+
+LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x);
+LUAI_FUNC int luaO_ceillog2 (unsigned int x);
+LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,
+ const TValue *p2, TValue *res);
+LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1,
+ const TValue *p2, StkId res);
+LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o);
+LUAI_FUNC int luaO_hexavalue (int c);
+LUAI_FUNC void luaO_tostring (lua_State *L, TValue *obj);
+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 srclen);
+
+
+#endif
+
diff --git a/include/lua/lopcodes.h b/include/lua/lopcodes.h
new file mode 100644
index 00000000..7c274515
--- /dev/null
+++ b/include/lua/lopcodes.h
@@ -0,0 +1,405 @@
+/*
+** $Id: lopcodes.h $
+** 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 32-bit integers.
+ All instructions have an opcode in the first 7 bits.
+ Instructions can have the following formats:
+
+ 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+ 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+iABC C(8) | B(8) |k| A(8) | Op(7) |
+iABx Bx(17) | A(8) | Op(7) |
+iAsBx sBx (signed)(17) | A(8) | Op(7) |
+iAx Ax(25) | Op(7) |
+isJ sJ(25) | Op(7) |
+
+ A signed argument is represented in excess K: the represented value is
+ the written unsigned value minus K, where K is half the maximum for the
+ corresponding unsigned argument.
+===========================================================================*/
+
+
+enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
+
+
+/*
+** size and position of opcode arguments.
+*/
+#define SIZE_C 8
+#define SIZE_B 8
+#define SIZE_Bx (SIZE_C + SIZE_B + 1)
+#define SIZE_A 8
+#define SIZE_Ax (SIZE_Bx + SIZE_A)
+#define SIZE_sJ (SIZE_Bx + SIZE_A)
+
+#define SIZE_OP 7
+
+#define POS_OP 0
+
+#define POS_A (POS_OP + SIZE_OP)
+#define POS_k (POS_A + SIZE_A)
+#define POS_B (POS_k + 1)
+#define POS_C (POS_B + SIZE_B)
+
+#define POS_Bx POS_k
+
+#define POS_Ax POS_A
+
+#define POS_sJ POS_A
+
+
+/*
+** limits for opcode arguments.
+** we use (signed) 'int' to manipulate most arguments,
+** so they must fit in ints.
+*/
+
+/* Check whether type 'int' has at least 'b' bits ('b' < 32) */
+#define L_INTHASBITS(b) ((UINT_MAX >> ((b) - 1)) >= 1)
+
+
+#if L_INTHASBITS(SIZE_Bx)
+#define MAXARG_Bx ((1<>1) /* 'sBx' is signed */
+
+
+#if L_INTHASBITS(SIZE_Ax)
+#define MAXARG_Ax ((1<> 1)
+
+
+#define MAXARG_A ((1<> 1)
+
+#define int2sC(i) ((i) + OFFSET_sC)
+#define sC2int(i) ((i) - OFFSET_sC)
+
+
+/* creates a mask with 'n' 1 bits at position 'p' */
+#define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p))
+
+/* creates a mask with 'n' 0 bits at position 'p' */
+#define MASK0(n,p) (~MASK1(n,p))
+
+/*
+** the following macros help to manipulate instructions
+*/
+
+#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
+#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
+ ((cast(Instruction, o)<>(pos)) & MASK1(size,0)))
+#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \
+ ((cast(Instruction, v)<> sC */
+OP_SHLI,/* A B sC R[A] := sC << R[B] */
+
+OP_ADD,/* A B C R[A] := R[B] + R[C] */
+OP_SUB,/* A B C R[A] := R[B] - R[C] */
+OP_MUL,/* A B C R[A] := R[B] * R[C] */
+OP_MOD,/* A B C R[A] := R[B] % R[C] */
+OP_POW,/* A B C R[A] := R[B] ^ R[C] */
+OP_DIV,/* A B C R[A] := R[B] / R[C] */
+OP_IDIV,/* A B C R[A] := R[B] // R[C] */
+
+OP_BAND,/* A B C R[A] := R[B] & R[C] */
+OP_BOR,/* A B C R[A] := R[B] | R[C] */
+OP_BXOR,/* A B C R[A] := R[B] ~ R[C] */
+OP_SHL,/* A B C R[A] := R[B] << R[C] */
+OP_SHR,/* A B C R[A] := R[B] >> R[C] */
+
+OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] (*) */
+OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */
+OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */
+
+OP_UNM,/* A B R[A] := -R[B] */
+OP_BNOT,/* A B R[A] := ~R[B] */
+OP_NOT,/* A B R[A] := not R[B] */
+OP_LEN,/* A B R[A] := #R[B] (length operator) */
+
+OP_CONCAT,/* A B R[A] := R[A].. ... ..R[A + B - 1] */
+
+OP_CLOSE,/* A close all upvalues >= R[A] */
+OP_TBC,/* A mark variable A "to be closed" */
+OP_JMP,/* sJ pc += sJ */
+OP_EQ,/* A B k if ((R[A] == R[B]) ~= k) then pc++ */
+OP_LT,/* A B k if ((R[A] < R[B]) ~= k) then pc++ */
+OP_LE,/* A B k if ((R[A] <= R[B]) ~= k) then pc++ */
+
+OP_EQK,/* A B k if ((R[A] == K[B]) ~= k) then pc++ */
+OP_EQI,/* A sB k if ((R[A] == sB) ~= k) then pc++ */
+OP_LTI,/* A sB k if ((R[A] < sB) ~= k) then pc++ */
+OP_LEI,/* A sB k if ((R[A] <= sB) ~= k) then pc++ */
+OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */
+OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */
+
+OP_TEST,/* A k if (not R[A] == k) then pc++ */
+OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */
+
+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 k return R[A](R[A+1], ... ,R[A+B-1]) */
+
+OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] (see note) */
+OP_RETURN0,/* return */
+OP_RETURN1,/* A return R[A] */
+
+OP_FORLOOP,/* A Bx update counters; if loop continues then pc-=Bx; */
+OP_FORPREP,/* A Bx ;
+ if not to run then pc+=Bx+1; */
+
+OP_TFORPREP,/* A Bx create upvalue for R[A + 3]; pc+=Bx */
+OP_TFORCALL,/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */
+OP_TFORLOOP,/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */
+
+OP_SETLIST,/* A B C k R[A][C+i] := R[A+i], 1 <= i <= B */
+
+OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
+
+OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
+
+OP_VARARGPREP,/*A (adjust vararg parameters) */
+
+OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
+} OpCode;
+
+
+#define NUM_OPCODES ((int)(OP_EXTRAARG) + 1)
+
+
+
+/*===========================================================================
+ Notes:
+
+ (*) Opcode OP_LFALSESKIP is used to convert a condition to a boolean
+ value, in a code equivalent to (not cond ? false : true). (It
+ produces false and skips the next instruction producing true.)
+
+ (*) Opcodes OP_MMBIN and variants follow each arithmetic and
+ bitwise opcode. If the operation succeeds, it skips this next
+ opcode. Otherwise, this opcode calls the corresponding metamethod.
+
+ (*) Opcode OP_TESTSET is used in short-circuit expressions that need
+ both to jump and to produce a value, such as (a = b or c).
+
+ (*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then
+ 'top' is set to last_result+1, so next open instruction (OP_CALL,
+ OP_RETURN*, OP_SETLIST) may use 'top'.
+
+ (*) In OP_VARARG, if (C == 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_LOADKX and OP_NEWTABLE, the next instruction is always
+ OP_EXTRAARG.
+
+ (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if k, then
+ real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the
+ bits of C).
+
+ (*) In OP_NEWTABLE, B is log2 of the hash size (which is always a
+ power of 2) plus 1, or zero for size zero. If not k, the array size
+ is C. Otherwise, the array size is EXTRAARG _ C.
+
+ (*) For comparisons, k specifies what condition the test should accept
+ (true or false).
+
+ (*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped
+ (the constant is the first operand).
+
+ (*) All 'skips' (pc++) assume that next instruction is a jump.
+
+ (*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
+ function builds upvalues, which may need to be closed. C > 0 means
+ the function is vararg, so that its 'func' must be corrected before
+ returning; in this case, (C - 1) is its number of fixed parameters.
+
+ (*) In comparisons with an immediate operand, C signals whether the
+ original operand was a float. (It must be corrected in case of
+ metamethods.)
+
+===========================================================================*/
+
+
+/*
+** masks for instruction properties. The format is:
+** bits 0-2: op mode
+** bit 3: instruction set register A
+** bit 4: operator is a test (next instruction must be a jump)
+** bit 5: instruction uses 'L->top' set by previous instruction (when B == 0)
+** bit 6: instruction sets 'L->top' for next instruction (when C == 0)
+** bit 7: instruction is an MM instruction (call a metamethod)
+*/
+
+LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)
+
+#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7))
+#define testAMode(m) (luaP_opmodes[m] & (1 << 3))
+#define testTMode(m) (luaP_opmodes[m] & (1 << 4))
+#define testITMode(m) (luaP_opmodes[m] & (1 << 5))
+#define testOTMode(m) (luaP_opmodes[m] & (1 << 6))
+#define testMMMode(m) (luaP_opmodes[m] & (1 << 7))
+
+/* "out top" (set top for next instruction) */
+#define isOT(i) \
+ ((testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0) || \
+ GET_OPCODE(i) == OP_TAILCALL)
+
+/* "in top" (uses top from previous instruction) */
+#define isIT(i) (testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0)
+
+#define opmode(mm,ot,it,t,a,m) \
+ (((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m))
+
+
+/* number of list items to accumulate before a SETLIST instruction */
+#define LFIELDS_PER_FLUSH 50
+
+#endif
diff --git a/include/lua/lopnames.h b/include/lua/lopnames.h
new file mode 100644
index 00000000..965cec9b
--- /dev/null
+++ b/include/lua/lopnames.h
@@ -0,0 +1,103 @@
+/*
+** $Id: lopnames.h $
+** Opcode names
+** See Copyright Notice in lua.h
+*/
+
+#if !defined(lopnames_h)
+#define lopnames_h
+
+#include
+
+
+/* ORDER OP */
+
+static const char *const opnames[] = {
+ "MOVE",
+ "LOADI",
+ "LOADF",
+ "LOADK",
+ "LOADKX",
+ "LOADFALSE",
+ "LFALSESKIP",
+ "LOADTRUE",
+ "LOADNIL",
+ "GETUPVAL",
+ "SETUPVAL",
+ "GETTABUP",
+ "GETTABLE",
+ "GETI",
+ "GETFIELD",
+ "SETTABUP",
+ "SETTABLE",
+ "SETI",
+ "SETFIELD",
+ "NEWTABLE",
+ "SELF",
+ "ADDI",
+ "ADDK",
+ "SUBK",
+ "MULK",
+ "MODK",
+ "POWK",
+ "DIVK",
+ "IDIVK",
+ "BANDK",
+ "BORK",
+ "BXORK",
+ "SHRI",
+ "SHLI",
+ "ADD",
+ "SUB",
+ "MUL",
+ "MOD",
+ "POW",
+ "DIV",
+ "IDIV",
+ "BAND",
+ "BOR",
+ "BXOR",
+ "SHL",
+ "SHR",
+ "MMBIN",
+ "MMBINI",
+ "MMBINK",
+ "UNM",
+ "BNOT",
+ "NOT",
+ "LEN",
+ "CONCAT",
+ "CLOSE",
+ "TBC",
+ "JMP",
+ "EQ",
+ "LT",
+ "LE",
+ "EQK",
+ "EQI",
+ "LTI",
+ "LEI",
+ "GTI",
+ "GEI",
+ "TEST",
+ "TESTSET",
+ "CALL",
+ "TAILCALL",
+ "RETURN",
+ "RETURN0",
+ "RETURN1",
+ "FORLOOP",
+ "FORPREP",
+ "TFORPREP",
+ "TFORCALL",
+ "TFORLOOP",
+ "SETLIST",
+ "CLOSURE",
+ "VARARG",
+ "VARARGPREP",
+ "EXTRAARG",
+ NULL
+};
+
+#endif
+
diff --git a/include/lua/lparser.h b/include/lua/lparser.h
new file mode 100644
index 00000000..5e4500f1
--- /dev/null
+++ b/include/lua/lparser.h
@@ -0,0 +1,171 @@
+/*
+** $Id: lparser.h $
+** Lua Parser
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lparser_h
+#define lparser_h
+
+#include "llimits.h"
+#include "lobject.h"
+#include "lzio.h"
+
+
+/*
+** Expression and variable descriptor.
+** Code generation for variables and expressions can be delayed to allow
+** optimizations; An 'expdesc' structure describes a potentially-delayed
+** variable/expression. It has a description of its "main" value plus a
+** list of conditional jumps that can also produce its value (generated
+** by short-circuit operators 'and'/'or').
+*/
+
+/* kinds of variables/expressions */
+typedef enum {
+ VVOID, /* when 'expdesc' describes the last expression of a list,
+ this kind means an empty list (so, no expression) */
+ VNIL, /* constant nil */
+ VTRUE, /* constant true */
+ VFALSE, /* constant false */
+ VK, /* constant in 'k'; info = index of constant in 'k' */
+ VKFLT, /* floating constant; nval = numerical float value */
+ VKINT, /* integer constant; ival = numerical integer value */
+ VKSTR, /* string constant; strval = TString address;
+ (string is fixed by the lexer) */
+ VNONRELOC, /* expression has its value in a fixed register;
+ info = result register */
+ VLOCAL, /* local variable; var.ridx = register index;
+ var.vidx = relative index in 'actvar.arr' */
+ VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
+ VCONST, /* compile-time variable;
+ info = absolute index in 'actvar.arr' */
+ VINDEXED, /* indexed variable;
+ ind.t = table register;
+ ind.idx = key's R index */
+ VINDEXUP, /* indexed upvalue;
+ ind.t = table upvalue;
+ ind.idx = key's K index */
+ VINDEXI, /* indexed variable with constant integer;
+ ind.t = table register;
+ ind.idx = key's value */
+ VINDEXSTR, /* indexed variable with literal string;
+ ind.t = table register;
+ ind.idx = key's K index */
+ VJMP, /* expression is a test/comparison;
+ info = pc of corresponding jump instruction */
+ VRELOC, /* expression can put result in any register;
+ info = instruction pc */
+ VCALL, /* expression is a function call; info = instruction pc */
+ VVARARG /* vararg expression; info = instruction pc */
+} expkind;
+
+
+#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXSTR)
+#define vkisindexed(k) (VINDEXED <= (k) && (k) <= VINDEXSTR)
+
+
+typedef struct expdesc {
+ expkind k;
+ union {
+ lua_Integer ival; /* for VKINT */
+ lua_Number nval; /* for VKFLT */
+ TString *strval; /* for VKSTR */
+ int info; /* for generic use */
+ struct { /* for indexed variables */
+ short idx; /* index (R or "long" K) */
+ lu_byte t; /* table (register or upvalue) */
+ } ind;
+ struct { /* for local variables */
+ lu_byte ridx; /* register holding the variable */
+ unsigned short vidx; /* compiler index (in 'actvar.arr') */
+ } var;
+ } u;
+ int t; /* patch list of 'exit when true' */
+ int f; /* patch list of 'exit when false' */
+} expdesc;
+
+
+/* kinds of variables */
+#define VDKREG 0 /* regular */
+#define RDKCONST 1 /* constant */
+#define RDKTOCLOSE 2 /* to-be-closed */
+#define RDKCTC 3 /* compile-time constant */
+
+/* description of an active local variable */
+typedef union Vardesc {
+ struct {
+ TValuefields; /* constant value (if it is a compile-time constant) */
+ lu_byte kind;
+ lu_byte ridx; /* register holding the variable */
+ short pidx; /* index of the variable in the Proto's 'locvars' array */
+ TString *name; /* variable name */
+ } vd;
+ TValue k; /* constant value (if any) */
+} Vardesc;
+
+
+
+/* description of pending goto statements and label statements */
+typedef struct Labeldesc {
+ TString *name; /* label identifier */
+ int pc; /* position in code */
+ int line; /* line where it appeared */
+ lu_byte nactvar; /* number of active variables in that position */
+ lu_byte close; /* goto that escapes upvalues */
+} Labeldesc;
+
+
+/* list of labels or gotos */
+typedef struct Labellist {
+ Labeldesc *arr; /* array */
+ int n; /* number of entries in use */
+ int size; /* array size */
+} Labellist;
+
+
+/* dynamic structures used by the parser */
+typedef struct Dyndata {
+ struct { /* list of all active local variables */
+ Vardesc *arr;
+ int n;
+ int size;
+ } actvar;
+ Labellist gt; /* list of pending gotos */
+ Labellist label; /* list of active labels */
+} Dyndata;
+
+
+/* control of blocks */
+struct BlockCnt; /* defined in lparser.c */
+
+
+/* state needed to generate code for a given function */
+typedef struct FuncState {
+ Proto *f; /* current function header */
+ struct FuncState *prev; /* enclosing function */
+ struct LexState *ls; /* lexical state */
+ struct BlockCnt *bl; /* chain of current blocks */
+ int pc; /* next position to code (equivalent to 'ncode') */
+ int lasttarget; /* 'label' of last 'jump label' */
+ int previousline; /* last line that was saved in 'lineinfo' */
+ int nk; /* number of elements in 'k' */
+ int np; /* number of elements in 'p' */
+ int nabslineinfo; /* number of elements in 'abslineinfo' */
+ int firstlocal; /* index of first local var (in Dyndata array) */
+ int firstlabel; /* index of first label (in 'dyd->label->arr') */
+ short ndebugvars; /* number of elements in 'f->locvars' */
+ lu_byte nactvar; /* number of active local variables */
+ lu_byte nups; /* number of upvalues */
+ lu_byte freereg; /* first free register */
+ lu_byte iwthabs; /* instructions issued since last absolute line info */
+ lu_byte needclose; /* function needs to close upvalues when returning */
+} FuncState;
+
+
+LUAI_FUNC int luaY_nvarstack (FuncState *fs);
+LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
+ Dyndata *dyd, const char *name, int firstchar);
+
+
+#endif
diff --git a/include/lua/lprefix.h b/include/lua/lprefix.h
new file mode 100644
index 00000000..484f2ad6
--- /dev/null
+++ b/include/lua/lprefix.h
@@ -0,0 +1,45 @@
+/*
+** $Id: lprefix.h $
+** Definitions for Lua code that must come before any other header file
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lprefix_h
+#define lprefix_h
+
+
+/*
+** Allows POSIX/XSI stuff
+*/
+#if !defined(LUA_USE_C89) /* { */
+
+#if !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE 600
+#elif _XOPEN_SOURCE == 0
+#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */
+#endif
+
+/*
+** Allows manipulation of large files in gcc and some other compilers
+*/
+#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS)
+#define _LARGEFILE_SOURCE 1
+#define _FILE_OFFSET_BITS 64
+#endif
+
+#endif /* } */
+
+
+/*
+** Windows stuff
+*/
+#if defined(_WIN32) /* { */
+
+#if !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */
+#endif
+
+#endif /* } */
+
+#endif
+
diff --git a/include/lua/lstate.h b/include/lua/lstate.h
new file mode 100644
index 00000000..61e82cde
--- /dev/null
+++ b/include/lua/lstate.h
@@ -0,0 +1,404 @@
+/*
+** $Id: lstate.h $
+** 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"
+
+
+/*
+** Some notes about garbage-collected objects: All objects in Lua must
+** be kept somehow accessible until being freed, so all objects always
+** belong to one (and only one) of these lists, using field 'next' of
+** the 'CommonHeader' for the link:
+**
+** 'allgc': all objects not marked for finalization;
+** 'finobj': all objects marked for finalization;
+** 'tobefnz': all objects ready to be finalized;
+** 'fixedgc': all objects that are not to be collected (currently
+** only small strings, such as reserved words).
+**
+** For the generational collector, some of these lists have marks for
+** generations. Each mark points to the first element in the list for
+** that particular generation; that generation goes until the next mark.
+**
+** 'allgc' -> 'survival': new objects;
+** 'survival' -> 'old': objects that survived one collection;
+** 'old1' -> 'reallyold': objects that became old in last collection;
+** 'reallyold' -> NULL: objects old for more than one cycle.
+**
+** 'finobj' -> 'finobjsur': new objects marked for finalization;
+** 'finobjsur' -> 'finobjold1': survived """";
+** 'finobjold1' -> 'finobjrold': just old """";
+** 'finobjrold' -> NULL: really old """".
+**
+** All lists can contain elements older than their main ages, due
+** to 'luaC_checkfinalizer' and 'udata2finalize', which move
+** objects between the normal lists and the "marked for finalization"
+** lists. Moreover, barriers can age young objects in young lists as
+** OLD0, which then become OLD1. However, a list never contains
+** elements younger than their main ages.
+**
+** The generational collector also uses a pointer 'firstold1', which
+** points to the first OLD1 object in the list. It is used to optimize
+** 'markold'. (Potentially OLD1 objects can be anywhere between 'allgc'
+** and 'reallyold', but often the list has no OLD1 objects or they are
+** after 'old1'.) Note the difference between it and 'old1':
+** 'firstold1': no OLD1 objects before this point; there can be all
+** ages after it.
+** 'old1': no objects younger than OLD1 after this point.
+*/
+
+/*
+** Moreover, there is another set of lists that control gray objects.
+** These lists are linked by fields 'gclist'. (All objects that
+** can become gray have such a field. The field is not the same
+** in all objects, but it always has this name.) Any gray object
+** must belong to one of these lists, and all objects in these lists
+** must be gray (with two exceptions explained below):
+**
+** 'gray': regular gray objects, still waiting to be visited.
+** 'grayagain': objects that must be revisited at the atomic phase.
+** That includes
+** - black objects got in a write barrier;
+** - all kinds of weak tables during propagation phase;
+** - all threads.
+** 'weak': tables with weak values to be cleared;
+** 'ephemeron': ephemeron tables with white->white entries;
+** 'allweak': tables with weak keys and/or weak values to be cleared.
+**
+** The exceptions to that "gray rule" are:
+** - TOUCHED2 objects in generational mode stay in a gray list (because
+** they must be visited again at the end of the cycle), but they are
+** marked black because assignments to them must activate barriers (to
+** move them back to TOUCHED1).
+** - Open upvales are kept gray to avoid barriers, but they stay out
+** of gray lists. (They don't even have a 'gclist' field.)
+*/
+
+
+
+/*
+** About 'nCcalls': This count has two parts: the lower 16 bits counts
+** the number of recursive invocations in the C stack; the higher
+** 16 bits counts the number of non-yieldable calls in the stack.
+** (They are together so that we can change and save both with one
+** instruction.)
+*/
+
+
+/* true if this thread does not have non-yieldable calls in the stack */
+#define yieldable(L) (((L)->nCcalls & 0xffff0000) == 0)
+
+/* real number of C calls */
+#define getCcalls(L) ((L)->nCcalls & 0xffff)
+
+
+/* Increment the number of non-yieldable calls */
+#define incnny(L) ((L)->nCcalls += 0x10000)
+
+/* Decrement the number of non-yieldable calls */
+#define decnny(L) ((L)->nCcalls -= 0x10000)
+
+/* Non-yieldable call increment */
+#define nyci (0x10000 | 1)
+
+
+
+
+struct lua_longjmp; /* defined in ldo.c */
+
+
+/*
+** Atomic type (relative to signals) to better ensure that 'lua_sethook'
+** is thread safe
+*/
+#if !defined(l_signalT)
+#include
+#define l_signalT sig_atomic_t
+#endif
+
+
+/*
+** Extra stack space to handle TM calls and some other extras. This
+** space is not included in 'stack_last'. It is used only to avoid stack
+** checks, either because the element will be promptly popped or because
+** there will be a stack check soon after the push. Function frames
+** never use this extra space, so it does not need to be kept clean.
+*/
+#define EXTRA_STACK 5
+
+
+#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
+
+#define stacksize(th) cast_int((th)->stack_last - (th)->stack)
+
+
+/* kinds of Garbage Collection */
+#define KGC_INC 0 /* incremental gc */
+#define KGC_GEN 1 /* generational gc */
+
+
+typedef struct stringtable {
+ TString **hash;
+ int nuse; /* number of elements */
+ int size;
+} stringtable;
+
+
+/*
+** Information about a call.
+** About union 'u':
+** - field 'l' is used only for Lua functions;
+** - field 'c' is used only for C functions.
+** About union 'u2':
+** - field 'funcidx' is used only by C functions while doing a
+** protected call;
+** - field 'nyield' is used only while a function is "doing" an
+** yield (from the yield until the next resume);
+** - field 'nres' is used only while closing tbc variables when
+** returning from a function;
+** - field 'transferinfo' is used only during call/returnhooks,
+** before the function starts or after it ends.
+*/
+typedef struct CallInfo {
+ StkId func; /* function index in the stack */
+ StkId top; /* top for this function */
+ struct CallInfo *previous, *next; /* dynamic call link */
+ union {
+ struct { /* only for Lua functions */
+ const Instruction *savedpc;
+ volatile l_signalT trap;
+ int nextraargs; /* # of extra arguments in vararg functions */
+ } l;
+ struct { /* only for C functions */
+ lua_KFunction k; /* continuation in case of yields */
+ ptrdiff_t old_errfunc;
+ lua_KContext ctx; /* context info. in case of yields */
+ } c;
+ } u;
+ union {
+ int funcidx; /* called-function index */
+ int nyield; /* number of values yielded */
+ int nres; /* number of values returned */
+ struct { /* info about transferred values (for call/return hooks) */
+ unsigned short ftransfer; /* offset of first value transferred */
+ unsigned short ntransfer; /* number of values transferred */
+ } transferinfo;
+ } u2;
+ short nresults; /* expected number of results from this function */
+ unsigned short callstatus;
+} CallInfo;
+
+
+/*
+** Bits in CallInfo status
+*/
+#define CIST_OAH (1<<0) /* original value of 'allowhook' */
+#define CIST_C (1<<1) /* call is running a C function */
+#define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */
+#define CIST_HOOKED (1<<3) /* call is running a debug hook */
+#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */
+#define CIST_TAIL (1<<5) /* call was tail called */
+#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
+#define CIST_FIN (1<<7) /* function "called" a finalizer */
+#define CIST_TRAN (1<<8) /* 'ci' has transfer information */
+#define CIST_CLSRET (1<<9) /* function is closing tbc variables */
+/* Bits 10-12 are used for CIST_RECST (see below) */
+#define CIST_RECST 10
+#if defined(LUA_COMPAT_LT_LE)
+#define CIST_LEQ (1<<13) /* using __lt for __le */
+#endif
+
+
+/*
+** Field CIST_RECST stores the "recover status", used to keep the error
+** status while closing to-be-closed variables in coroutines, so that
+** Lua can correctly resume after an yield from a __close method called
+** because of an error. (Three bits are enough for error status.)
+*/
+#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7)
+#define setcistrecst(ci,st) \
+ check_exp(((st) & 7) == (st), /* status must fit in three bits */ \
+ ((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST)) \
+ | ((st) << CIST_RECST)))
+
+
+/* active function is a Lua function */
+#define isLua(ci) (!((ci)->callstatus & CIST_C))
+
+/* call is running Lua code (not a hook) */
+#define isLuacode(ci) (!((ci)->callstatus & (CIST_C | CIST_HOOKED)))
+
+/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */
+#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v))
+#define getoah(st) ((st) & CIST_OAH)
+
+
+/*
+** 'global state', shared by all threads of this state
+*/
+typedef struct global_State {
+ lua_Alloc frealloc; /* function to reallocate memory */
+ void *ud; /* auxiliary data to 'frealloc' */
+ l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
+ l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
+ lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
+ lu_mem lastatomic; /* see function 'genstep' in file 'lgc.c' */
+ stringtable strt; /* hash table for strings */
+ TValue l_registry;
+ TValue nilvalue; /* a nil value */
+ unsigned int seed; /* randomized seed for hashes */
+ lu_byte currentwhite;
+ lu_byte gcstate; /* state of garbage collector */
+ lu_byte gckind; /* kind of GC running */
+ lu_byte gcstopem; /* stops emergency collections */
+ lu_byte genminormul; /* control for minor generational collections */
+ lu_byte genmajormul; /* control for major generational collections */
+ lu_byte gcstp; /* control whether GC is running */
+ lu_byte gcemergency; /* true if this is an emergency collection */
+ lu_byte gcpause; /* size of pause between successive GCs */
+ lu_byte gcstepmul; /* GC "speed" */
+ lu_byte gcstepsize; /* (log2 of) GC granularity */
+ GCObject *allgc; /* list of all collectable objects */
+ GCObject **sweepgc; /* current position of sweep in list */
+ GCObject *finobj; /* list of collectable objects with finalizers */
+ GCObject *gray; /* list of gray objects */
+ GCObject *grayagain; /* list of objects to be traversed atomically */
+ GCObject *weak; /* list of tables with weak values */
+ GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
+ GCObject *allweak; /* list of all-weak tables */
+ GCObject *tobefnz; /* list of userdata to be GC */
+ GCObject *fixedgc; /* list of objects not to be collected */
+ /* fields for generational collector */
+ GCObject *survival; /* start of objects that survived one GC cycle */
+ GCObject *old1; /* start of old1 objects */
+ GCObject *reallyold; /* objects more than one cycle old ("really old") */
+ GCObject *firstold1; /* first OLD1 object in the list (if any) */
+ GCObject *finobjsur; /* list of survival objects with finalizers */
+ GCObject *finobjold1; /* list of old1 objects with finalizers */
+ GCObject *finobjrold; /* list of really old objects with finalizers */
+ struct lua_State *twups; /* list of threads with open upvalues */
+ lua_CFunction panic; /* to be called in unprotected errors */
+ struct lua_State *mainthread;
+ TString *memerrmsg; /* message for memory-allocation errors */
+ TString *tmname[TM_N]; /* array with tag-method names */
+ struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
+ TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
+ lua_WarnFunction warnf; /* warning function */
+ void *ud_warn; /* auxiliary data to 'warnf' */
+} global_State;
+
+
+/*
+** 'per thread' state
+*/
+struct lua_State {
+ CommonHeader;
+ lu_byte status;
+ lu_byte allowhook;
+ unsigned short nci; /* number of items in 'ci' list */
+ StkId top; /* first free slot in the stack */
+ global_State *l_G;
+ CallInfo *ci; /* call info for current function */
+ StkId stack_last; /* end of stack (last element + 1) */
+ StkId stack; /* stack base */
+ UpVal *openupval; /* list of open upvalues in this stack */
+ StkId tbclist; /* list of to-be-closed variables */
+ GCObject *gclist;
+ struct lua_State *twups; /* list of threads with open upvalues */
+ struct lua_longjmp *errorJmp; /* current error recover point */
+ CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
+ volatile lua_Hook hook;
+ ptrdiff_t errfunc; /* current error handling function (stack index) */
+ l_uint32 nCcalls; /* number of nested (non-yieldable | C) calls */
+ int oldpc; /* last pc traced */
+ int basehookcount;
+ int hookcount;
+ volatile l_signalT hookmask;
+};
+
+
+#define G(L) (L->l_G)
+
+/*
+** 'g->nilvalue' being a nil value flags that the state was completely
+** build.
+*/
+#define completestate(g) ttisnil(&g->nilvalue)
+
+
+/*
+** Union of all collectable objects (only for conversions)
+** ISO C99, 6.5.2.3 p.5:
+** "if a union contains several structures that share a common initial
+** sequence [...], and if the union object currently contains one
+** of these structures, it is permitted to inspect the common initial
+** part of any of them anywhere that a declaration of the complete type
+** of the union is visible."
+*/
+union GCUnion {
+ GCObject gc; /* common header */
+ struct TString ts;
+ struct Udata u;
+ union Closure cl;
+ struct Table h;
+ struct Proto p;
+ struct lua_State th; /* thread */
+ struct UpVal upv;
+};
+
+
+/*
+** ISO C99, 6.7.2.1 p.14:
+** "A pointer to a union object, suitably converted, points to each of
+** its members [...], and vice versa."
+*/
+#define cast_u(o) cast(union GCUnion *, (o))
+
+/* macros to convert a GCObject into a specific value */
+#define gco2ts(o) \
+ check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))
+#define gco2u(o) check_exp((o)->tt == LUA_VUSERDATA, &((cast_u(o))->u))
+#define gco2lcl(o) check_exp((o)->tt == LUA_VLCL, &((cast_u(o))->cl.l))
+#define gco2ccl(o) check_exp((o)->tt == LUA_VCCL, &((cast_u(o))->cl.c))
+#define gco2cl(o) \
+ check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))
+#define gco2t(o) check_exp((o)->tt == LUA_VTABLE, &((cast_u(o))->h))
+#define gco2p(o) check_exp((o)->tt == LUA_VPROTO, &((cast_u(o))->p))
+#define gco2th(o) check_exp((o)->tt == LUA_VTHREAD, &((cast_u(o))->th))
+#define gco2upv(o) check_exp((o)->tt == LUA_VUPVAL, &((cast_u(o))->upv))
+
+
+/*
+** macro to convert a Lua object into a GCObject
+** (The access to 'tt' tries to ensure that 'v' is actually a Lua object.)
+*/
+#define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc))
+
+
+/* actual number of total bytes allocated */
+#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt)
+
+LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
+LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
+LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
+LUAI_FUNC void luaE_freeCI (lua_State *L);
+LUAI_FUNC void luaE_shrinkCI (lua_State *L);
+LUAI_FUNC void luaE_checkcstack (lua_State *L);
+LUAI_FUNC void luaE_incCstack (lua_State *L);
+LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
+LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
+LUAI_FUNC int luaE_resetthread (lua_State *L, int status);
+
+
+#endif
+
diff --git a/include/lua/lstring.h b/include/lua/lstring.h
new file mode 100644
index 00000000..450c2390
--- /dev/null
+++ b/include/lua/lstring.h
@@ -0,0 +1,57 @@
+/*
+** $Id: lstring.h $
+** 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"
+
+
+/*
+** Memory-allocation error message must be preallocated (it cannot
+** be created after memory is exhausted)
+*/
+#define MEMERRMSG "not enough memory"
+
+
+/*
+** Size of a TString: Size of the header plus space for the string
+** itself (including final '\0').
+*/
+#define sizelstring(l) (offsetof(TString, contents) + ((l) + 1) * sizeof(char))
+
+#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
+ (sizeof(s)/sizeof(char))-1))
+
+
+/*
+** test whether a string is a reserved word
+*/
+#define isreserved(s) ((s)->tt == LUA_VSHRSTR && (s)->extra > 0)
+
+
+/*
+** equality for short strings, which are always internalized
+*/
+#define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b))
+
+
+LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
+LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
+LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
+LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
+LUAI_FUNC void luaS_clearcache (global_State *g);
+LUAI_FUNC void luaS_init (lua_State *L);
+LUAI_FUNC void luaS_remove (lua_State *L, TString *ts);
+LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue);
+LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
+LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
+LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
+
+
+#endif
diff --git a/include/lua/ltable.h b/include/lua/ltable.h
new file mode 100644
index 00000000..7bbbcb21
--- /dev/null
+++ b/include/lua/ltable.h
@@ -0,0 +1,66 @@
+/*
+** $Id: ltable.h $
+** 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 gval(n) (&(n)->i_val)
+#define gnext(n) ((n)->u.next)
+
+
+/*
+** Clear all bits of fast-access metamethods, which means that the table
+** may have any of these metamethods. (First access that fails after the
+** clearing will set the bit again.)
+*/
+#define invalidateTMcache(t) ((t)->flags &= ~maskflags)
+
+
+/* true when 't' is using 'dummynode' as its hash part */
+#define isdummy(t) ((t)->lastfree == NULL)
+
+
+/* allocated size for hash nodes */
+#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t))
+
+
+/* returns the Node, given the value of a table entry */
+#define nodefromval(v) cast(Node *, (v))
+
+
+LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
+LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
+ TValue *value);
+LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
+LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
+LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
+LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
+ TValue *value);
+LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
+ TValue *value);
+LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
+ const TValue *slot, TValue *value);
+LUAI_FUNC Table *luaH_new (lua_State *L);
+LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
+ unsigned int nhsize);
+LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned 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 lua_Unsigned luaH_getn (Table *t);
+LUAI_FUNC unsigned int luaH_realasize (const Table *t);
+
+
+#if defined(LUA_DEBUG)
+LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
+LUAI_FUNC int luaH_isdummy (const Table *t);
+#endif
+
+
+#endif
diff --git a/include/lua/ltm.h b/include/lua/ltm.h
new file mode 100644
index 00000000..73b833c6
--- /dev/null
+++ b/include/lua/ltm.h
@@ -0,0 +1,103 @@
+/*
+** $Id: ltm.h $
+** 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" and "ORDER OP"
+*/
+typedef enum {
+ TM_INDEX,
+ TM_NEWINDEX,
+ TM_GC,
+ TM_MODE,
+ TM_LEN,
+ TM_EQ, /* last tag method with fast access */
+ TM_ADD,
+ TM_SUB,
+ TM_MUL,
+ TM_MOD,
+ TM_POW,
+ TM_DIV,
+ TM_IDIV,
+ TM_BAND,
+ TM_BOR,
+ TM_BXOR,
+ TM_SHL,
+ TM_SHR,
+ TM_UNM,
+ TM_BNOT,
+ TM_LT,
+ TM_LE,
+ TM_CONCAT,
+ TM_CALL,
+ TM_CLOSE,
+ TM_N /* number of elements in the enum */
+} TMS;
+
+
+/*
+** Mask with 1 in all fast-access methods. A 1 in any of these bits
+** in the flag of a (meta)table means the metatable does not have the
+** corresponding metamethod field. (Bit 7 of the flag is used for
+** 'isrealasize'.)
+*/
+#define maskflags (~(~0u << (TM_EQ + 1)))
+
+
+/*
+** Test whether there is no tagmethod.
+** (Because tagmethods use raw accesses, the result may be an "empty" nil.)
+*/
+#define notm(tm) ttisnil(tm)
+
+
+#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)
+
+#define ttypename(x) luaT_typenames_[(x) + 1]
+
+LUAI_DDEC(const char *const luaT_typenames_[LUA_TOTALTYPES];)
+
+
+LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
+
+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);
+
+LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
+ const TValue *p2, const TValue *p3);
+LUAI_FUNC void luaT_callTMres (lua_State *L, const TValue *f,
+ const TValue *p1, const TValue *p2, StkId p3);
+LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
+ StkId res, TMS event);
+LUAI_FUNC void luaT_tryconcatTM (lua_State *L);
+LUAI_FUNC void luaT_trybinassocTM (lua_State *L, const TValue *p1,
+ const TValue *p2, int inv, StkId res, TMS event);
+LUAI_FUNC void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
+ int inv, StkId res, TMS event);
+LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
+ const TValue *p2, TMS event);
+LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
+ int inv, int isfloat, TMS event);
+
+LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
+ struct CallInfo *ci, const Proto *p);
+LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
+ StkId where, int wanted);
+
+
+#endif
diff --git a/include/lua/lua.h b/include/lua/lua.h
new file mode 100644
index 00000000..e6618392
--- /dev/null
+++ b/include/lua/lua.h
@@ -0,0 +1,518 @@
+/*
+** $Id: lua.h $
+** Lua - A Scripting 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_MAJOR "5"
+#define LUA_VERSION_MINOR "4"
+#define LUA_VERSION_RELEASE "4"
+
+#define LUA_VERSION_NUM 504
+#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4)
+
+#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
+#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio"
+#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
+
+
+/* mark for precompiled code ('Lua') */
+#define LUA_SIGNATURE "\x1bLua"
+
+/* option for multiple returns in 'lua_pcall' and 'lua_call' */
+#define LUA_MULTRET (-1)
+
+
+/*
+** Pseudo-indices
+** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
+** space after that to help overflow detection)
+*/
+#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
+#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
+
+
+/* thread status */
+#define LUA_OK 0
+#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;
+
+
+/*
+** 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
+
+#define LUA_NUMTYPES 9
+
+
+
+/* minimum Lua stack available to a C function */
+#define LUA_MINSTACK 20
+
+
+/* predefined values in the registry */
+#define LUA_RIDX_MAINTHREAD 1
+#define LUA_RIDX_GLOBALS 2
+#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
+
+
+/* type of numbers in Lua */
+typedef LUA_NUMBER lua_Number;
+
+
+/* type for integer functions */
+typedef LUA_INTEGER lua_Integer;
+
+/* unsigned integer type */
+typedef LUA_UNSIGNED lua_Unsigned;
+
+/* type for continuation-function contexts */
+typedef LUA_KCONTEXT lua_KContext;
+
+
+/*
+** Type for C functions registered with Lua
+*/
+typedef int (*lua_CFunction) (lua_State *L);
+
+/*
+** Type for continuation functions
+*/
+typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
+
+
+/*
+** Type for 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);
+
+
+/*
+** Type for memory-allocation functions
+*/
+typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
+
+
+/*
+** Type for warning functions
+*/
+typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
+
+
+
+
+/*
+** generic extra include file
+*/
+#if defined(LUA_USER_H)
+#include LUA_USER_H
+#endif
+
+
+/*
+** RCS ident string
+*/
+extern const char lua_ident[];
+
+
+/*
+** 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 int (lua_resetthread) (lua_State *L);
+
+LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
+
+
+LUA_API lua_Number (lua_version) (lua_State *L);
+
+
+/*
+** basic stack manipulation
+*/
+LUA_API int (lua_absindex) (lua_State *L, int idx);
+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_rotate) (lua_State *L, int idx, int n);
+LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx);
+LUA_API int (lua_checkstack) (lua_State *L, int n);
+
+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_isinteger) (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 lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
+LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
+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 lua_Unsigned (lua_rawlen) (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);
+
+
+/*
+** Comparison and arithmetic functions
+*/
+
+#define LUA_OPADD 0 /* ORDER TM, ORDER OP */
+#define LUA_OPSUB 1
+#define LUA_OPMUL 2
+#define LUA_OPMOD 3
+#define LUA_OPPOW 4
+#define LUA_OPDIV 5
+#define LUA_OPIDIV 6
+#define LUA_OPBAND 7
+#define LUA_OPBOR 8
+#define LUA_OPBXOR 9
+#define LUA_OPSHL 10
+#define LUA_OPSHR 11
+#define LUA_OPUNM 12
+#define LUA_OPBNOT 13
+
+LUA_API void (lua_arith) (lua_State *L, int op);
+
+#define LUA_OPEQ 0
+#define LUA_OPLT 1
+#define LUA_OPLE 2
+
+LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
+LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op);
+
+
+/*
+** 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 const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
+LUA_API const char *(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 int (lua_getglobal) (lua_State *L, const char *name);
+LUA_API int (lua_gettable) (lua_State *L, int idx);
+LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
+LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);
+LUA_API int (lua_rawget) (lua_State *L, int idx);
+LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
+LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
+
+LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
+LUA_API void *(lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue);
+LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
+LUA_API int (lua_getiuservalue) (lua_State *L, int idx, int n);
+
+
+/*
+** set functions (stack -> Lua)
+*/
+LUA_API void (lua_setglobal) (lua_State *L, const char *name);
+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_seti) (lua_State *L, int idx, lua_Integer n);
+LUA_API void (lua_rawset) (lua_State *L, int idx);
+LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n);
+LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p);
+LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
+LUA_API int (lua_setiuservalue) (lua_State *L, int idx, int n);
+
+
+/*
+** 'load' and 'call' functions (load and run Lua code)
+*/
+LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults,
+ lua_KContext ctx, lua_KFunction k);
+#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
+
+LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
+ lua_KContext ctx, lua_KFunction k);
+#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
+
+LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
+ const char *chunkname, const char *mode);
+
+LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
+
+
+/*
+** coroutine functions
+*/
+LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx,
+ lua_KFunction k);
+LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg,
+ int *nres);
+LUA_API int (lua_status) (lua_State *L);
+LUA_API int (lua_isyieldable) (lua_State *L);
+
+#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
+
+
+/*
+** Warning-related functions
+*/
+LUA_API void (lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud);
+LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont);
+
+
+/*
+** 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
+#define LUA_GCISRUNNING 9
+#define LUA_GCGEN 10
+#define LUA_GCINC 11
+
+LUA_API int (lua_gc) (lua_State *L, int what, ...);
+
+
+/*
+** 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 void (lua_len) (lua_State *L, int idx);
+
+LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
+
+LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
+LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
+
+LUA_API void (lua_toclose) (lua_State *L, int idx);
+LUA_API void (lua_closeslot) (lua_State *L, int idx);
+
+
+/*
+** {==============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE))
+
+#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL)
+#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL)
+
+#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_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_pushstring(L, "" s)
+
+#define lua_pushglobaltable(L) \
+ ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
+
+#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
+
+
+#define lua_insert(L,idx) lua_rotate(L, (idx), 1)
+
+#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
+
+#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))
+
+/* }============================================================== */
+
+
+/*
+** {==============================================================
+** compatibility macros
+** ===============================================================
+*/
+#if defined(LUA_COMPAT_APIINTCASTS)
+
+#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
+#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is))
+#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL)
+
+#endif
+
+#define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1)
+#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1)
+#define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1)
+
+#define LUA_NUMTAGS LUA_NUMTYPES
+
+/* }============================================================== */
+
+/*
+** {======================================================================
+** Debug API
+** =======================================================================
+*/
+
+
+/*
+** Event codes
+*/
+#define LUA_HOOKCALL 0
+#define LUA_HOOKRET 1
+#define LUA_HOOKLINE 2
+#define LUA_HOOKCOUNT 3
+#define LUA_HOOKTAILCALL 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 debugger 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 void *(lua_upvalueid) (lua_State *L, int fidx, int n);
+LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,
+ int fidx2, int n2);
+
+LUA_API void (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);
+
+LUA_API int (lua_setcstacklimit) (lua_State *L, unsigned int limit);
+
+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) */
+ size_t srclen; /* (S) */
+ int currentline; /* (l) */
+ int linedefined; /* (S) */
+ int lastlinedefined; /* (S) */
+ unsigned char nups; /* (u) number of upvalues */
+ unsigned char nparams;/* (u) number of parameters */
+ char isvararg; /* (u) */
+ char istailcall; /* (t) */
+ unsigned short ftransfer; /* (r) index of first value transferred */
+ unsigned short ntransfer; /* (r) number of transferred values */
+ char short_src[LUA_IDSIZE]; /* (S) */
+ /* private part */
+ struct CallInfo *i_ci; /* active function */
+};
+
+/* }====================================================================== */
+
+
+/******************************************************************************
+* Copyright (C) 1994-2022 Lua.org, PUC-Rio.
+*
+* 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/include/lua/lua.hpp b/include/lua/lua.hpp
new file mode 100644
index 00000000..ec417f59
--- /dev/null
+++ b/include/lua/lua.hpp
@@ -0,0 +1,9 @@
+// lua.hpp
+// Lua header files for C++
+// <> not supplied automatically because Lua also compiles as C++
+
+extern "C" {
+#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
+}
diff --git a/include/lua/luaconf.h b/include/lua/luaconf.h
new file mode 100644
index 00000000..d42d14b7
--- /dev/null
+++ b/include/lua/luaconf.h
@@ -0,0 +1,786 @@
+/*
+** $Id: luaconf.h $
+** Configuration file for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef luaconf_h
+#define luaconf_h
+
+#include
+#include
+
+
+/*
+** ===================================================================
+** General Configuration File for Lua
+**
+** Some definitions here can be changed externally, through the compiler
+** (e.g., with '-D' options): They are commented out or protected
+** by '#if !defined' guards. However, several other definitions
+** should be changed directly here, either because they affect the
+** Lua ABI (by making the changes here, you ensure that all software
+** connected to Lua, such as C libraries, will be compiled with the same
+** configuration); or because they are seldom changed.
+**
+** Search for "@@" to find all configurable definitions.
+** ===================================================================
+*/
+
+
+/*
+** {====================================================================
+** System Configuration: macros to adapt (if needed) Lua to some
+** particular platform, for instance restricting it to C89.
+** =====================================================================
+*/
+
+/*
+@@ LUA_USE_C89 controls the use of non-ISO-C89 features.
+** Define it if you want Lua to avoid the use of a few C99 features
+** or Windows-specific features on Windows.
+*/
+/* #define LUA_USE_C89 */
+
+
+/*
+** By default, Lua on Windows use (some) specific Windows features
+*/
+#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)
+#define LUA_USE_WINDOWS /* enable goodies for regular Windows */
+#endif
+
+
+#if defined(LUA_USE_WINDOWS)
+#define LUA_DL_DLL /* enable support for DLL */
+#define LUA_USE_C89 /* broadly, Windows is C89 */
+#endif
+
+
+#if defined(LUA_USE_LINUX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
+#endif
+
+
+#if defined(LUA_USE_MACOSX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN /* MacOS does not need -ldl */
+#endif
+
+
+/*
+@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
+*/
+#define LUAI_IS32INT ((UINT_MAX >> 30) >= 3)
+
+/* }================================================================== */
+
+
+
+/*
+** {==================================================================
+** Configuration for Number types. These options should not be
+** set externally, because any other code connected to Lua must
+** use the same configuration.
+** ===================================================================
+*/
+
+/*
+@@ LUA_INT_TYPE defines the type for Lua integers.
+@@ LUA_FLOAT_TYPE defines the type for Lua floats.
+** Lua should work fine with any mix of these options supported
+** by your C compiler. The usual configurations are 64-bit integers
+** and 'double' (the default), 32-bit integers and 'float' (for
+** restricted platforms), and 'long'/'double' (for C compilers not
+** compliant with C99, which may not have support for 'long long').
+*/
+
+/* predefined options for LUA_INT_TYPE */
+#define LUA_INT_INT 1
+#define LUA_INT_LONG 2
+#define LUA_INT_LONGLONG 3
+
+/* predefined options for LUA_FLOAT_TYPE */
+#define LUA_FLOAT_FLOAT 1
+#define LUA_FLOAT_DOUBLE 2
+#define LUA_FLOAT_LONGDOUBLE 3
+
+
+/* Default configuration ('long long' and 'double', for 64-bit Lua) */
+#define LUA_INT_DEFAULT LUA_INT_LONGLONG
+#define LUA_FLOAT_DEFAULT LUA_FLOAT_DOUBLE
+
+
+/*
+@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
+*/
+#define LUA_32BITS 0
+
+
+/*
+@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
+** C89 ('long' and 'double'); Windows always has '__int64', so it does
+** not need to use this case.
+*/
+#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
+#define LUA_C89_NUMBERS 1
+#else
+#define LUA_C89_NUMBERS 0
+#endif
+
+
+#if LUA_32BITS /* { */
+/*
+** 32-bit integers and 'float'
+*/
+#if LUAI_IS32INT /* use 'int' if big enough */
+#define LUA_INT_TYPE LUA_INT_INT
+#else /* otherwise use 'long' */
+#define LUA_INT_TYPE LUA_INT_LONG
+#endif
+#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
+
+#elif LUA_C89_NUMBERS /* }{ */
+/*
+** largest types available for C89 ('long' and 'double')
+*/
+#define LUA_INT_TYPE LUA_INT_LONG
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+
+#else /* }{ */
+/* use defaults */
+
+#define LUA_INT_TYPE LUA_INT_DEFAULT
+#define LUA_FLOAT_TYPE LUA_FLOAT_DEFAULT
+
+#endif /* } */
+
+
+/* }================================================================== */
+
+
+
+/*
+** {==================================================================
+** Configuration for Paths.
+** ===================================================================
+*/
+
+/*
+** LUA_PATH_SEP is the character that separates templates in a path.
+** LUA_PATH_MARK is the string that marks the substitution points in a
+** template.
+** LUA_EXEC_DIR in a Windows path is replaced by the executable's
+** directory.
+*/
+#define LUA_PATH_SEP ";"
+#define LUA_PATH_MARK "?"
+#define LUA_EXEC_DIR "!"
+
+
+/*
+@@ 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.
+*/
+
+#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
+#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_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\"
+
+#if !defined(LUA_PATH_DEFAULT)
+#define LUA_PATH_DEFAULT \
+ LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
+ LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \
+ ".\\?.lua;" ".\\?\\init.lua"
+#endif
+
+#if !defined(LUA_CPATH_DEFAULT)
+#define LUA_CPATH_DEFAULT \
+ LUA_CDIR"?.dll;" \
+ LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
+ LUA_CDIR"loadall.dll;" ".\\?.dll"
+#endif
+
+#else /* }{ */
+
+#define LUA_ROOT "/usr/local/"
+#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/"
+#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/"
+
+#if !defined(LUA_PATH_DEFAULT)
+#define LUA_PATH_DEFAULT \
+ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
+ "./?.lua;" "./?/init.lua"
+#endif
+
+#if !defined(LUA_CPATH_DEFAULT)
+#define LUA_CPATH_DEFAULT \
+ LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so"
+#endif
+
+#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(LUA_DIRSEP)
+
+#if defined(_WIN32)
+#define LUA_DIRSEP "\\"
+#else
+#define LUA_DIRSEP "/"
+#endif
+
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Marks for exported symbols in the C code
+** ===================================================================
+*/
+
+/*
+@@ LUA_API is a mark for all core API functions.
+@@ LUALIB_API is a mark for all auxiliary library functions.
+@@ LUAMOD_API is a mark for all standard library opening 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
+#define LUAMOD_API LUA_API
+
+
+/*
+@@ LUAI_FUNC is a mark for all extern functions that are not to be
+** exported to outside modules.
+@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables,
+** none of which to be exported to outside modules (LUAI_DDEF for
+** definitions and LUAI_DDEC for declarations).
+** 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. Not all elf targets support
+** this attribute. Unfortunately, gcc does not offer a way to check
+** whether the target offers that support, and those without support
+** give a warning about it. To avoid these warnings, change to the
+** default definition.
+*/
+#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
+ defined(__ELF__) /* { */
+#define LUAI_FUNC __attribute__((visibility("internal"))) extern
+#else /* }{ */
+#define LUAI_FUNC extern
+#endif /* } */
+
+#define LUAI_DDEC(dec) LUAI_FUNC dec
+#define LUAI_DDEF /* empty */
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Compatibility with previous versions
+** ===================================================================
+*/
+
+/*
+@@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3.
+** You can define it to get all options, or change specific options
+** to fit your specific needs.
+*/
+#if defined(LUA_COMPAT_5_3) /* { */
+
+/*
+@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
+** functions in the mathematical library.
+** (These functions were already officially removed in 5.3;
+** nevertheless they are still available here.)
+*/
+#define LUA_COMPAT_MATHLIB
+
+/*
+@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for
+** manipulating other integer types (lua_pushunsigned, lua_tounsigned,
+** luaL_checkint, luaL_checklong, etc.)
+** (These macros were also officially removed in 5.3, but they are still
+** available here.)
+*/
+#define LUA_COMPAT_APIINTCASTS
+
+
+/*
+@@ LUA_COMPAT_LT_LE controls the emulation of the '__le' metamethod
+** using '__lt'.
+*/
+#define LUA_COMPAT_LT_LE
+
+
+/*
+@@ The following macros supply trivial compatibility for some
+** changes in the API. The macros themselves document how to
+** change your code to avoid using them.
+** (Once more, these macros were officially removed in 5.3, but they are
+** still available here.)
+*/
+#define lua_strlen(L,i) lua_rawlen(L, (i))
+
+#define lua_objlen(L,i) lua_rawlen(L, (i))
+
+#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
+#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
+
+#endif /* } */
+
+/* }================================================================== */
+
+
+
+/*
+** {==================================================================
+** Configuration for Numbers (low-level part).
+** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
+** satisfy your needs.
+** ===================================================================
+*/
+
+/*
+@@ LUAI_UACNUMBER is the result of a 'default argument promotion'
+@@ over a floating number.
+@@ l_floatatt(x) corrects float attribute 'x' to the proper float type
+** by prefixing it with one of FLT/DBL/LDBL.
+@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
+@@ LUA_NUMBER_FMT is the format for writing floats.
+@@ lua_number2str converts a float to a string.
+@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
+@@ l_floor takes the floor of a float.
+@@ lua_str2number converts a decimal numeral to a number.
+*/
+
+
+/* The following definitions are good for most cases here */
+
+#define l_floor(x) (l_mathop(floor)(x))
+
+#define lua_number2str(s,sz,n) \
+ l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n))
+
+/*
+@@ lua_numbertointeger converts a float number with an integral value
+** to an integer, or returns 0 if float is not within the range of
+** a lua_Integer. (The range comparisons are tricky because of
+** rounding. The tests here assume a two-complement representation,
+** where MININTEGER always has an exact representation as a float;
+** MAXINTEGER may not have one, and therefore its conversion to float
+** may have an ill-defined value.)
+*/
+#define lua_numbertointeger(n,p) \
+ ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
+ (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
+ (*(p) = (LUA_INTEGER)(n), 1))
+
+
+/* now the variable definitions */
+
+#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
+
+#define LUA_NUMBER float
+
+#define l_floatatt(n) (FLT_##n)
+
+#define LUAI_UACNUMBER double
+
+#define LUA_NUMBER_FRMLEN ""
+#define LUA_NUMBER_FMT "%.7g"
+
+#define l_mathop(op) op##f
+
+#define lua_str2number(s,p) strtof((s), (p))
+
+
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
+
+#define LUA_NUMBER long double
+
+#define l_floatatt(n) (LDBL_##n)
+
+#define LUAI_UACNUMBER long double
+
+#define LUA_NUMBER_FRMLEN "L"
+#define LUA_NUMBER_FMT "%.19Lg"
+
+#define l_mathop(op) op##l
+
+#define lua_str2number(s,p) strtold((s), (p))
+
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
+
+#define LUA_NUMBER double
+
+#define l_floatatt(n) (DBL_##n)
+
+#define LUAI_UACNUMBER double
+
+#define LUA_NUMBER_FRMLEN ""
+#define LUA_NUMBER_FMT "%.14g"
+
+#define l_mathop(op) op
+
+#define lua_str2number(s,p) strtod((s), (p))
+
+#else /* }{ */
+
+#error "numeric float type not defined"
+
+#endif /* } */
+
+
+
+/*
+@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
+@@ LUAI_UACINT is the result of a 'default argument promotion'
+@@ over a LUA_INTEGER.
+@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
+@@ LUA_INTEGER_FMT is the format for writing integers.
+@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
+@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
+@@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED.
+@@ lua_integer2str converts an integer to a string.
+*/
+
+
+/* The following definitions are good for most cases here */
+
+#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
+
+#define LUAI_UACINT LUA_INTEGER
+
+#define lua_integer2str(s,sz,n) \
+ l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n))
+
+/*
+** use LUAI_UACINT here to avoid problems with promotions (which
+** can turn a comparison between unsigneds into a signed comparison)
+*/
+#define LUA_UNSIGNED unsigned LUAI_UACINT
+
+
+/* now the variable definitions */
+
+#if LUA_INT_TYPE == LUA_INT_INT /* { int */
+
+#define LUA_INTEGER int
+#define LUA_INTEGER_FRMLEN ""
+
+#define LUA_MAXINTEGER INT_MAX
+#define LUA_MININTEGER INT_MIN
+
+#define LUA_MAXUNSIGNED UINT_MAX
+
+#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
+
+#define LUA_INTEGER long
+#define LUA_INTEGER_FRMLEN "l"
+
+#define LUA_MAXINTEGER LONG_MAX
+#define LUA_MININTEGER LONG_MIN
+
+#define LUA_MAXUNSIGNED ULONG_MAX
+
+#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
+
+/* use presence of macro LLONG_MAX as proxy for C99 compliance */
+#if defined(LLONG_MAX) /* { */
+/* use ISO C99 stuff */
+
+#define LUA_INTEGER long long
+#define LUA_INTEGER_FRMLEN "ll"
+
+#define LUA_MAXINTEGER LLONG_MAX
+#define LUA_MININTEGER LLONG_MIN
+
+#define LUA_MAXUNSIGNED ULLONG_MAX
+
+#elif defined(LUA_USE_WINDOWS) /* }{ */
+/* in Windows, can use specific Windows types */
+
+#define LUA_INTEGER __int64
+#define LUA_INTEGER_FRMLEN "I64"
+
+#define LUA_MAXINTEGER _I64_MAX
+#define LUA_MININTEGER _I64_MIN
+
+#define LUA_MAXUNSIGNED _UI64_MAX
+
+#else /* }{ */
+
+#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \
+ or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)"
+
+#endif /* } */
+
+#else /* }{ */
+
+#error "numeric integer type not defined"
+
+#endif /* } */
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Dependencies with C99 and other C details
+** ===================================================================
+*/
+
+/*
+@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
+** (All uses in Lua have only one format item.)
+*/
+#if !defined(LUA_USE_C89)
+#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
+#else
+#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
+#endif
+
+
+/*
+@@ lua_strx2number converts a hexadecimal numeral to a number.
+** In C99, 'strtod' does that conversion. Otherwise, you can
+** leave 'lua_strx2number' undefined and Lua will provide its own
+** implementation.
+*/
+#if !defined(LUA_USE_C89)
+#define lua_strx2number(s,p) lua_str2number(s,p)
+#endif
+
+
+/*
+@@ lua_pointer2str converts a pointer to a readable string in a
+** non-specified way.
+*/
+#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p)
+
+
+/*
+@@ lua_number2strx converts a float to a hexadecimal numeral.
+** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
+** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
+** provide its own implementation.
+*/
+#if !defined(LUA_USE_C89)
+#define lua_number2strx(L,b,sz,f,n) \
+ ((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n)))
+#endif
+
+
+/*
+** 'strtof' and 'opf' variants for math functions are not valid in
+** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the
+** availability of these variants. ('math.h' is already included in
+** all files that use these macros.)
+*/
+#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF))
+#undef l_mathop /* variants not available */
+#undef lua_str2number
+#define l_mathop(op) (lua_Number)op /* no variant */
+#define lua_str2number(s,p) ((lua_Number)strtod((s), (p)))
+#endif
+
+
+/*
+@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation
+** functions. It must be a numerical type; Lua will use 'intptr_t' if
+** available, otherwise it will use 'ptrdiff_t' (the nearest thing to
+** 'intptr_t' in C89)
+*/
+#define LUA_KCONTEXT ptrdiff_t
+
+#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 199901L
+#include
+#if defined(INTPTR_MAX) /* even in C99 this type is optional */
+#undef LUA_KCONTEXT
+#define LUA_KCONTEXT intptr_t
+#endif
+#endif
+
+
+/*
+@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
+** Change that if you do not want to use C locales. (Code using this
+** macro must include the header 'locale.h'.)
+*/
+#if !defined(lua_getlocaledecpoint)
+#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
+#endif
+
+
+/*
+** macros to improve jump prediction, used mostly for error handling
+** and debug facilities. (Some macros in the Lua API use these macros.
+** Define LUA_NOBUILTIN if you do not want '__builtin_expect' in your
+** code.)
+*/
+#if !defined(luai_likely)
+
+#if defined(__GNUC__) && !defined(LUA_NOBUILTIN)
+#define luai_likely(x) (__builtin_expect(((x) != 0), 1))
+#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0))
+#else
+#define luai_likely(x) (x)
+#define luai_unlikely(x) (x)
+#endif
+
+#endif
+
+
+#if defined(LUA_CORE) || defined(LUA_LIB)
+/* shorter names for Lua's own use */
+#define l_likely(x) luai_likely(x)
+#define l_unlikely(x) luai_unlikely(x)
+#endif
+
+
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Language Variations
+** =====================================================================
+*/
+
+/*
+@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some
+** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from
+** numbers to strings. Define LUA_NOCVTS2N to turn off automatic
+** coercion from strings to numbers.
+*/
+/* #define LUA_NOCVTN2S */
+/* #define LUA_NOCVTS2N */
+
+
+/*
+@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
+** Define it as a help when debugging C code.
+*/
+#if defined(LUA_USE_APICHECK)
+#include
+#define luai_apicheck(l,e) assert(e)
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Macros that affect the API and must be stable (that is, must be the
+** same when you compile Lua and when you compile code that links to
+** Lua).
+** =====================================================================
+*/
+
+/*
+@@ LUAI_MAXSTACK limits the size of the Lua stack.
+** CHANGE it if you need a different limit. This limit is arbitrary;
+** its only purpose is to stop Lua from consuming unlimited stack
+** space (and to reserve some numbers for pseudo-indices).
+** (It must fit into max(size_t)/32.)
+*/
+#if LUAI_IS32INT
+#define LUAI_MAXSTACK 1000000
+#else
+#define LUAI_MAXSTACK 15000
+#endif
+
+
+/*
+@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
+** a Lua state with very fast access.
+** CHANGE it if you need a different size.
+*/
+#define LUA_EXTRASPACE (sizeof(void *))
+
+
+/*
+@@ 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
+
+
+/*
+@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+*/
+#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
+
+
+/*
+@@ LUAI_MAXALIGN defines fields that, when used in a union, ensure
+** maximum alignment for the other items in that union.
+*/
+#define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l
+
+/* }================================================================== */
+
+
+
+
+
+/* =================================================================== */
+
+/*
+** Local configuration. You can use this space to add your redefinitions
+** without modifying the main part of the file.
+*/
+
+
+
+
+
+#endif
+
diff --git a/include/lua/lualib.h b/include/lua/lualib.h
new file mode 100644
index 00000000..26255290
--- /dev/null
+++ b/include/lua/lualib.h
@@ -0,0 +1,52 @@
+/*
+** $Id: lualib.h $
+** Lua standard libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lualib_h
+#define lualib_h
+
+#include "lua.h"
+
+
+/* version suffix for environment variable names */
+#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
+
+
+LUAMOD_API int (luaopen_base) (lua_State *L);
+
+#define LUA_COLIBNAME "coroutine"
+LUAMOD_API int (luaopen_coroutine) (lua_State *L);
+
+#define LUA_TABLIBNAME "table"
+LUAMOD_API int (luaopen_table) (lua_State *L);
+
+#define LUA_IOLIBNAME "io"
+LUAMOD_API int (luaopen_io) (lua_State *L);
+
+#define LUA_OSLIBNAME "os"
+LUAMOD_API int (luaopen_os) (lua_State *L);
+
+#define LUA_STRLIBNAME "string"
+LUAMOD_API int (luaopen_string) (lua_State *L);
+
+#define LUA_UTF8LIBNAME "utf8"
+LUAMOD_API int (luaopen_utf8) (lua_State *L);
+
+#define LUA_MATHLIBNAME "math"
+LUAMOD_API int (luaopen_math) (lua_State *L);
+
+#define LUA_DBLIBNAME "debug"
+LUAMOD_API int (luaopen_debug) (lua_State *L);
+
+#define LUA_LOADLIBNAME "package"
+LUAMOD_API int (luaopen_package) (lua_State *L);
+
+
+/* open all previous libraries */
+LUALIB_API void (luaL_openlibs) (lua_State *L);
+
+
+#endif
diff --git a/include/lua/lundump.h b/include/lua/lundump.h
new file mode 100644
index 00000000..f3748a99
--- /dev/null
+++ b/include/lua/lundump.h
@@ -0,0 +1,36 @@
+/*
+** $Id: lundump.h $
+** load precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lundump_h
+#define lundump_h
+
+#include "llimits.h"
+#include "lobject.h"
+#include "lzio.h"
+
+
+/* data to catch conversion errors */
+#define LUAC_DATA "\x19\x93\r\n\x1a\n"
+
+#define LUAC_INT 0x5678
+#define LUAC_NUM cast_num(370.5)
+
+/*
+** Encode major-minor version in one byte, one nibble for each
+*/
+#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */
+#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
+
+#define LUAC_FORMAT 0 /* this is the official format */
+
+/* load one chunk; from lundump.c */
+LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name);
+
+/* dump one chunk; from ldump.c */
+LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
+ void* data, int strip);
+
+#endif
diff --git a/include/lua/lvm.h b/include/lua/lvm.h
new file mode 100644
index 00000000..1bc16f3a
--- /dev/null
+++ b/include/lua/lvm.h
@@ -0,0 +1,136 @@
+/*
+** $Id: lvm.h $
+** Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lvm_h
+#define lvm_h
+
+
+#include "ldo.h"
+#include "lobject.h"
+#include "ltm.h"
+
+
+#if !defined(LUA_NOCVTN2S)
+#define cvt2str(o) ttisnumber(o)
+#else
+#define cvt2str(o) 0 /* no conversion from numbers to strings */
+#endif
+
+
+#if !defined(LUA_NOCVTS2N)
+#define cvt2num(o) ttisstring(o)
+#else
+#define cvt2num(o) 0 /* no conversion from strings to numbers */
+#endif
+
+
+/*
+** You can define LUA_FLOORN2I if you want to convert floats to integers
+** by flooring them (instead of raising an error if they are not
+** integral values)
+*/
+#if !defined(LUA_FLOORN2I)
+#define LUA_FLOORN2I F2Ieq
+#endif
+
+
+/*
+** Rounding modes for float->integer coercion
+ */
+typedef enum {
+ F2Ieq, /* no rounding; accepts only integral values */
+ F2Ifloor, /* takes the floor of the number */
+ F2Iceil /* takes the ceil of the number */
+} F2Imod;
+
+
+/* convert an object to a float (including string coercion) */
+#define tonumber(o,n) \
+ (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
+
+
+/* convert an object to a float (without string coercion) */
+#define tonumberns(o,n) \
+ (ttisfloat(o) ? ((n) = fltvalue(o), 1) : \
+ (ttisinteger(o) ? ((n) = cast_num(ivalue(o)), 1) : 0))
+
+
+/* convert an object to an integer (including string coercion) */
+#define tointeger(o,i) \
+ (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \
+ : luaV_tointeger(o,i,LUA_FLOORN2I))
+
+
+/* convert an object to an integer (without string coercion) */
+#define tointegerns(o,i) \
+ (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \
+ : luaV_tointegerns(o,i,LUA_FLOORN2I))
+
+
+#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
+
+#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)
+
+
+/*
+** fast track for 'gettable': if 't' is a table and 't[k]' is present,
+** return 1 with 'slot' pointing to 't[k]' (position of final result).
+** Otherwise, return 0 (meaning it will have to check metamethod)
+** with 'slot' pointing to an empty 't[k]' (if 't' is a table) or NULL
+** (otherwise). 'f' is the raw get function to use.
+*/
+#define luaV_fastget(L,t,k,slot,f) \
+ (!ttistable(t) \
+ ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
+ : (slot = f(hvalue(t), k), /* else, do raw access */ \
+ !isempty(slot))) /* result not empty? */
+
+
+/*
+** Special case of 'luaV_fastget' for integers, inlining the fast case
+** of 'luaH_getint'.
+*/
+#define luaV_fastgeti(L,t,k,slot) \
+ (!ttistable(t) \
+ ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
+ : (slot = (l_castS2U(k) - 1u < hvalue(t)->alimit) \
+ ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \
+ !isempty(slot))) /* result not empty? */
+
+
+/*
+** Finish a fast set operation (when fast get succeeds). In that case,
+** 'slot' points to the place to put the value.
+*/
+#define luaV_finishfastset(L,t,slot,v) \
+ { setobj2t(L, cast(TValue *,slot), v); \
+ luaC_barrierback(L, gcvalue(t), v); }
+
+
+
+
+LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
+LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
+LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
+LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
+LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode);
+LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p,
+ F2Imod mode);
+LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode);
+LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
+ StkId val, const TValue *slot);
+LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
+ TValue *val, const TValue *slot);
+LUAI_FUNC void luaV_finishOp (lua_State *L);
+LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci);
+LUAI_FUNC void luaV_concat (lua_State *L, int total);
+LUAI_FUNC lua_Integer luaV_idiv (lua_State *L, lua_Integer x, lua_Integer y);
+LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y);
+LUAI_FUNC lua_Number luaV_modf (lua_State *L, lua_Number x, lua_Number y);
+LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y);
+LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb);
+
+#endif
diff --git a/include/lua/lzio.h b/include/lua/lzio.h
new file mode 100644
index 00000000..38f397fd
--- /dev/null
+++ b/include/lua/lzio.h
@@ -0,0 +1,66 @@
+/*
+** $Id: lzio.h $
+** 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 zgetc(z) (((z)->n--)>0 ? cast_uchar(*(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_buffremove(buff,i) ((buff)->n -= (i))
+#define luaZ_resetbuffer(buff) ((buff)->n = 0)
+
+
+#define luaZ_resizebuffer(L, buff, size) \
+ ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \
+ (buff)->buffsize, size), \
+ (buff)->buffsize = size)
+
+#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0)
+
+
+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 */
+
+
+
+/* --------- Private Part ------------------ */
+
+struct Zio {
+ size_t n; /* bytes still unread */
+ const char *p; /* current position in buffer */
+ lua_Reader reader; /* reader function */
+ void *data; /* additional data */
+ lua_State *L; /* Lua state (for reader) */
+};
+
+
+LUAI_FUNC int luaZ_fill (ZIO *z);
+
+#endif
diff --git a/lib/win/lua54.dll b/lib/win/lua54.dll
new file mode 100644
index 00000000..77ff13fd
Binary files /dev/null and b/lib/win/lua54.dll differ
diff --git a/lua/client/client.lua b/lua/client/client.lua
new file mode 100644
index 00000000..0ed8b6f8
--- /dev/null
+++ b/lua/client/client.lua
@@ -0,0 +1,25 @@
+local Client = class('Client')
+
+freekill.client_callback = {}
+
+function Client:initialize()
+ self.client = freekill.ClientInstance
+ self.notifyUI = function(self, command, json_data)
+ freekill.Backend:emitNotifyUI(command, json_data)
+ end
+ self.client.callback = function(_self, command, json_data)
+ local cb = freekill.client_callback[command]
+ if (type(cb) == "function") then
+ cb(json_data)
+ else
+ self:notifyUI("error_msg", "Unknown command " .. command);
+ end
+ end
+end
+
+freekill.client_callback["enter_lobby"] = function(json_data)
+ ClientInstance:notifyUI("enter_lobby", json_data)
+end
+
+-- Create ClientInstance (used by Lua)
+ClientInstance = Client:new()
diff --git a/lua/core/card.lua b/lua/core/card.lua
new file mode 100644
index 00000000..31e9bc11
--- /dev/null
+++ b/lua/core/card.lua
@@ -0,0 +1,52 @@
+-- class Card : public Object
+local Card = class('Card')
+
+-- public:
+
+-- enum Suit
+Card.Suit = {
+ Spade = 0,
+ Club = 1,
+ Heart = 2,
+ Diamond = 3,
+ NoSuitBlack = 4,
+ NoSuitRed = 5,
+ NoSuit = 6,
+ SuitToBeDecided = -1,
+}
+
+-- enum Color
+Card.Color = {
+ Red = 0,
+ Black = 1,
+ Colorless = 2,
+}
+
+-- enum HandlingMethod
+Card.HandlingMethod = {
+ MethodNone = 0,
+ MethodUse = 1,
+ MethodResponse = 2,
+ MethodDiscard = 3,
+ MethodRecast = 4,
+ MethodPindian = 5,
+}
+function Card:initialize(suit, number)
+
+end
+
+-- private:
+local subcards = {} -- array of cards
+local target_fixed
+local mute
+local will_throw
+local has_preact
+local can_recast
+local m_suit
+local m_number
+local id
+local skill_name
+local handling_method
+local flags = {}
+
+return Card
diff --git a/lua/freekill.lua b/lua/freekill.lua
new file mode 100644
index 00000000..4ae794e6
--- /dev/null
+++ b/lua/freekill.lua
@@ -0,0 +1,16 @@
+-- Fundemental script for FreeKill
+-- Load mods, init the engine, etc.
+
+package.path = package.path .. ';./lua/lib/?.lua'
+
+-- load libraries
+class = require 'middleclass'
+json = require 'json'
+
+function pt(t)
+ for k, v in pairs(t) do
+ print(k, v)
+ end
+end
+
+-- load core classes
diff --git a/lua/lib/json.lua b/lua/lib/json.lua
new file mode 100644
index 00000000..711ef786
--- /dev/null
+++ b/lua/lib/json.lua
@@ -0,0 +1,388 @@
+--
+-- json.lua
+--
+-- Copyright (c) 2020 rxi
+--
+-- 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.
+--
+
+local json = { _version = "0.1.2" }
+
+-------------------------------------------------------------------------------
+-- Encode
+-------------------------------------------------------------------------------
+
+local encode
+
+local escape_char_map = {
+ [ "\\" ] = "\\",
+ [ "\"" ] = "\"",
+ [ "\b" ] = "b",
+ [ "\f" ] = "f",
+ [ "\n" ] = "n",
+ [ "\r" ] = "r",
+ [ "\t" ] = "t",
+}
+
+local escape_char_map_inv = { [ "/" ] = "/" }
+for k, v in pairs(escape_char_map) do
+ escape_char_map_inv[v] = k
+end
+
+
+local function escape_char(c)
+ return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
+end
+
+
+local function encode_nil(val)
+ return "null"
+end
+
+
+local function encode_table(val, stack)
+ local res = {}
+ stack = stack or {}
+
+ -- Circular reference?
+ if stack[val] then error("circular reference") end
+
+ stack[val] = true
+
+ if rawget(val, 1) ~= nil or next(val) == nil then
+ -- Treat as array -- check keys are valid and it is not sparse
+ local n = 0
+ for k in pairs(val) do
+ if type(k) ~= "number" then
+ error("invalid table: mixed or invalid key types")
+ end
+ n = n + 1
+ end
+ if n ~= #val then
+ error("invalid table: sparse array")
+ end
+ -- Encode
+ for i, v in ipairs(val) do
+ table.insert(res, encode(v, stack))
+ end
+ stack[val] = nil
+ return "[" .. table.concat(res, ",") .. "]"
+
+ else
+ -- Treat as an object
+ for k, v in pairs(val) do
+ if type(k) ~= "string" then
+ error("invalid table: mixed or invalid key types")
+ end
+ table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
+ end
+ stack[val] = nil
+ return "{" .. table.concat(res, ",") .. "}"
+ end
+end
+
+
+local function encode_string(val)
+ return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
+end
+
+
+local function encode_number(val)
+ -- Check for NaN, -inf and inf
+ if val ~= val or val <= -math.huge or val >= math.huge then
+ error("unexpected number value '" .. tostring(val) .. "'")
+ end
+ return string.format("%.14g", val)
+end
+
+
+local type_func_map = {
+ [ "nil" ] = encode_nil,
+ [ "table" ] = encode_table,
+ [ "string" ] = encode_string,
+ [ "number" ] = encode_number,
+ [ "boolean" ] = tostring,
+}
+
+
+encode = function(val, stack)
+ local t = type(val)
+ local f = type_func_map[t]
+ if f then
+ return f(val, stack)
+ end
+ error("unexpected type '" .. t .. "'")
+end
+
+
+function json.encode(val)
+ return ( encode(val) )
+end
+
+
+-------------------------------------------------------------------------------
+-- Decode
+-------------------------------------------------------------------------------
+
+local parse
+
+local function create_set(...)
+ local res = {}
+ for i = 1, select("#", ...) do
+ res[ select(i, ...) ] = true
+ end
+ return res
+end
+
+local space_chars = create_set(" ", "\t", "\r", "\n")
+local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
+local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
+local literals = create_set("true", "false", "null")
+
+local literal_map = {
+ [ "true" ] = true,
+ [ "false" ] = false,
+ [ "null" ] = nil,
+}
+
+
+local function next_char(str, idx, set, negate)
+ for i = idx, #str do
+ if set[str:sub(i, i)] ~= negate then
+ return i
+ end
+ end
+ return #str + 1
+end
+
+
+local function decode_error(str, idx, msg)
+ local line_count = 1
+ local col_count = 1
+ for i = 1, idx - 1 do
+ col_count = col_count + 1
+ if str:sub(i, i) == "\n" then
+ line_count = line_count + 1
+ col_count = 1
+ end
+ end
+ error( string.format("%s at line %d col %d", msg, line_count, col_count) )
+end
+
+
+local function codepoint_to_utf8(n)
+ -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
+ local f = math.floor
+ if n <= 0x7f then
+ return string.char(n)
+ elseif n <= 0x7ff then
+ return string.char(f(n / 64) + 192, n % 64 + 128)
+ elseif n <= 0xffff then
+ return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
+ elseif n <= 0x10ffff then
+ return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
+ f(n % 4096 / 64) + 128, n % 64 + 128)
+ end
+ error( string.format("invalid unicode codepoint '%x'", n) )
+end
+
+
+local function parse_unicode_escape(s)
+ local n1 = tonumber( s:sub(1, 4), 16 )
+ local n2 = tonumber( s:sub(7, 10), 16 )
+ -- Surrogate pair?
+ if n2 then
+ return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
+ else
+ return codepoint_to_utf8(n1)
+ end
+end
+
+
+local function parse_string(str, i)
+ local res = ""
+ local j = i + 1
+ local k = j
+
+ while j <= #str do
+ local x = str:byte(j)
+
+ if x < 32 then
+ decode_error(str, j, "control character in string")
+
+ elseif x == 92 then -- `\`: Escape
+ res = res .. str:sub(k, j - 1)
+ j = j + 1
+ local c = str:sub(j, j)
+ if c == "u" then
+ local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
+ or str:match("^%x%x%x%x", j + 1)
+ or decode_error(str, j - 1, "invalid unicode escape in string")
+ res = res .. parse_unicode_escape(hex)
+ j = j + #hex
+ else
+ if not escape_chars[c] then
+ decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
+ end
+ res = res .. escape_char_map_inv[c]
+ end
+ k = j + 1
+
+ elseif x == 34 then -- `"`: End of string
+ res = res .. str:sub(k, j - 1)
+ return res, j + 1
+ end
+
+ j = j + 1
+ end
+
+ decode_error(str, i, "expected closing quote for string")
+end
+
+
+local function parse_number(str, i)
+ local x = next_char(str, i, delim_chars)
+ local s = str:sub(i, x - 1)
+ local n = tonumber(s)
+ if not n then
+ decode_error(str, i, "invalid number '" .. s .. "'")
+ end
+ return n, x
+end
+
+
+local function parse_literal(str, i)
+ local x = next_char(str, i, delim_chars)
+ local word = str:sub(i, x - 1)
+ if not literals[word] then
+ decode_error(str, i, "invalid literal '" .. word .. "'")
+ end
+ return literal_map[word], x
+end
+
+
+local function parse_array(str, i)
+ local res = {}
+ local n = 1
+ i = i + 1
+ while 1 do
+ local x
+ i = next_char(str, i, space_chars, true)
+ -- Empty / end of array?
+ if str:sub(i, i) == "]" then
+ i = i + 1
+ break
+ end
+ -- Read token
+ x, i = parse(str, i)
+ res[n] = x
+ n = n + 1
+ -- Next token
+ i = next_char(str, i, space_chars, true)
+ local chr = str:sub(i, i)
+ i = i + 1
+ if chr == "]" then break end
+ if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
+ end
+ return res, i
+end
+
+
+local function parse_object(str, i)
+ local res = {}
+ i = i + 1
+ while 1 do
+ local key, val
+ i = next_char(str, i, space_chars, true)
+ -- Empty / end of object?
+ if str:sub(i, i) == "}" then
+ i = i + 1
+ break
+ end
+ -- Read key
+ if str:sub(i, i) ~= '"' then
+ decode_error(str, i, "expected string for key")
+ end
+ key, i = parse(str, i)
+ -- Read ':' delimiter
+ i = next_char(str, i, space_chars, true)
+ if str:sub(i, i) ~= ":" then
+ decode_error(str, i, "expected ':' after key")
+ end
+ i = next_char(str, i + 1, space_chars, true)
+ -- Read value
+ val, i = parse(str, i)
+ -- Set
+ res[key] = val
+ -- Next token
+ i = next_char(str, i, space_chars, true)
+ local chr = str:sub(i, i)
+ i = i + 1
+ if chr == "}" then break end
+ if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
+ end
+ return res, i
+end
+
+
+local char_func_map = {
+ [ '"' ] = parse_string,
+ [ "0" ] = parse_number,
+ [ "1" ] = parse_number,
+ [ "2" ] = parse_number,
+ [ "3" ] = parse_number,
+ [ "4" ] = parse_number,
+ [ "5" ] = parse_number,
+ [ "6" ] = parse_number,
+ [ "7" ] = parse_number,
+ [ "8" ] = parse_number,
+ [ "9" ] = parse_number,
+ [ "-" ] = parse_number,
+ [ "t" ] = parse_literal,
+ [ "f" ] = parse_literal,
+ [ "n" ] = parse_literal,
+ [ "[" ] = parse_array,
+ [ "{" ] = parse_object,
+}
+
+
+parse = function(str, idx)
+ local chr = str:sub(idx, idx)
+ local f = char_func_map[chr]
+ if f then
+ return f(str, idx)
+ end
+ decode_error(str, idx, "unexpected character '" .. chr .. "'")
+end
+
+
+function json.decode(str)
+ if type(str) ~= "string" then
+ error("expected argument of type string, got " .. type(str))
+ end
+ local res, idx = parse(str, next_char(str, 1, space_chars, true))
+ idx = next_char(str, idx, space_chars, true)
+ if idx <= #str then
+ decode_error(str, idx, "trailing garbage")
+ end
+ return res
+end
+
+
+return json
diff --git a/lua/lib/middleclass.lua b/lua/lib/middleclass.lua
new file mode 100644
index 00000000..b479f1ef
--- /dev/null
+++ b/lua/lib/middleclass.lua
@@ -0,0 +1,189 @@
+local middleclass = {
+ _VERSION = 'middleclass v4.1.1',
+ _DESCRIPTION = 'Object Orientation for Lua',
+ _URL = 'https://github.com/kikito/middleclass',
+ _LICENSE = [[
+ MIT LICENSE
+ Copyright (c) 2011 Enrique García Cota
+ 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.
+ ]]
+}
+
+local function _createIndexWrapper(aClass, f)
+ if f == nil then
+ return aClass.__instanceDict
+ elseif type(f) == "function" then
+ return function(self, name)
+ local value = aClass.__instanceDict[name]
+
+ if value ~= nil then
+ return value
+ else
+ return (f(self, name))
+ end
+ end
+ else -- if type(f) == "table" then
+ return function(self, name)
+ local value = aClass.__instanceDict[name]
+
+ if value ~= nil then
+ return value
+ else
+ return f[name]
+ end
+ end
+ end
+end
+
+local function _propagateInstanceMethod(aClass, name, f)
+ f = name == "__index" and _createIndexWrapper(aClass, f) or f
+ aClass.__instanceDict[name] = f
+
+ for subclass in pairs(aClass.subclasses) do
+ if rawget(subclass.__declaredMethods, name) == nil then
+ _propagateInstanceMethod(subclass, name, f)
+ end
+ end
+end
+
+local function _declareInstanceMethod(aClass, name, f)
+ aClass.__declaredMethods[name] = f
+
+ if f == nil and aClass.super then
+ f = aClass.super.__instanceDict[name]
+ end
+
+ _propagateInstanceMethod(aClass, name, f)
+end
+
+local function _tostring(self) return "class " .. self.name end
+local function _call(self, ...) return self:new(...) end
+
+local function _createClass(name, super)
+ local dict = {}
+ dict.__index = dict
+
+ local aClass = { name = name, super = super, static = {},
+ __instanceDict = dict, __declaredMethods = {},
+ subclasses = setmetatable({}, {__mode='k'}) }
+
+ if super then
+ setmetatable(aClass.static, {
+ __index = function(_,k)
+ local result = rawget(dict,k)
+ if result == nil then
+ return super.static[k]
+ end
+ return result
+ end
+ })
+ else
+ setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) end })
+ end
+
+ setmetatable(aClass, { __index = aClass.static, __tostring = _tostring,
+ __call = _call, __newindex = _declareInstanceMethod })
+
+ return aClass
+end
+
+local function _includeMixin(aClass, mixin)
+ assert(type(mixin) == 'table', "mixin must be a table")
+
+ for name,method in pairs(mixin) do
+ if name ~= "included" and name ~= "static" then aClass[name] = method end
+ end
+
+ for name,method in pairs(mixin.static or {}) do
+ aClass.static[name] = method
+ end
+
+ if type(mixin.included)=="function" then mixin:included(aClass) end
+ return aClass
+end
+
+local DefaultMixin = {
+ __tostring = function(self) return "instance of " .. tostring(self.class) end,
+
+ initialize = function(self, ...) end,
+
+ isInstanceOf = function(self, aClass)
+ return type(aClass) == 'table'
+ and type(self) == 'table'
+ and (self.class == aClass
+ or type(self.class) == 'table'
+ and type(self.class.isSubclassOf) == 'function'
+ and self.class:isSubclassOf(aClass))
+ end,
+
+ static = {
+ allocate = function(self)
+ assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
+ return setmetatable({ class = self }, self.__instanceDict)
+ end,
+
+ new = function(self, ...)
+ assert(type(self) == 'table', "Make sure that you are using 'Class:new' instead of 'Class.new'")
+ local instance = self:allocate()
+ instance:initialize(...)
+ return instance
+ end,
+
+ subclass = function(self, name)
+ assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
+ assert(type(name) == "string", "You must provide a name(string) for your class")
+
+ local subclass = _createClass(name, self)
+
+ for methodName, f in pairs(self.__instanceDict) do
+ if not (methodName == "__index" and type(f) == "table") then
+ _propagateInstanceMethod(subclass, methodName, f)
+ end
+ end
+ subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end
+
+ self.subclasses[subclass] = true
+ self:subclassed(subclass)
+
+ return subclass
+ end,
+
+ subclassed = function(self, other) end,
+
+ isSubclassOf = function(self, other)
+ return type(other) == 'table' and
+ type(self.super) == 'table' and
+ ( self.super == other or self.super:isSubclassOf(other) )
+ end,
+
+ include = function(self, ...)
+ assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'")
+ for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
+ return self
+ end
+ }
+}
+
+function middleclass.class(name, super)
+ assert(type(name) == 'string', "A name (string) is needed for the new class")
+ return super and super:subclass(name) or _includeMixin(_createClass(name), DefaultMixin)
+end
+
+setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end })
+
+return middleclass
diff --git a/lua/server/server.lua b/lua/server/server.lua
new file mode 100644
index 00000000..67b33266
--- /dev/null
+++ b/lua/server/server.lua
@@ -0,0 +1,26 @@
+local Server = class('Server')
+
+freekill.server_callback = {}
+
+function Server:initialize()
+ self.server = freekill.ServerInstance
+ self.server.callback = function(_self, command, json_data)
+ local cb = freekill.server_callback[command]
+ if (type(cb) == "function") then
+ cb(json_data)
+ else
+ print("Server error: Unknown command " .. command);
+ end
+ end
+end
+
+freekill.server_callback["create_room"] = function(json_data)
+ -- json_data: [ int id, string name, int capacity ]
+ local data = json.decode(json_data)
+ local owner = freekill.ServerInstance:findPlayer(data[1])
+ local roomName = data[2]
+ local capacity = data[3]
+ freekill.ServerInstance:createRoom(owner, roomName, capacity)
+end
+
+ServerInstance = Server:new()
diff --git a/qml/Page/Init.qml b/qml/Page/Init.qml
new file mode 100644
index 00000000..c49f6525
--- /dev/null
+++ b/qml/Page/Init.qml
@@ -0,0 +1,39 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.0
+import QtQuick.Window 2.0
+
+Item {
+ id: root
+
+ Frame {
+ id: join_server
+ anchors.centerIn: parent
+ Column {
+ spacing: 8
+ TextField {
+ id: server_addr
+ text: "127.0.0.1"
+ }
+ TextField {
+ text: "player"
+ }
+ Button {
+ text: "Join Server"
+ onClicked: {
+ mainWindow.state = "busy";
+ mainWindow.busyString = "Connecting to host...";
+ Backend.joinServer(server_addr.text);
+ }
+ }
+ Button {
+ text: "Console start"
+ onClicked: {
+ mainWindow.state = "busy";
+ mainWindow.busyString = "Connecting to host...";
+ Backend.startServer(9527);
+ Backend.joinServer("127.0.0.1");
+ }
+ }
+ }
+ }
+}
diff --git a/qml/Page/Lobby.qml b/qml/Page/Lobby.qml
new file mode 100644
index 00000000..885b7e90
--- /dev/null
+++ b/qml/Page/Lobby.qml
@@ -0,0 +1,112 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.0
+import QtQuick.Window 2.0
+import QtQuick.Layouts 1.15
+
+Item {
+ id: root
+ width: 640; height: 480
+ Component {
+ id: roomDelegate
+
+ Row {
+ spacing: 24
+ Text {
+ width: 40
+ text: String(roomId)
+ }
+
+ Text {
+ width: 40
+ text: roomName
+ }
+
+ Text {
+ width: 20
+ text: gameMode
+ }
+
+ Text {
+ width: 10
+ color: (playerNum == capacity) ? "red" : "black"
+ text: String(playerNum) + "/" + String(capacity)
+ }
+
+ Text {
+ text: "Enter"
+ font.underline: true
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: { parent.color = "blue" }
+ onExited: { parent.color = "black" }
+ onClicked: {}
+ }
+ }
+ }
+ }
+
+ ListModel {
+ id: roomModel
+ }
+
+ RowLayout {
+ anchors.fill: parent
+ Rectangle {
+ width: root.width * 0.7
+ height: root.height
+ color: "#e2e2e1"
+ radius: 4
+ Text {
+ text: "Room List"
+ }
+ ListView {
+ height: parent.height * 0.9
+ width: parent.width * 0.95
+ anchors.centerIn: parent
+ id: roomList
+ delegate: roomDelegate
+ model: roomModel
+ }
+ Rectangle {
+ id: scrollbar
+ anchors.right: roomList.right
+ y: roomList.visibleArea.yPosition * roomList.height
+ width: 10
+ radius: 4
+ height: roomList.visibleArea.heightRatio * roomList.height
+ color: "#a89da8"
+ }
+ }
+
+ ColumnLayout {
+ Text {
+ text: "Avatar"
+ }
+ Button {
+ text: "Create Room"
+ onClicked: {}
+ }
+ Button {
+ text: "Generals Overview"
+ }
+ Button {
+ text: "Cards Overview"
+ }
+ Button {
+ text: "Scenarios Overview"
+ }
+ Button {
+ text: "About"
+ }
+ Button {
+ text: "Exit Lobby"
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ // toast.show("Welcome to FreeKill lobby!")
+ }
+}
+
diff --git a/qml/Page/Room.qml b/qml/Page/Room.qml
new file mode 100644
index 00000000..22c5da15
--- /dev/null
+++ b/qml/Page/Room.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.0
+import QtQuick.Window 2.0
+
+Item {
+ id: root
+}
+
diff --git a/qml/main.qml b/qml/main.qml
new file mode 100644
index 00000000..76ed0efa
--- /dev/null
+++ b/qml/main.qml
@@ -0,0 +1,108 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.0
+import QtQuick.Window 2.0
+
+Window {
+ id: mainWindow
+ visible: true
+ width: 720
+ height: 480
+ property var callbacks: ({
+ "error_msg": function(json_data) {
+ toast.show(json_data);
+ if (mainWindow.state === "busy")
+ mainWindow.state = "init";
+ },
+ "enter_lobby": function(json_data) {
+ mainWindow.state = "lobby";
+ }
+ })
+
+ Loader {
+ id: mainLoader
+ source: "Page/Init.qml"
+ anchors.fill: parent
+ }
+
+ property string state: "init"
+
+ onStateChanged: {
+ switch (state) {
+ case "init":
+ mainLoader.source = "Page/Init.qml";
+ break;
+ case "lobby":
+ mainLoader.source = "Page/Lobby.qml";
+ break;
+ case "room":
+ mainLoader.source = "Page/Room.qml";
+ break;
+ case "busy":
+ mainLoader.source = "";
+ break;
+ default: break;
+ }
+ }
+
+ property string busyString: "Busy"
+
+ BusyIndicator {
+ running: true
+ anchors.centerIn: parent
+ visible: mainWindow.state === "busy"
+ }
+
+ Rectangle {
+ id: toast
+ opacity: 0
+ z: 998
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: parent.height * 0.8
+ radius: 16
+ color: "#F2808A87"
+ height: toast_text.height + 20
+ width: toast_text.width + 40
+ Text {
+ id: toast_text
+ text: "FreeKill"
+ anchors.centerIn: parent
+ color: "white"
+ }
+ Behavior on opacity {
+ NumberAnimation {
+ duration: 240
+ easing.type: Easing.InOutQuad
+ }
+ }
+ SequentialAnimation {
+ id: keepAnim
+ running: toast.opacity == 1
+ PauseAnimation {
+ duration: 2800
+ }
+
+ ScriptAction {
+ script: {
+ toast.opacity = 0
+ }
+ }
+ }
+
+ function show(text) {
+ opacity = 1
+ toast_text.text = text
+ }
+ }
+
+ Connections {
+ target: Backend
+ function onNotifyUI(command, json_data) {
+ let cb = callbacks[command]
+ if (typeof(cb) === "function") {
+ cb(json_data);
+ } else {
+ callbacks["error_msg"]("Unknown UI command " + command + "!");
+ }
+ }
+ }
+}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 00000000..6a430bbc
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,49 @@
+set(freekill_SRCS
+ "main.cpp"
+ "core/player.cpp"
+ "core/global.cpp"
+ "network/server_socket.cpp"
+ "network/client_socket.cpp"
+ "network/router.cpp"
+ "server/server.cpp"
+ "server/serverplayer.cpp"
+ "server/room.cpp"
+ "server/gamelogic.cpp"
+ "client/client.cpp"
+ "client/clientplayer.cpp"
+ "ui/qmlbackend.cpp"
+ "swig/freekill-wrap.cxx"
+)
+
+set(freekill_HEADERS
+ "core/global.h"
+ "core/player.h"
+ "network/server_socket.h"
+ "network/client_socket.h"
+ "network/router.h"
+ "server/server.h"
+ "server/serverplayer.h"
+ "server/room.h"
+ "server/gamelogic.h"
+ "client/client.h"
+ "client/clientplayer.h"
+ "ui/qmlbackend.h"
+)
+
+if (WIN32)
+ set(LUA_LIB ${PROJECT_SOURCE_DIR}/lib/win/lua54.dll)
+else ()
+ set(LUA_LIB lua5.4)
+endif ()
+
+source_group("Include" FILES ${freekill_HEADERS})
+add_executable(FreeKill ${freekill_SRCS})
+target_link_libraries(FreeKill ${LUA_LIB} Qt5::Qml Qt5::Gui Qt5::Network Qt5::Multimedia)
+add_custom_command(
+ OUTPUT ${PROJECT_SOURCE_DIR}/src/swig/freekill-wrap.cxx
+ DEPENDS ${PROJECT_SOURCE_DIR}/src/swig/freekill.i
+ COMMENT "Generating freekill-wrap.cxx"
+ COMMAND swig -c++ -lua -Wall -o
+ ${PROJECT_SOURCE_DIR}/src/swig/freekill-wrap.cxx
+ ${PROJECT_SOURCE_DIR}/src/swig/freekill.i
+)
diff --git a/src/client/client.cpp b/src/client/client.cpp
new file mode 100644
index 00000000..5d16316e
--- /dev/null
+++ b/src/client/client.cpp
@@ -0,0 +1,50 @@
+#include "client.h"
+#include "client_socket.h"
+#include "clientplayer.h"
+
+Client *ClientInstance;
+ClientPlayer *Self;
+
+Client::Client(QObject* parent)
+ : QObject(parent), callback(0)
+{
+ ClientInstance = this;
+ Self = nullptr;
+
+ ClientSocket *socket = new ClientSocket;
+ connect(socket, &ClientSocket::error_message, this, &Client::error_message);
+ router = new Router(this, socket, Router::TYPE_CLIENT);
+
+ L = CreateLuaState();
+ DoLuaScript(L, "lua/freekill.lua");
+ DoLuaScript(L, "lua/client/client.lua");
+}
+
+Client::~Client()
+{
+ ClientInstance = nullptr;
+ router->getSocket()->deleteLater();
+}
+
+void Client::connectToHost(const QHostAddress& server, ushort port)
+{
+ router->getSocket()->connectToHost(server, port);
+}
+
+void Client::requestServer(const QString& command, const QString& json_data, int timeout)
+{
+ int type = Router::TYPE_REQUEST | Router::SRC_CLIENT | Router::DEST_SERVER;
+ router->request(type, command, json_data, timeout);
+}
+
+void Client::replyToServer(const QString& command, const QString& json_data)
+{
+ int type = Router::TYPE_REQUEST | Router::SRC_CLIENT | Router::DEST_SERVER;
+ router->reply(type, command, json_data);
+}
+
+void Client::notifyServer(const QString& command, const QString& json_data)
+{
+ int type = Router::TYPE_REQUEST | Router::SRC_CLIENT | Router::DEST_SERVER;
+ router->notify(type, command, json_data);
+}
diff --git a/src/client/client.h b/src/client/client.h
new file mode 100644
index 00000000..8bd31bac
--- /dev/null
+++ b/src/client/client.h
@@ -0,0 +1,42 @@
+#ifndef _CLIENT_H
+#define _CLIENT_H
+
+#include
+#include
+#include "router.h"
+#include "clientplayer.h"
+#include "global.h"
+
+class Client : public QObject {
+ Q_OBJECT
+public:
+ Client(QObject *parent = nullptr);
+ ~Client();
+
+ void connectToHost(const QHostAddress &server, ushort port);
+
+ // TODO: database of the server
+ // void signup
+ // void login
+
+ void requestServer(const QString &command,
+ const QString &json_data, int timeout = -1);
+ void replyToServer(const QString &command, const QString &json_data);
+ void notifyServer(const QString &command, const QString &json_data);
+
+ void callLua(const QString &command, const QString &json_data);
+ LuaFunction callback;
+
+signals:
+ void error_message(const QString &msg);
+
+private:
+ Router *router;
+ QMap players;
+
+ lua_State *L;
+};
+
+extern Client *ClientInstance;
+
+#endif // _CLIENT_H
diff --git a/src/client/clientplayer.cpp b/src/client/clientplayer.cpp
new file mode 100644
index 00000000..d4461390
--- /dev/null
+++ b/src/client/clientplayer.cpp
@@ -0,0 +1,11 @@
+#include "clientplayer.h"
+
+ClientPlayer::ClientPlayer(uint id, QObject* parent)
+ : Player(parent)
+{
+ setId(id);
+}
+
+ClientPlayer::~ClientPlayer()
+{
+}
diff --git a/src/client/clientplayer.h b/src/client/clientplayer.h
new file mode 100644
index 00000000..733a85c8
--- /dev/null
+++ b/src/client/clientplayer.h
@@ -0,0 +1,17 @@
+#ifndef _CLIENTPLAYER_H
+#define _CLIENTPLAYER_H
+
+#include "player.h"
+
+class ClientPlayer : public Player {
+ Q_OBJECT
+public:
+ ClientPlayer(uint id, QObject *parent = nullptr);
+ ~ClientPlayer();
+
+private:
+};
+
+extern ClientPlayer *Self;
+
+#endif // _CLIENTPLAYER_H
diff --git a/src/core/global.cpp b/src/core/global.cpp
new file mode 100644
index 00000000..9cb75ec3
--- /dev/null
+++ b/src/core/global.cpp
@@ -0,0 +1,27 @@
+#include "global.h"
+#include
+
+extern "C" {
+ int luaopen_freekill(lua_State *);
+}
+
+lua_State *CreateLuaState()
+{
+ lua_State *L = luaL_newstate();
+ luaL_openlibs(L);
+ luaopen_freekill(L);
+
+ return L;
+}
+
+bool DoLuaScript(lua_State *L, const char *script)
+{
+ int error = luaL_dofile(L, script);
+ if (error) {
+ QString error_msg = lua_tostring(L, -1);
+ qDebug() << error_msg;
+ return false;
+ }
+ return true;
+}
+
diff --git a/src/core/global.h b/src/core/global.h
new file mode 100644
index 00000000..036a9b1a
--- /dev/null
+++ b/src/core/global.h
@@ -0,0 +1,12 @@
+#ifndef _GLOBAL_H
+#define _GLOBAL_H
+
+#include
+
+// utilities
+typedef int LuaFunction;
+
+lua_State *CreateLuaState();
+bool DoLuaScript(lua_State *L, const char *script);
+
+#endif // _GLOBAL_H
diff --git a/src/core/player.cpp b/src/core/player.cpp
new file mode 100644
index 00000000..89083e33
--- /dev/null
+++ b/src/core/player.cpp
@@ -0,0 +1,94 @@
+#include "player.h"
+
+Player::Player(QObject* parent)
+ : QObject(parent)
+ , id(0)
+ , state(Player::Invalid)
+ , ready(false)
+{
+}
+
+Player::~Player()
+{
+}
+
+uint Player::getId() const
+{
+ return id;
+}
+
+void Player::setId(uint id)
+{
+ this->id = id;
+}
+
+QString Player::getScreenName() const
+{
+ return screenName;
+}
+
+void Player::setScreenName(const QString& name)
+{
+ this->screenName = name;
+ emit screenNameChanged();
+}
+
+QString Player::getAvatar() const
+{
+ return avatar;
+}
+
+void Player::setAvatar(const QString& avatar)
+{
+ this->avatar = avatar;
+ emit avatarChanged();
+}
+
+Player::State Player::getState() const
+{
+ return state;
+}
+
+QString Player::getStateString() const
+{
+ switch (state) {
+ case Online:
+ return QStringLiteral("online");
+ case Trust:
+ return QStringLiteral("trust");
+ case Offline:
+ return QStringLiteral("offline");
+ default:
+ return QStringLiteral("invalid");
+ }
+}
+
+void Player::setState(Player::State state)
+{
+ this->state = state;
+ emit stateChanged();
+}
+
+void Player::setStateString(const QString &state)
+{
+ if (state == QStringLiteral("online"))
+ setState(Online);
+ else if (state == QStringLiteral("trust"))
+ setState(Trust);
+ else if (state == QStringLiteral("offline"))
+ setState(Offline);
+ else
+ setState(Invalid);
+}
+
+bool Player::isReady() const
+{
+ return ready;
+}
+
+void Player::setReady(bool ready)
+{
+ this->ready = ready;
+ emit readyChanged();
+}
+
diff --git a/src/core/player.h b/src/core/player.h
new file mode 100644
index 00000000..8ca97f5e
--- /dev/null
+++ b/src/core/player.h
@@ -0,0 +1,53 @@
+#ifndef _PLAYER_H
+#define _PLAYER_H
+
+#include
+
+// Common part of ServerPlayer and ClientPlayer
+// dont initialize it directly
+class Player : public QObject {
+ Q_OBJECT
+
+public:
+ enum State{
+ Invalid,
+ Online,
+ Trust,
+ Offline
+ };
+
+ explicit Player(QObject *parent = nullptr);
+ ~Player();
+
+ uint getId() const;
+ void setId(uint id);
+
+ QString getScreenName() const;
+ void setScreenName(const QString &name);
+
+ QString getAvatar() const;
+ void setAvatar(const QString &avatar);
+
+ State getState() const;
+ QString getStateString() const;
+ void setState(State state);
+ void setStateString(const QString &state);
+
+ bool isReady() const;
+ void setReady(bool ready);
+
+signals:
+ void screenNameChanged();
+ void avatarChanged();
+ void stateChanged();
+ void readyChanged();
+
+private:
+ uint id;
+ QString screenName;
+ QString avatar;
+ State state;
+ bool ready;
+};
+
+#endif // _PLAYER_H
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 00000000..c7e6cb64
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,42 @@
+#include
+#include
+#include
+#include
+#include "qmlbackend.h"
+#include "server.h"
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+ QGuiApplication::setApplicationName("FreeKill");
+ QGuiApplication::setApplicationVersion("Alpha 0.0.1");
+
+ QCommandLineParser parser;
+ parser.setApplicationDescription("FreeKill server");
+ parser.addHelpOption();
+ parser.addVersionOption();
+ parser.addOption({{"s", "server"}, "start server at ", "port"});
+ parser.process(app);
+
+ bool startServer = parser.isSet("server");
+ ushort serverPort = 9527;
+
+ if (startServer) {
+ bool ok = false;
+ if (parser.value("server").toInt(&ok) && ok)
+ serverPort = parser.value("server").toInt();
+ Server *server = new Server;
+ if (!server->listen(QHostAddress::Any, serverPort)) {
+ fprintf(stderr, "cannot listen on port %d!\n", serverPort);
+ exit(1);
+ }
+ return app.exec();
+ }
+
+ QQmlApplicationEngine engine;
+ QmlBackend backend;
+ engine.rootContext()->setContextProperty("Backend", &backend);
+ engine.load("qml/main.qml");
+
+ return app.exec();
+}
diff --git a/src/network/client_socket.cpp b/src/network/client_socket.cpp
new file mode 100644
index 00000000..58f00b65
--- /dev/null
+++ b/src/network/client_socket.cpp
@@ -0,0 +1,95 @@
+#include "client_socket.h"
+#include
+#include
+
+ClientSocket::ClientSocket() : socket(new QTcpSocket(this))
+{
+ init();
+}
+
+ClientSocket::ClientSocket(QTcpSocket* socket)
+{
+ socket->setParent(this);
+ this->socket = socket;
+ init();
+}
+
+void ClientSocket::init()
+{
+ connect(socket, &QTcpSocket::connected,
+ this, &ClientSocket::connected);
+ connect(socket, &QTcpSocket::disconnected,
+ this, &ClientSocket::disconnected);
+ connect(socket, &QTcpSocket::readyRead,
+ this, &ClientSocket::getMessage);
+ connect(socket, &QTcpSocket::errorOccurred,
+ this, &ClientSocket::raiseError);
+}
+
+void ClientSocket::connectToHost(const QHostAddress &address, ushort port)
+{
+ socket->connectToHost(address, port);
+}
+
+void ClientSocket::getMessage()
+{
+ while (socket->canReadLine()) {
+ char msg[16000]; // buffer
+ socket->readLine(msg, sizeof(msg));
+ emit message_got(msg);
+ }
+}
+
+void ClientSocket::disconnectFromHost()
+{
+ socket->disconnectFromHost();
+}
+
+void ClientSocket::send(const QByteArray &msg)
+{
+ socket->write(msg);
+ if (!msg.endsWith("\n"))
+ socket->write("\n");
+ socket->flush();
+}
+
+bool ClientSocket::isConnected() const
+{
+ return socket->state() == QTcpSocket::ConnectedState;
+}
+
+QString ClientSocket::peerName() const
+{
+ QString peer_name = socket->peerName();
+ if (peer_name.isEmpty())
+ peer_name = QString("%1:%2").arg(socket->peerAddress().toString()).arg(socket->peerPort());
+
+ return peer_name;
+}
+
+QString ClientSocket::peerAddress() const
+{
+ return socket->peerAddress().toString();
+}
+
+void ClientSocket::raiseError(QAbstractSocket::SocketError socket_error)
+{
+ // translate error message
+ QString reason;
+ switch (socket_error) {
+ case QAbstractSocket::ConnectionRefusedError:
+ reason = tr("Connection was refused or timeout"); break;
+ case QAbstractSocket::RemoteHostClosedError:
+ reason = tr("Remote host close this connection"); break;
+ case QAbstractSocket::HostNotFoundError:
+ reason = tr("Host not found"); break;
+ case QAbstractSocket::SocketAccessError:
+ reason = tr("Socket access error"); break;
+ case QAbstractSocket::NetworkError:
+ return; // this error is ignored ...
+ default: reason = tr("Unknow error"); break;
+ }
+
+ emit error_message(tr("Connection failed, error code = %1\n reason:\n %2")
+ .arg(socket_error).arg(reason));
+}
diff --git a/src/network/client_socket.h b/src/network/client_socket.h
new file mode 100644
index 00000000..23853077
--- /dev/null
+++ b/src/network/client_socket.h
@@ -0,0 +1,40 @@
+#ifndef _CLIENT_SOCKET_H
+#define _CLIENT_SOCKET_H
+
+#include
+#include
+#include
+
+class QTcpSocket;
+
+class ClientSocket : public QObject {
+ Q_OBJECT
+
+public:
+ ClientSocket();
+ // For server use
+ ClientSocket(QTcpSocket *socket);
+
+ void connectToHost(const QHostAddress &address = QHostAddress::LocalHost, ushort port = 9527u);
+ void disconnectFromHost();
+ void send(const QByteArray& msg);
+ bool isConnected() const;
+ QString peerName() const;
+ QString peerAddress() const;
+
+signals:
+ void message_got(const QByteArray& msg);
+ void error_message(const QString &msg);
+ void disconnected();
+ void connected();
+
+private slots:
+ void getMessage();
+ void raiseError(QAbstractSocket::SocketError error);
+
+private:
+ QTcpSocket *socket;
+ void init();
+};
+
+#endif // _CLIENT_SOCKET_H
diff --git a/src/network/router.cpp b/src/network/router.cpp
new file mode 100644
index 00000000..51a597bc
--- /dev/null
+++ b/src/network/router.cpp
@@ -0,0 +1,196 @@
+#include
+#include
+#include "router.h"
+#include "client.h"
+#include "server.h"
+
+Router::Router(QObject *parent, ClientSocket *socket, RouterType type)
+ : QObject(parent)
+{
+ this->type = type;
+ this->socket = nullptr;
+ setSocket(socket);
+ expectedReplyId = -1;
+ replyTimeout = 0;
+ extraReplyReadySemaphore = nullptr;
+}
+
+Router::~Router()
+{
+ abortRequest();
+}
+
+ClientSocket* Router::getSocket() const
+{
+ return socket;
+}
+
+void Router::setSocket(ClientSocket *socket)
+{
+ if (this->socket != nullptr) {
+ this->socket->disconnect(this);
+ disconnect(this->socket);
+ this->socket->deleteLater();
+ }
+
+ this->socket = nullptr;
+ if (socket != nullptr) {
+ connect(this, &Router::messageReady, socket, &ClientSocket::send);
+ connect(socket, &ClientSocket::message_got, this, &Router::handlePacket);
+ connect(socket, &ClientSocket::disconnected, this, &Router::abortRequest);
+ socket->setParent(this);
+ this->socket = socket;
+ }
+}
+
+void Router::setReplyReadySemaphore(QSemaphore *semaphore)
+{
+ extraReplyReadySemaphore = semaphore;
+}
+
+void Router::request(int type, const QString& command,
+ const QString& json_data, int timeout)
+{
+ // In case a request is called without a following waitForReply call
+ if (replyReadySemaphore.available() > 0)
+ replyReadySemaphore.acquire(replyReadySemaphore.available());
+
+ static int requestId = 0;
+ requestId++;
+
+ replyMutex.lock();
+ expectedReplyId = requestId;
+ replyTimeout = 0;
+ requestStartTime = QDateTime::currentDateTime();
+ m_reply = QString();
+ replyMutex.unlock();
+
+ QJsonArray body;
+ body << requestId;
+ body << type;
+ body << command;
+ body << json_data;
+ body << timeout;
+
+ emit messageReady(QJsonDocument(body).toJson(QJsonDocument::Compact));
+}
+
+void Router::reply(int type, const QString& command, const QString& json_data)
+{
+ QJsonArray body;
+ body << this->requestId;
+ body << type;
+ body << command;
+ body << json_data;
+
+ emit messageReady(QJsonDocument(body).toJson(QJsonDocument::Compact));
+}
+
+void Router::notify(int type, const QString& command, const QString& json_data)
+{
+ QJsonArray body;
+ body << -2; // requestId = -2 mean this is for notification
+ body << type;
+ body << command;
+ body << json_data;
+
+ emit messageReady(QJsonDocument(body).toJson(QJsonDocument::Compact));
+}
+
+int Router::getTimeout() const
+{
+ return requestTimeout;
+}
+
+// cancel last request from the sender
+void Router::cancelRequest()
+{
+ replyMutex.lock();
+ expectedReplyId = -1;
+ replyTimeout = 0;
+ extraReplyReadySemaphore = nullptr;
+ replyMutex.unlock();
+
+ if (replyReadySemaphore.available() > 0)
+ replyReadySemaphore.acquire(replyReadySemaphore.available());
+}
+
+QString Router::waitForReply()
+{
+ replyReadySemaphore.acquire();
+ return m_reply;
+}
+
+QString Router::waitForReply(int timeout)
+{
+ replyReadySemaphore.tryAcquire(1, timeout);
+ return m_reply;
+}
+
+void Router::abortRequest()
+{
+ replyMutex.lock();
+ if (expectedReplyId != -1) {
+ replyReadySemaphore.release();
+ if (extraReplyReadySemaphore)
+ extraReplyReadySemaphore->release();
+ expectedReplyId = -1;
+ extraReplyReadySemaphore = nullptr;
+ }
+ replyMutex.unlock();
+}
+
+void Router::handlePacket(const QByteArray& rawPacket)
+{
+ QJsonDocument packet = QJsonDocument::fromJson(rawPacket);
+ if (packet.isNull() || !packet.isArray())
+ return;
+
+ int requestId = packet[0].toInt();
+ int type = packet[1].toInt();
+ QString command = packet[2].toString();
+ QString json_data = packet[3].toString();
+
+ if (type & TYPE_NOTIFICATION) {
+ if (type & DEST_CLIENT) {
+ qobject_cast(parent())->callLua(command, json_data);
+ } else {
+ qDebug() << rawPacket << Qt::endl;
+ }
+ }
+ else if (type & TYPE_REQUEST) {
+ this->requestId = requestId;
+ this->requestTimeout = packet[4].toInt();
+
+ if (type & DEST_CLIENT) {
+ qobject_cast(parent())->callLua(command, json_data);
+ } else {
+ qDebug() << rawPacket << Qt::endl;
+ }
+ }
+ else if (type & TYPE_REPLY) {
+ QMutexLocker locker(&replyMutex);
+
+ if (requestId != this->expectedReplyId)
+ return;
+
+ this->expectedReplyId = -1;
+
+ if (replyTimeout >= 0 && replyTimeout <
+ requestStartTime.secsTo(QDateTime::currentDateTime()))
+ return;
+
+ m_reply = json_data;
+ // TODO: callback?
+ qDebug() << rawPacket << Qt::endl;
+
+ replyReadySemaphore.release();
+ if (extraReplyReadySemaphore) {
+ extraReplyReadySemaphore->release();
+ extraReplyReadySemaphore = nullptr;
+ }
+ locker.unlock();
+ emit replyReady();
+ }
+}
+
diff --git a/src/network/router.h b/src/network/router.h
new file mode 100644
index 00000000..9e7a8ba0
--- /dev/null
+++ b/src/network/router.h
@@ -0,0 +1,83 @@
+#ifndef _ROUTER_H
+#define _ROUTER_H
+
+#include
+#include
+#include
+#include
+#include
+#include "client_socket.h"
+
+class Router : public QObject {
+ Q_OBJECT
+
+public:
+ enum PacketType {
+ TYPE_REQUEST = 0x100,
+ TYPE_REPLY = 0x200,
+ TYPE_NOTIFICATION = 0x400,
+ SRC_CLIENT = 0x010,
+ SRC_SERVER = 0x020,
+ SRC_LOBBY = 0x040,
+ DEST_CLIENT = 0x001,
+ DEST_SERVER = 0x002,
+ DEST_LOBBY = 0x004
+ };
+
+ enum RouterType {
+ TYPE_SERVER,
+ TYPE_CLIENT
+ };
+ Router(QObject *parent, ClientSocket *socket, RouterType type);
+ ~Router();
+
+ ClientSocket *getSocket() const;
+ void setSocket(ClientSocket *socket);
+
+ void setReplyReadySemaphore(QSemaphore *semaphore);
+
+ void request(int type, const QString &command,
+ const QString &json_data, int timeout);
+ void reply(int type, const QString &command, const QString &json_data);
+ void notify(int type, const QString &command, const QString &json_data);
+
+ int getTimeout() const;
+
+ void cancelRequest();
+
+ QString waitForReply();
+ QString waitForReply(int timeout);
+
+signals:
+ void messageReady(const QByteArray &message);
+ void unknownPacket(const QByteArray &packet);
+ void replyReady();
+
+protected:
+ void abortRequest();
+ void handlePacket(const QByteArray &rawPacket);
+
+private:
+ ClientSocket *socket;
+ RouterType type;
+
+ // For sender
+ int requestId;
+ int requestTimeout;
+
+ // For receiver
+ QDateTime requestStartTime;
+ QMutex replyMutex;
+ int expectedReplyId;
+ int replyTimeout;
+ QString m_reply; // should be json string
+ QSemaphore replyReadySemaphore;
+ QSemaphore *extraReplyReadySemaphore;
+
+ // Two Lua global table for callbacks and interactions
+ // stored in the lua_State of the sender
+ // LuaTable interactions;
+ // LuaTable callbacks;
+};
+
+#endif // _ROUTER_H
diff --git a/src/network/server_socket.cpp b/src/network/server_socket.cpp
new file mode 100644
index 00000000..cbf2322b
--- /dev/null
+++ b/src/network/server_socket.cpp
@@ -0,0 +1,23 @@
+#include "server_socket.h"
+#include "client_socket.h"
+#include
+
+ServerSocket::ServerSocket()
+{
+ server = new QTcpServer(this);
+ connect(server, &QTcpServer::newConnection,
+ this, &ServerSocket::processNewConnection);
+}
+
+bool ServerSocket::listen(const QHostAddress &address, ushort port)
+{
+ return server->listen(address, port);
+}
+
+void ServerSocket::processNewConnection()
+{
+ QTcpSocket *socket = server->nextPendingConnection();
+ ClientSocket *connection = new ClientSocket(socket);
+ emit new_connection(connection);
+}
+
diff --git a/src/network/server_socket.h b/src/network/server_socket.h
new file mode 100644
index 00000000..ec9966a9
--- /dev/null
+++ b/src/network/server_socket.h
@@ -0,0 +1,28 @@
+#ifndef _SERVER_SOCKET_H
+#define _SERVER_SOCKET_H
+
+#include
+#include
+
+class QTcpServer;
+class ClientSocket;
+
+class ServerSocket : public QObject {
+ Q_OBJECT
+
+public:
+ ServerSocket();
+
+ bool listen(const QHostAddress &address = QHostAddress::Any, ushort port = 9527u);
+
+signals:
+ void new_connection(ClientSocket *socket);
+
+private slots:
+ void processNewConnection();
+
+private:
+ QTcpServer *server;
+};
+
+#endif // _SERVER_SOCKET_H
diff --git a/src/resources.qrc b/src/resources.qrc
new file mode 100644
index 00000000..7c75584c
--- /dev/null
+++ b/src/resources.qrc
@@ -0,0 +1,5 @@
+
+
+ qml/main.qml
+
+
diff --git a/src/server/gamelogic.cpp b/src/server/gamelogic.cpp
new file mode 100644
index 00000000..c20467ea
--- /dev/null
+++ b/src/server/gamelogic.cpp
@@ -0,0 +1,11 @@
+#include "gamelogic.h"
+
+GameLogic::GameLogic(Room *room)
+{
+
+}
+
+void GameLogic::run()
+{
+
+}
diff --git a/src/server/gamelogic.h b/src/server/gamelogic.h
new file mode 100644
index 00000000..fbe323eb
--- /dev/null
+++ b/src/server/gamelogic.h
@@ -0,0 +1,17 @@
+#ifndef _GAMELOGIC_H
+#define _GAMELOGIC_H
+
+#include
+class Room;
+
+// Just like the class 'RoomThread' in QSanguosha
+class GameLogic : public QThread {
+ Q_OBJECT
+public:
+ explicit GameLogic(Room *room);
+
+protected:
+ virtual void run();
+};
+
+#endif // _GAMELOGIC_H
diff --git a/src/server/room.cpp b/src/server/room.cpp
new file mode 100644
index 00000000..18189d5e
--- /dev/null
+++ b/src/server/room.cpp
@@ -0,0 +1,124 @@
+#include "room.h"
+#include "serverplayer.h"
+#include "server.h"
+
+Room::Room(Server* server)
+{
+ static uint roomId = 0;
+ id = roomId;
+ roomId++;
+ this->server = server;
+}
+
+Room::~Room()
+{
+ // TODO
+}
+
+Server *Room::getServer() const
+{
+ return server;
+}
+
+uint Room::getId() const
+{
+ return id;
+}
+
+bool Room::isLobby() const
+{
+ return id == 0;
+}
+
+QString Room::getName() const
+{
+ return name;
+}
+
+void Room::setName(const QString &name)
+{
+ this->name = name;
+}
+
+uint Room::getCapacity() const
+{
+ return capacity;
+}
+
+void Room::setCapacity(uint capacity)
+{
+ this->capacity = capacity;
+}
+
+bool Room::isFull() const
+{
+ return players.count() == capacity;
+}
+
+bool Room::isAbandoned() const
+{
+ return players.isEmpty();
+}
+
+ServerPlayer *Room::getOwner() const
+{
+ return owner;
+}
+
+void Room::setOwner(ServerPlayer *owner)
+{
+ this->owner = owner;
+}
+
+void Room::addPlayer(ServerPlayer *player)
+{
+ players.insert(player->getId(), player);
+ emit playerAdded(player);
+}
+
+void Room::removePlayer(ServerPlayer *player)
+{
+ players.remove(player->getId());
+ emit playerRemoved(player);
+}
+
+QHash Room::getPlayers() const
+{
+ return players;
+}
+
+ServerPlayer *Room::findPlayer(uint id) const
+{
+ return players.value(id);
+}
+
+void Room::setGameLogic(GameLogic *logic)
+{
+ this->logic = logic;
+}
+
+GameLogic *Room::getGameLogic() const
+{
+ return logic;
+}
+
+void Room::startGame()
+{
+ // TODO
+}
+
+void Room::doRequest(const QList targets, int timeout)
+{
+ // TODO
+}
+
+void Room::doNotify(const QList targets, int timeout)
+{
+ // TODO
+}
+
+void Room::run()
+{
+ // TODO
+}
+
diff --git a/src/server/room.h b/src/server/room.h
new file mode 100644
index 00000000..959c2241
--- /dev/null
+++ b/src/server/room.h
@@ -0,0 +1,69 @@
+#ifndef _ROOM_H
+#define _ROOM_H
+
+#include
+#include
+class Server;
+class ServerPlayer;
+class GameLogic;
+
+class Room : public QThread {
+ Q_OBJECT
+public:
+ explicit Room(Server *m_server);
+ ~Room();
+
+ // Property reader & setter
+ // ==================================={
+ Server *getServer() const;
+ uint getId() const;
+ bool isLobby() const;
+ QString getName() const;
+ void setName(const QString &name);
+ uint getCapacity() const;
+ void setCapacity(uint capacity);
+ bool isFull() const;
+ bool isAbandoned() const;
+
+ ServerPlayer *getOwner() const;
+ void setOwner(ServerPlayer *owner);
+
+ void addPlayer(ServerPlayer *player);
+ void removePlayer(ServerPlayer *player);
+ QHash getPlayers() const;
+ ServerPlayer *findPlayer(uint id) const;
+
+ void setGameLogic(GameLogic *logic);
+ GameLogic *getGameLogic() const;
+ // ====================================}
+
+ void startGame();
+ void doRequest(const QList targets, int timeout);
+ void doNotify(const QList targets, int timeout);
+
+signals:
+ void abandoned();
+
+ void aboutToStart();
+ void started();
+ void finished();
+
+ void playerAdded(ServerPlayer *player);
+ void playerRemoved(ServerPlayer *player);
+
+protected:
+ virtual void run();
+
+private:
+ Server *server;
+ uint id; // Lobby's id is 0
+ QString name; // “阴间大乱斗”
+ uint capacity; // by default is 5, max is 8
+ bool m_abandoned; // If room is empty, delete it
+
+ ServerPlayer *owner; // who created this room?
+ QHash players;
+ GameLogic *logic;
+};
+
+#endif // _ROOM_H
diff --git a/src/server/server.cpp b/src/server/server.cpp
new file mode 100644
index 00000000..c08906fb
--- /dev/null
+++ b/src/server/server.cpp
@@ -0,0 +1,100 @@
+#include "server.h"
+#include "server_socket.h"
+#include "client_socket.h"
+#include "room.h"
+#include "serverplayer.h"
+#include "global.h"
+
+Server *ServerInstance;
+
+Server::Server(QObject* parent)
+ : QObject(parent)
+{
+ ServerInstance = this;
+ server = new ServerSocket();
+ server->setParent(this);
+ connect(server, &ServerSocket::new_connection,
+ this, &Server::processNewConnection);
+
+ // create lobby
+ createRoom(NULL, "Lobby", UINT32_MAX);
+ connect(lobby(), &Room::playerAdded, this, &Server::updateRoomList);
+
+ L = CreateLuaState();
+ DoLuaScript(L, "lua/freekill.lua");
+}
+
+Server::~Server()
+{
+ ServerInstance = nullptr;
+}
+
+bool Server::listen(const QHostAddress& address, ushort port)
+{
+ return server->listen(address, port);
+}
+
+void Server::createRoom(ServerPlayer* owner, const QString &name, uint capacity)
+{
+ Room *room = new Room(this);
+ connect(room, &Room::abandoned, this, &Server::onRoomAbandoned);
+ room->setName(name);
+ room->setCapacity(capacity);
+ room->setOwner(owner);
+ // TODO
+ // room->addPlayer(owner);
+ rooms.insert(room->getId(), room);
+#ifdef QT_DEBUG
+ qDebug() << "Room #" << room->getId() << " created.";
+#endif
+ emit roomCreated(room);
+}
+
+Room *Server::findRoom(uint id) const
+{
+ return rooms.value(id);
+}
+
+Room *Server::lobby() const
+{
+ return findRoom(0);
+}
+
+ServerPlayer *Server::findPlayer(uint id) const
+{
+ return players.value(id);
+}
+
+void Server::updateRoomList(ServerPlayer* user)
+{
+ // TODO
+}
+
+void Server::processNewConnection(ClientSocket* client)
+{
+ // version check, file check, ban IP, reconnect, etc
+ ServerPlayer *player = new ServerPlayer(lobby());
+ player->setSocket(client);
+#ifdef QT_DEBUG
+ qDebug() << "ServerPlayer #" << player->getUid() << "connected.";
+ qDebug() << "His address is " << client->peerAddress();
+#endif
+
+ player->doNotify("enter_lobby", "{}");
+
+}
+
+void Server::onRoomAbandoned()
+{
+ // TODO
+}
+
+void Server::onUserDisconnected()
+{
+ // TODO
+}
+
+void Server::onUserStateChanged()
+{
+ // TODO
+}
diff --git a/src/server/server.h b/src/server/server.h
new file mode 100644
index 00000000..f6bf4f4d
--- /dev/null
+++ b/src/server/server.h
@@ -0,0 +1,58 @@
+#ifndef _SERVER_H
+#define _SERVER_H
+
+#include
+#include
+#include
+#include
+
+class ServerSocket;
+class ClientSocket;
+class Room;
+class ServerPlayer;
+
+typedef int LuaFunction;
+
+class Server : public QObject {
+ Q_OBJECT
+
+public:
+ explicit Server(QObject *parent = nullptr);
+ ~Server();
+
+ bool listen(const QHostAddress &address = QHostAddress::Any, ushort port = 9527u);
+
+ void createRoom(ServerPlayer *owner, const QString &name, uint capacity);
+ Room *findRoom(uint id) const;
+ Room *lobby() const;
+
+ ServerPlayer *findPlayer(uint id) const;
+
+ void updateRoomList(ServerPlayer *user);
+
+ void callLua(const QString &command, const QString &json_data);
+ LuaFunction callback;
+
+signals:
+ void roomCreated(Room *room);
+ void playerAdded(ServerPlayer *player);
+ void playerRemoved(ServerPlayer *player);
+
+public slots:
+ void processNewConnection(ClientSocket *client);
+
+ void onRoomAbandoned();
+ void onUserDisconnected();
+ void onUserStateChanged();
+
+private:
+ ServerSocket *server;
+ QHash rooms;
+ QHash players;
+
+ lua_State *L;
+};
+
+extern Server *ServerInstance;
+
+#endif // _SERVER_H
diff --git a/src/server/serverplayer.cpp b/src/server/serverplayer.cpp
new file mode 100644
index 00000000..48ab5550
--- /dev/null
+++ b/src/server/serverplayer.cpp
@@ -0,0 +1,76 @@
+#include "serverplayer.h"
+#include "room.h"
+#include "server.h"
+
+ServerPlayer::ServerPlayer(Room *room)
+ : uid(0)
+{
+ static int m_playerid = 0;
+ m_playerid++;
+
+ uid = m_playerid;
+
+ socket = nullptr;
+ router = new Router(this, socket, Router::TYPE_SERVER);
+
+ this->room = room;
+}
+
+ServerPlayer::~ServerPlayer()
+{
+ router->deleteLater();
+}
+
+uint ServerPlayer::getUid() const
+{
+ return uid;
+}
+
+void ServerPlayer::setSocket(ClientSocket *socket)
+{
+ this->socket = socket;
+ router->setSocket(socket);
+}
+
+Server *ServerPlayer::getServer() const
+{
+ return room->getServer();
+}
+
+Room *ServerPlayer::getRoom() const
+{
+ return room;
+}
+
+void ServerPlayer::setRoom(Room* room)
+{
+ this->room = room;
+}
+
+void ServerPlayer::speak(const QString& message)
+{
+ ;
+}
+
+void ServerPlayer::doRequest(const QString& command, const QString& json_data, int timeout)
+{
+ int type = Router::TYPE_REQUEST | Router::SRC_SERVER | Router::DEST_CLIENT;
+ router->request(type, command, json_data, timeout);
+}
+
+void ServerPlayer::doReply(const QString& command, const QString& json_data)
+{
+ int type = Router::TYPE_REPLY | Router::SRC_SERVER | Router::DEST_CLIENT;
+ router->reply(type, command, json_data);
+}
+
+void ServerPlayer::doNotify(const QString& command, const QString& json_data)
+{
+ int type = Router::TYPE_NOTIFICATION | Router::SRC_SERVER | Router::DEST_CLIENT;
+ router->notify(type, command, json_data);
+}
+
+void ServerPlayer::prepareForRequest(const QString& command, const QVariant& data)
+{
+ ;
+}
diff --git a/src/server/serverplayer.h b/src/server/serverplayer.h
new file mode 100644
index 00000000..af1def6b
--- /dev/null
+++ b/src/server/serverplayer.h
@@ -0,0 +1,45 @@
+#ifndef _SERVERPLAYER_H
+#define _SERVERPLAYER_H
+
+#include "player.h"
+#include "router.h"
+#include
+class ClientSocket;
+class Server;
+class Room;
+
+class ServerPlayer : public Player {
+ Q_OBJECT
+public:
+ explicit ServerPlayer(Room *room);
+ ~ServerPlayer();
+
+ uint getUid() const;
+
+ void setSocket(ClientSocket *socket);
+
+ Server *getServer() const;
+ Room *getRoom() const;
+ void setRoom(Room *room);
+
+ void speak(const QString &message);
+
+ void doRequest(const QString &command,
+ const QString &json_data, int timeout = -1);
+ void doReply(const QString &command, const QString &json_data);
+ void doNotify(const QString &command, const QString &json_data);
+
+ void prepareForRequest(const QString &command,
+ const QVariant &data = QVariant());
+private:
+ uint uid;
+ ClientSocket *socket; // socket for communicating with client
+ Router *router;
+ Server *server;
+ Room *room; // Room that player is in, maybe lobby
+
+ QString requestCommand;
+ QVariant requestData;
+};
+
+#endif // _SERVERPLAYER_H
diff --git a/src/swig/freekill.i b/src/swig/freekill.i
new file mode 100644
index 00000000..06d7e955
--- /dev/null
+++ b/src/swig/freekill.i
@@ -0,0 +1,232 @@
+%module freekill
+
+%{
+#include "client.h"
+#include "server.h"
+#include "serverplayer.h"
+#include "clientplayer.h"
+#include "room.h"
+#include "qmlbackend.h"
+%}
+
+// ------------------------------------------------------
+// type bindings
+// ------------------------------------------------------
+
+// LuaFunction(int) and lua function
+%naturalvar LuaFunction;
+%typemap(in) LuaFunction
+%{
+if (lua_isfunction(L, $input)) {
+ lua_pushvalue(L, $input);
+ $1 = luaL_ref(L, LUA_REGISTRYINDEX);
+} else {
+ $1 = 0;
+}
+%}
+
+%typemap(out) LuaFunction
+%{
+lua_rawgeti(L, LUA_REGISTRYINDEX, $1);
+SWIG_arg ++;
+%}
+
+// QString and lua string
+%naturalvar QString;
+
+%typemap(in, checkfn = "lua_isstring") QString
+%{ $1 = lua_tostring(L, $input); %}
+
+%typemap(out) QString
+%{ lua_pushstring(L, $1.toUtf8()); SWIG_arg++; %}
+
+// const QString &
+%typemap(in, checkfn = "lua_isstring") QString const &
+%{
+ if (1) { // to avoid 'Jump bypasses variable initialization' error
+ QString $1_str = QString::fromUtf8(lua_tostring(L, $input));
+ $1 = &$1_str;
+ }
+%}
+
+%typemap(out) QString const &
+%{ lua_pushstring(L, $1.toUtf8()); SWIG_arg++; %}
+
+// ------------------------------------------------------
+// classes and functions
+// ------------------------------------------------------
+
+class QObject {
+public:
+ QString objectName();
+ void setObjectName(const char *name);
+ bool inherits(const char *class_name);
+ bool setProperty(const char *name, const QVariant &value);
+ QVariant property(const char *name) const;
+ void setParent(QObject *parent);
+ void deleteLater();
+};
+
+class QThread {};
+
+class QmlBackend : public QObject {
+public:
+ void emitNotifyUI(const char *command, const char *json_data);
+};
+
+extern QmlBackend *Backend;
+
+class Client : public QObject {
+public:
+ void requestServer(const QString &command,
+ const QString &json_data, int timeout = -1);
+ void replyToServer(const QString &command, const QString &json_data);
+ void notifyServer(const QString &command, const QString &json_data);
+
+ LuaFunction callback;
+};
+
+extern Client *ClientInstance;
+
+%{
+void Client::callLua(const QString& command, const QString& json_data)
+{
+ Q_ASSERT(callback);
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, callback);
+ SWIG_NewPointerObj(L, this, SWIGTYPE_p_Client, 0);
+ lua_pushstring(L, command.toUtf8());
+ lua_pushstring(L, json_data.toUtf8());
+
+ int error = lua_pcall(L, 3, 0, 0);
+ if (error) {
+ const char *error_msg = lua_tostring(L, -1);
+ qDebug() << error_msg;
+ }
+}
+%}
+
+class Server : public QObject {
+public:
+ void createRoom(ServerPlayer *owner, const QString &name, unsigned int capacity);
+ Room *findRoom(unsigned int id) const;
+ Room *lobby() const;
+
+ ServerPlayer *findPlayer(unsigned int id) const;
+
+ void updateRoomList(ServerPlayer *user);
+
+ LuaFunction callback;
+};
+
+%{
+void Server::callLua(const QString& command, const QString& json_data)
+{
+ Q_ASSERT(callback);
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, callback);
+ SWIG_NewPointerObj(L, this, SWIGTYPE_p_Server, 0);
+ lua_pushstring(L, command.toUtf8());
+ lua_pushstring(L, json_data.toUtf8());
+
+ int error = lua_pcall(L, 3, 0, 0);
+ if (error) {
+ const char *error_msg = lua_tostring(L, -1);
+ qDebug() << error_msg;
+ }
+}
+%}
+
+extern Server *ServerInstance;
+
+class Player : public QObject {
+ enum State{
+ Invalid,
+ Online,
+ Trust,
+ Offline
+ };
+
+ unsigned int getId() const;
+ void setId(unsigned int id);
+
+ QString getScreenName() const;
+ void setScreenName(const QString &name);
+
+ QString getAvatar() const;
+ void setAvatar(const QString &avatar);
+
+ State getState() const;
+ QString getStateString() const;
+ void setState(State state);
+ void setStateString(const QString &state);
+
+ bool isReady() const;
+ void setReady(bool ready);
+};
+
+class ClientPlayer : public Player {
+public:
+ ClientPlayer(unsigned int id, QObject *parent = nullptr);
+ ~ClientPlayer();
+};
+
+extern ClientPlayer *Self;
+
+class ServerPlayer : public Player {
+public:
+ explicit ServerPlayer(Room *room);
+ ~ServerPlayer();
+
+ unsigned int getUid() const;
+
+ void setSocket(ClientSocket *socket);
+
+ Server *getServer() const;
+ Room *getRoom() const;
+ void setRoom(Room *room);
+
+ void speak(const QString &message);
+
+ void doRequest(const QString &command,
+ const QString &json_data, int timeout = -1);
+ void doReply(const QString &command, const QString &json_data);
+ void doNotify(const QString &command, const QString &json_data);
+
+ void prepareForRequest(const QString &command,
+ const QVariant &data = QVariant());
+};
+
+class Room : public QThread {
+public:
+ explicit Room(Server *m_server);
+ ~Room();
+
+ // Property reader & setter
+ // ==================================={
+ Server *getServer() const;
+ unsigned int getId() const;
+ bool isLobby() const;
+ QString getName() const;
+ void setName(const QString &name);
+ unsigned int getCapacity() const;
+ void setCapacity(unsigned int capacity);
+ bool isFull() const;
+ bool isAbandoned() const;
+
+ ServerPlayer *getOwner() const;
+ void setOwner(ServerPlayer *owner);
+
+ void addPlayer(ServerPlayer *player);
+ void removePlayer(ServerPlayer *player);
+ QHash getPlayers() const;
+ ServerPlayer *findPlayer(unsigned int id) const;
+
+ void setGameLogic(GameLogic *logic);
+ GameLogic *getGameLogic() const;
+ // ====================================}
+
+ void startGame();
+ void doRequest(const QList targets, int timeout);
+ void doNotify(const QList targets, int timeout);
+};
diff --git a/src/ui/qmlbackend.cpp b/src/ui/qmlbackend.cpp
new file mode 100644
index 00000000..b95ebb6c
--- /dev/null
+++ b/src/ui/qmlbackend.cpp
@@ -0,0 +1,52 @@
+#include "qmlbackend.h"
+#include "server.h"
+#include "client.h"
+
+QmlBackend *Backend;
+
+QmlBackend::QmlBackend(QObject* parent)
+ : QObject(parent)
+{
+ Backend = this;
+}
+
+
+void QmlBackend::startServer(ushort port)
+{
+ class Server *server = new class Server(this);
+ if (!server->listen(QHostAddress::Any, port)) {
+ server->deleteLater();
+ emit notifyUI("error_msg", tr("Cannot start server!"));
+ }
+}
+
+void QmlBackend::joinServer(QString address)
+{
+ class Client *client = new class Client(this);
+ connect(client, &Client::error_message, [this, client](const QString &msg){
+ client->deleteLater();
+ emit notifyUI("error_msg", msg);
+ });
+ QString addr = "127.0.0.1";
+ ushort port = 9527u;
+
+ if (address.contains(QChar(':'))) {
+ QStringList texts = address.split(QChar(':'));
+ addr = texts.value(0);
+ port = texts.value(1).toUShort();
+ } else {
+ addr = address;
+ }
+
+ client->connectToHost(QHostAddress(addr), port);
+}
+
+void QmlBackend::replyToServer(const QString& command, const QString& json_data)
+{
+ ClientInstance->replyToServer(command, json_data);
+}
+
+void QmlBackend::notifyServer(const QString& command, const QString& json_data)
+{
+ ClientInstance->notifyServer(command, json_data);
+}
diff --git a/src/ui/qmlbackend.h b/src/ui/qmlbackend.h
new file mode 100644
index 00000000..7eae0774
--- /dev/null
+++ b/src/ui/qmlbackend.h
@@ -0,0 +1,40 @@
+#ifndef _QMLBACKEND_H
+#define _QMLBACKEND_H
+
+#include
+#include
+#include "client.h"
+
+class QmlBackend : public QObject {
+ Q_OBJECT
+public:
+ enum WindowType {
+ Server,
+ Lobby,
+ Room,
+ NotStarted
+ };
+
+ QmlBackend(QObject *parent = nullptr);
+
+ // For lua use
+ void emitNotifyUI(const char *command, const char *json_data) {
+ emit notifyUI(command, json_data);
+ }
+
+signals:
+ void notifyUI(const QString &command, const QString &json_data);
+
+public slots:
+ void startServer(ushort port);
+ void joinServer(QString address);
+ void replyToServer(const QString &command, const QString &json_data);
+ void notifyServer(const QString &command, const QString &json_data);
+
+private:
+ WindowType type;
+};
+
+extern QmlBackend *Backend;
+
+#endif // _QMLBACKEND_H