Commit f2af5ebb authored by Megax's avatar Megax
Browse files

* KopiLua integralva lett a magba nem nem mukodik valamiert normalisan.

parent 153cecd9
/*
** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace KopiLua
{
using TValue = Lua.lua_TValue;
using StkId = Lua.lua_TValue;
using lu_byte = System.Byte;
using lua_Number = System.Double;
using l_uacNumber = System.Double;
using Instruction = System.UInt32;
public partial class Lua
{
/* tags for values visible from Lua */
public const int LAST_TAG = LUA_TTHREAD;
public const int NUM_TAGS = (LAST_TAG+1);
/*
** Extra tags for non-values
*/
public const int LUA_TPROTO = (LAST_TAG+1);
public const int LUA_TUPVAL = (LAST_TAG+2);
public const int LUA_TDEADKEY = (LAST_TAG+3);
public interface ArrayElement
{
void set_index(int index);
void set_array(object array);
}
/*
** Common Header for all collectable objects (in macro form, to be
** included in other objects)
*/
public class CommonHeader
{
public GCObject next;
public lu_byte tt;
public lu_byte marked;
}
/*
** Common header in struct form
*/
public class GCheader : CommonHeader {
};
/*
** Union of all Lua values (in c# we use virtual data members and boxing)
*/
public class Value
{
// in the original code Value is a struct, so all assignments in the code
// need to be replaced with a call to Copy. as it turns out, there are only
// a couple. the vast majority of references to Value are the instance that
// appears in the TValue class, so if you make that a virtual data member and
// omit the set accessor then you'll get a compiler error if anything tries
// to set it.
public void Copy(Value copy)
{
this.p = copy.p;
}
public GCObject gc
{
get {return (GCObject)this.p;}
set {this.p = value;}
}
public object p;
public lua_Number n
{
get { return (lua_Number)this.p; }
set { this.p = (object)value; }
}
public int b
{
get { return (int)this.p; }
set { this.p = (object)value; }
}
};
/*
** Tagged Values
*/
//#define TValuefields Value value; int tt
public class lua_TValue : ArrayElement
{
private lua_TValue[] values = null;
private int index = -1;
public void set_index(int index)
{
this.index = index;
}
public void set_array(object array)
{
this.values = (lua_TValue[])array;
Debug.Assert(this.values != null);
}
public lua_TValue this[int offset]
{
get { return this.values[this.index + offset]; }
}
public lua_TValue this[uint offset]
{
get { return this.values[this.index + (int)offset]; }
}
public static lua_TValue operator +(lua_TValue value, int offset)
{
return value.values[value.index + offset];
}
public static lua_TValue operator +(int offset, lua_TValue value)
{
return value.values[value.index + offset];
}
public static lua_TValue operator -(lua_TValue value, int offset)
{
return value.values[value.index - offset];
}
public static int operator -(lua_TValue value, lua_TValue[] array)
{
Debug.Assert(value.values == array);
return value.index;
}
public static int operator -(lua_TValue a, lua_TValue b)
{
Debug.Assert(a.values == b.values);
return a.index - b.index;
}
public static bool operator <(lua_TValue a, lua_TValue b)
{
Debug.Assert(a.values == b.values);
return a.index < b.index;
}
public static bool operator <=(lua_TValue a, lua_TValue b)
{
Debug.Assert(a.values == b.values);
return a.index <= b.index;
}
public static bool operator >(lua_TValue a, lua_TValue b)
{
Debug.Assert(a.values == b.values);
return a.index > b.index;
}
public static bool operator >=(lua_TValue a, lua_TValue b)
{
Debug.Assert(a.values == b.values);
return a.index >= b.index;
}
public static lua_TValue inc(ref lua_TValue value)
{
value = value[1];
return value[-1];
}
public static lua_TValue dec(ref lua_TValue value)
{
value = value[-1];
return value[1];
}
public static implicit operator int(lua_TValue value)
{
return value.index;
}
public lua_TValue()
{
}
public lua_TValue(lua_TValue copy)
{
this.values = copy.values;
this.index = copy.index;
this.value.Copy(copy.value);
this.tt = copy.tt;
}
public lua_TValue(Value value, int tt)
{
this.values = null;
this.index = 0;
this.value.Copy(value);
this.tt = tt;
}
public Value value = new Value();
public int tt;
};
/* Macros to test type */
internal static bool ttisnil(TValue o) { return (ttype(o) == LUA_TNIL); }
internal static bool ttisnumber(TValue o) {return (ttype(o) == LUA_TNUMBER);}
internal static bool ttisstring(TValue o) {return (ttype(o) == LUA_TSTRING);}
internal static bool ttistable(TValue o) {return (ttype(o) == LUA_TTABLE);}
internal static bool ttisfunction(TValue o) {return (ttype(o) == LUA_TFUNCTION);}
internal static bool ttisboolean(TValue o) { return (ttype(o) == LUA_TBOOLEAN); }
internal static bool ttisuserdata(TValue o) { return (ttype(o) == LUA_TUSERDATA); }
internal static bool ttisthread(TValue o) {return (ttype(o) == LUA_TTHREAD);}
internal static bool ttislightuserdata(TValue o) { return (ttype(o) == LUA_TLIGHTUSERDATA); }
/* Macros to access values */
#if DEBUG
internal static int ttype(TValue o) { return o.tt; }
internal static int ttype(CommonHeader o) { return o.tt; }
internal static GCObject gcvalue(TValue o) { return (GCObject)check_exp(iscollectable(o), o.value.gc); }
internal static object pvalue(TValue o) { return (object)check_exp(ttislightuserdata(o), o.value.p); }
internal static lua_Number nvalue(TValue o) { return (lua_Number)check_exp(ttisnumber(o), o.value.n); }
internal static TString rawtsvalue(TValue o) { return (TString)check_exp(ttisstring(o), o.value.gc.ts); }
internal static TString_tsv tsvalue(TValue o) { return rawtsvalue(o).tsv; }
internal static Udata rawuvalue(TValue o) { return (Udata)check_exp(ttisuserdata(o), o.value.gc.u); }
internal static Udata_uv uvalue(TValue o) { return rawuvalue(o).uv; }
internal static Closure clvalue(TValue o) { return (Closure)check_exp(ttisfunction(o), o.value.gc.cl); }
internal static Table hvalue(TValue o) { return (Table)check_exp(ttistable(o), o.value.gc.h); }
internal static int bvalue(TValue o) { return (int)check_exp(ttisboolean(o), o.value.b); }
internal static lua_State thvalue(TValue o) { return (lua_State)check_exp(ttisthread(o), o.value.gc.th); }
#else
internal static int ttype(TValue o) { return o.tt; }
internal static int ttype(CommonHeader o) { return o.tt; }
internal static GCObject gcvalue(TValue o) { return o.value.gc; }
internal static object pvalue(TValue o) { return o.value.p; }
internal static lua_Number nvalue(TValue o) { return o.value.n; }
internal static TString rawtsvalue(TValue o) { return o.value.gc.ts; }
internal static TString_tsv tsvalue(TValue o) { return rawtsvalue(o).tsv; }
internal static Udata rawuvalue(TValue o) { return o.value.gc.u; }
internal static Udata_uv uvalue(TValue o) { return rawuvalue(o).uv; }
internal static Closure clvalue(TValue o) { return o.value.gc.cl; }
internal static Table hvalue(TValue o) { return o.value.gc.h; }
internal static int bvalue(TValue o) { return o.value.b; }
internal static lua_State thvalue(TValue o) { return (lua_State)check_exp(ttisthread(o), o.value.gc.th); }
#endif
public static int l_isfalse(TValue o) { return ((ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))) ? 1 : 0; }
/*
** for internal debug only
*/
[Conditional("DEBUG")]
internal static void checkconsistency(TValue obj)
{
lua_assert(!iscollectable(obj) || (ttype(obj) == (obj).value.gc.gch.tt));
}
[Conditional("DEBUG")]
internal static void checkliveness(global_State g, TValue obj)
{
lua_assert(!iscollectable(obj) ||
((ttype(obj) == obj.value.gc.gch.tt) && !isdead(g, obj.value.gc)));
}
/* Macros to set values */
internal static void setnilvalue(TValue obj) {
obj.tt=LUA_TNIL;
}
internal static void setnvalue(TValue obj, lua_Number x) {
obj.value.n = x;
obj.tt = LUA_TNUMBER;
}
internal static void setpvalue( TValue obj, object x) {
obj.value.p = x;
obj.tt = LUA_TLIGHTUSERDATA;
}
internal static void setbvalue(TValue obj, int x) {
obj.value.b = x;
obj.tt = LUA_TBOOLEAN;
}
internal static void setsvalue(lua_State L, TValue obj, GCObject x) {
obj.value.gc = x;
obj.tt = LUA_TSTRING;
checkliveness(G(L), obj);
}
internal static void setuvalue(lua_State L, TValue obj, GCObject x) {
obj.value.gc = x;
obj.tt = LUA_TUSERDATA;
checkliveness(G(L), obj);
}
internal static void setthvalue(lua_State L, TValue obj, GCObject x) {
obj.value.gc = x;
obj.tt = LUA_TTHREAD;
checkliveness(G(L), obj);
}
internal static void setclvalue(lua_State L, TValue obj, Closure x) {
obj.value.gc = x;
obj.tt = LUA_TFUNCTION;
checkliveness(G(L), obj);
}
internal static void sethvalue(lua_State L, TValue obj, Table x) {
obj.value.gc = x;
obj.tt = LUA_TTABLE;
checkliveness(G(L), obj);
}
internal static void setptvalue(lua_State L, TValue obj, Proto x) {
obj.value.gc = x;
obj.tt = LUA_TPROTO;
checkliveness(G(L), obj);
}
internal static void setobj(lua_State L, TValue obj1, TValue obj2) {
obj1.value.Copy(obj2.value);
obj1.tt = obj2.tt;
checkliveness(G(L), obj1);
}
/*
** different types of sets, according to destination
*/
/* from stack to (same) stack */
//#define setobjs2s setobj
internal static void setobjs2s(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); }
///* to stack (not from same stack) */
//#define setobj2s setobj
internal static void setobj2s(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); }
//#define setsvalue2s setsvalue
internal static void setsvalue2s(lua_State L, TValue obj, TString x) { setsvalue(L, obj, x); }
//#define sethvalue2s sethvalue
internal static void sethvalue2s(lua_State L, TValue obj, Table x) { sethvalue(L, obj, x); }
//#define setptvalue2s setptvalue
internal static void setptvalue2s(lua_State L, TValue obj, Proto x) { setptvalue(L, obj, x); }
///* from table to same table */
//#define setobjt2t setobj
internal static void setobjt2t(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); }
///* to table */
//#define setobj2t setobj
internal static void setobj2t(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); }
///* to new object */
//#define setobj2n setobj
internal static void setobj2n(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); }
//#define setsvalue2n setsvalue
internal static void setsvalue2n(lua_State L, TValue obj, TString x) { setsvalue(L, obj, x); }
internal static void setttype(TValue obj, int tt) { obj.tt = tt; }
internal static bool iscollectable(TValue o) { return (ttype(o) >= LUA_TSTRING); }
//typedef TValue *StkId; /* index to stack elements */
/*
** String headers for string table
*/
public class TString_tsv : GCObject
{
public lu_byte reserved;
public uint hash;
public uint len;
};
public class TString : TString_tsv {
//public L_Umaxalign dummy; /* ensures maximum alignment for strings */
public TString_tsv tsv { get { return this; } }
public TString()
{
}
public TString(CharPtr str) { this.str = str; }
public CharPtr str;
public override string ToString() { return str.ToString(); } // for debugging
};
public static CharPtr getstr(TString ts) { return ts.str; }
public static CharPtr svalue(StkId o) { return getstr(rawtsvalue(o)); }
public class Udata_uv : GCObject
{
public Table metatable;
public Table env;
public uint len;
};
public class Udata : Udata_uv
{
public Udata() { this.uv = this; }
public new Udata_uv uv;
//public L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */
// in the original C code this was allocated alongside the structure memory. it would probably
// be possible to still do that by allocating memory and pinning it down, but we can do the
// same thing just as easily by allocating a seperate byte array for it instead.
public object user_data;
};
/*
** Function Prototypes
*/
public class Proto : GCObject {
public Proto[] protos = null;
public int index = 0;
public Proto this[int offset] {get { return this.protos[this.index + offset]; }}
public TValue[] k; /* constants used by the function */
public Instruction[] code;
public new Proto[] p; /* functions defined inside the function */
public int[] lineinfo; /* map from opcodes to source lines */
public LocVar[] locvars; /* information about local variables */
public TString[] upvalues; /* upvalue names */
public TString source;
public int sizeupvalues;
public int sizek; /* size of `k' */
public int sizecode;
public int sizelineinfo;
public int sizep; /* size of `p' */
public int sizelocvars;
public int linedefined;
public int lastlinedefined;
public GCObject gclist;
public lu_byte nups; /* number of upvalues */
public lu_byte numparams;
public lu_byte is_vararg;
public lu_byte maxstacksize;
};
/* masks for new-style vararg */
public const int VARARG_HASARG = 1;
public const int VARARG_ISVARARG = 2;
public const int VARARG_NEEDSARG = 4;
public class LocVar {
public TString varname;
public int startpc; /* first point where variable is active */
public int endpc; /* first point where variable is dead */
};
/*
** Upvalues
*/
public class UpVal : GCObject {
public TValue v; /* points to stack or to its own value */
public class _u {
public TValue value = new TValue(); /* the value (when closed) */
public class _l { /* double linked list (when open) */
public UpVal prev;
public UpVal next;
};
public _l l = new _l();
}
public new _u u = new _u();
};
/*
** Closures
*/
public class ClosureHeader : GCObject {
public lu_byte isC;
public lu_byte nupvalues;
public GCObject gclist;
public Table env;
};
public class ClosureType {
ClosureHeader header;
public static implicit operator ClosureHeader(ClosureType ctype) {return ctype.header;}
public ClosureType(ClosureHeader header) {this.header = header;}
public lu_byte isC { get { return header.isC; } set { header.isC = value; } }
public lu_byte nupvalues { get { return header.nupvalues; } set { header.nupvalues = value; } }
public GCObject gclist { get { return header.gclist; } set { header.gclist = value; } }
public Table env { get { return header.env; } set { header.env = value; } }
}
public class CClosure : ClosureType {
public CClosure(ClosureHeader header) : base(header) { }
public lua_CFunction f;
public TValue[] upvalue;
};
public class LClosure : ClosureType {
public LClosure(ClosureHeader header) : base(header) { }
public Proto p;
public UpVal[] upvals;
};
public class Closure : ClosureHeader
{
public Closure()
{
c = new CClosure(this);
l = new LClosure(this);
}
public CClosure c;
public LClosure l;
};
public static bool iscfunction(TValue o) { return ((ttype(o) == LUA_TFUNCTION) && (clvalue(o).c.isC != 0)); }
public static bool isLfunction(TValue o) { return ((ttype(o) == LUA_TFUNCTION) && (clvalue(o).c.isC==0)); }
/*
** Tables
*/
public class TKey_nk : TValue
{
public TKey_nk() { }
public TKey_nk(Value value, int tt, Node next) : base(value, tt)
{
this.next = next;
}
public Node next; /* for chaining */
};
public class TKey {
public TKey()
{
this.nk = new TKey_nk();
}
public TKey(TKey copy)
{
this.nk = new TKey_nk(copy.nk.value, copy.nk.tt, copy.nk.next);
}
public TKey(Value value, int tt, Node next)
{
this.nk = new TKey_nk(value, tt, next);
}
public TKey_nk nk = new TKey_nk();
public TValue tvk { get { return this.nk; } }
};
public class Node : ArrayElement
{
private Node[] values = null;
private int index = -1;
public void set_index(int index)
{
this.index = index;
}
public void set_array(object array)
{
this.values = (Node[])array;
Debug.Assert(this.values != null);
}
public Node()
{
this.i_val = new TValue();
this.i_key = new TKey();
}
public Node(Node copy)
{
this.values = copy.values;
this.index = copy.index;
this.i_val = new TValue(copy.i_val);
this.i_key = new TKey(copy.i_key);
}
public Node(TValue i_val, TKey i_key)
{
this.values = new Node[] { this };
this.index = 0;
this.i_val = i_val;
this.i_key = i_key;
}
public TValue i_val;
public TKey i_key;
public Node this[uint offset]
{
get { return this.values[this.index + (int)offset]; }
}
public Node this[int offset]
{
get { return this.values[this.index + offset]; }
}
public static int operator -(Node n1, Node n2)
{
Debug.Assert(n1.values == n2.values);
return n1.index - n2.index;
}
public static Node inc(ref Node node)
{
node = node[1];
return node[-1];
}
public static Node dec(ref Node node)
{
node = node[-1];
return node[1];
}
public static bool operator >(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index > n2.index; }
public static bool operator >=(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index >= n2.index; }
public static bool operator <(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index < n2.index; }
public static bool operator <=(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index <= n2.index; }
public static bool operator ==(Node n1, Node n2)
{
object o1 = n1 as Node;
object o2 = n2 as Node;
if ((o1 == null) && (o2 == null)) return true;
if (o1 == null) return false;
if (o2 == null) return false;
if (n1.values != n2.values) return false;
return n1.index == n2.index;
}
public static bool operator !=(Node n1, Node n2) { return !(n1==n2); }
public override bool Equals(object o) {return this == (Node)o;}
public override int GetHashCode() {return 0;}
};
public class Table : GCObject {
public lu_byte flags; /* 1<<p means tagmethod(p) is not present */
public lu_byte lsizenode; /* log2 of size of `node' array */
public Table metatable;
public TValue[] array; /* array part */
public Node[] node;
public int lastfree; /* any free position is before this position */
public GCObject gclist;
public int sizearray; /* size of `array' array */
};
/*
** `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)))))
internal static int twoto(int x) { return 1 << x; }
internal static int sizenode(Table t) { return twoto(t.lsizenode); }
public static TValue luaO_nilobject_ = new TValue(new Value(), LUA_TNIL);
public static TValue luaO_nilobject = luaO_nilobject_;
public static int ceillog2(int x) {return luaO_log2((uint)(x-1)) + 1;}
/*
** converts an integer to a "floating point byte", represented as
** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
** eeeee != 0 and (xxx) otherwise.
*/
public static int luaO_int2fb (uint x) {
int e = 0; /* expoent */
while (x >= 16) {
x = (x+1) >> 1;
e++;
}
if (x < 8) return (int)x;
else return ((e+1) << 3) | (cast_int(x) - 8);
}
/* converts back */
public static int luaO_fb2int (int x) {
int e = (x >> 3) & 31;
if (e == 0) return x;
else return ((x & 7)+8) << (e - 1);
}
private readonly static lu_byte[] log_2 = {
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
};
public static int luaO_log2 (uint x) {
int l = -1;
while (x >= 256) { l += 8; x >>= 8; }
return l + log_2[x];
}
public static int luaO_rawequalObj (TValue t1, TValue t2) {
Console.WriteLine("luaO_rawequalObj: {0}", ttype(t1) != ttype(t2));
if (ttype(t1) != ttype(t2)) return 0;
else switch (ttype(t1)) {
case LUA_TNIL:
return 1;
case LUA_TNUMBER:
return luai_numeq(nvalue(t1), nvalue(t2)) ? 1 : 0;
case LUA_TBOOLEAN:
return bvalue(t1) == bvalue(t2) ? 1 : 0; /* boolean true must be 1....but not in C# !! */
case LUA_TLIGHTUSERDATA:
return pvalue(t1) == pvalue(t2) ? 1 : 0;
default:
lua_assert(iscollectable(t1));
Console.WriteLine("luaO_rawequalObj1-0: {0}", gcvalue(t1));
Console.WriteLine("luaO_rawequalObj1-1: {0}", gcvalue(t2));
Console.WriteLine("luaO_rawequalObj1: {0}", gcvalue(t1) == gcvalue(t2));
return gcvalue(t1) == gcvalue(t2) ? 1 : 0;
}
}
public static int luaO_str2d (CharPtr s, out lua_Number result) {
CharPtr endptr;
result = lua_str2number(s, out endptr);
if (endptr == s) return 0; /* conversion failed */
if (endptr[0] == 'x' || endptr[0] == 'X') /* maybe an hexadecimal constant? */
result = cast_num(strtoul(s, out endptr, 16));
if (endptr[0] == '\0') return 1; /* most common case */
while (isspace(endptr[0])) endptr = endptr.next();
if (endptr[0] != '\0') return 0; /* invalid trailing characters? */
return 1;
}
private static void pushstr (lua_State L, CharPtr str) {
setsvalue2s(L, L.top, luaS_new(L, str));
incr_top(L);
}
/* this function handles only `%d', `%c', %f, %p, and `%s' formats */
public static CharPtr luaO_pushvfstring (lua_State L, CharPtr fmt, params object[] argp) {
int parm_index = 0;
int n = 1;
pushstr(L, "");
for (;;) {
CharPtr e = strchr(fmt, '%');
if (e == null) break;
setsvalue2s(L, L.top, luaS_newlstr(L, fmt, (uint)(e-fmt)));
incr_top(L);
switch (e[1]) {
case 's': {
object o = argp[parm_index++];
CharPtr s = o as CharPtr;
if (s == null)
s = (string)o;
if (s == null) s = "(null)";
pushstr(L, s);
break;
}
case 'c': {
CharPtr buff = new char[2];
buff[0] = (char)(int)argp[parm_index++];
buff[1] = '\0';
pushstr(L, buff);
break;
}
case 'd': {
setnvalue(L.top, (int)argp[parm_index++]);
incr_top(L);
break;
}
case 'f': {
setnvalue(L.top, (l_uacNumber)argp[parm_index++]);
incr_top(L);
break;
}
case 'p': {
//CharPtr buff = new char[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */
CharPtr buff = new char[32];
sprintf(buff, "0x%08x", argp[parm_index++].GetHashCode());
pushstr(L, buff);
break;
}
case '%': {
pushstr(L, "%");
break;
}
default: {
CharPtr buff = new char[3];
buff[0] = '%';
buff[1] = e[1];
buff[2] = '\0';
pushstr(L, buff);
break;
}
}
n += 2;
fmt = e+2;
}
pushstr(L, fmt);
luaV_concat(L, n+1, cast_int(L.top - L.base_) - 1);
L.top -= n;
return svalue(L.top - 1);
}
public static CharPtr luaO_pushfstring(lua_State L, CharPtr fmt, params object[] args)
{
return luaO_pushvfstring(L, fmt, args);
}
public static void luaO_chunkid (CharPtr out_, CharPtr source, uint bufflen) {
//out_ = "";
if (source[0] == '=') {
strncpy(out_, source+1, (int)bufflen); /* remove first char */
out_[bufflen-1] = '\0'; /* ensures null termination */
}
else { /* out = "source", or "...source" */
if (source[0] == '@') {
uint l;
source = source.next(); /* skip the `@' */
bufflen -= (uint)(" '...' ".Length + 1);
l = (uint)strlen(source);
strcpy(out_, "");
if (l > bufflen) {
source += (l-bufflen); /* get last part of file name */
strcat(out_, "...");
}
strcat(out_, source);
}
else { /* out = [string "string"] */
uint len = strcspn(source, "\n\r"); /* stop at first newline */
bufflen -= (uint)(" [string \"...\"] ".Length + 1);
if (len > bufflen) len = bufflen;
strcpy(out_, "[string \"");
if (source[len] != '\0') { /* must truncate? */
strncat(out_, source, (int)len);
strcat(out_, "...");
}
else
strcat(out_, source);
strcat(out_, "\"]");
}
}
}
}
}
/*
** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $
** See Copyright Notice in lua.h
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace KopiLua
{
using lu_byte = System.Byte;
using Instruction = System.UInt32;
public partial class Lua
{
/*===========================================================================
We assume that instructions are unsigned numbers.
All instructions have an opcode in the first 6 bits.
Instructions can have the following fields:
`A' : 8 bits
`B' : 9 bits
`C' : 9 bits
`Bx' : 18 bits (`B' and `C' together)
`sBx' : signed Bx
A signed argument is represented in excess K; that is, the number
value is the unsigned value minus K. K is exactly the maximum value
for that argument (so that -max is represented by 0, and +max is
represented by 2*max), which is half the maximum for the corresponding
unsigned argument.
===========================================================================*/
public enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */
/*
** size and position of opcode arguments.
*/
public const int SIZE_C = 9;
public const int SIZE_B = 9;
public const int SIZE_Bx = (SIZE_C + SIZE_B);
public const int SIZE_A = 8;
public const int SIZE_OP = 6;
public const int POS_OP = 0;
public const int POS_A = (POS_OP + SIZE_OP);
public const int POS_C = (POS_A + SIZE_A);
public const int POS_B = (POS_C + SIZE_C);
public const int POS_Bx = POS_C;
/*
** limits for opcode arguments.
** we use (signed) int to manipulate most arguments,
** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
*/
//#if SIZE_Bx < LUAI_BITSINT-1
public const int MAXARG_Bx = ((1<<SIZE_Bx)-1);
public const int MAXARG_sBx = (MAXARG_Bx>>1); /* `sBx' is signed */
//#else
//public const int MAXARG_Bx = System.Int32.MaxValue;
//public const int MAXARG_sBx = System.Int32.MaxValue;
//#endif
public const uint MAXARG_A = (uint)((1 << (int)SIZE_A) -1);
public const uint MAXARG_B = (uint)((1 << (int)SIZE_B) -1);
public const uint MAXARG_C = (uint)((1 << (int)SIZE_C) -1);
/* creates a mask with `n' 1 bits at position `p' */
//public static int MASK1(int n, int p) { return ((~((~(Instruction)0) << n)) << p); }
internal static uint MASK1(int n, int p) { return (uint)((~((~0) << n)) << p); }
/* creates a mask with `n' 0 bits at position `p' */
internal static uint MASK0(int n, int p) { return (uint)(~MASK1(n, p)); }
/*
** the following macros help to manipulate instructions
*/
internal static OpCode GET_OPCODE(Instruction i)
{
return (OpCode)((i >> POS_OP) & MASK1(SIZE_OP, 0));
}
internal static OpCode GET_OPCODE(InstructionPtr i) { return GET_OPCODE(i[0]); }
internal static void SET_OPCODE(ref Instruction i, Instruction o)
{
i = (Instruction)(i & MASK0(SIZE_OP, POS_OP)) | ((o << POS_OP) & MASK1(SIZE_OP, POS_OP));
}
internal static void SET_OPCODE(ref Instruction i, OpCode opcode)
{
i = (Instruction)(i & MASK0(SIZE_OP, POS_OP)) | (((uint)opcode << POS_OP) & MASK1(SIZE_OP, POS_OP));
}
internal static void SET_OPCODE(InstructionPtr i, OpCode opcode) { SET_OPCODE(ref i.codes[i.pc], opcode); }
internal static int GETARG_A(Instruction i)
{
return (int)((i >> POS_A) & MASK1(SIZE_A, 0));
}
internal static int GETARG_A(InstructionPtr i) { return GETARG_A(i[0]); }
internal static void SETARG_A(InstructionPtr i, int u)
{
i[0] = (Instruction)((i[0] & MASK0(SIZE_A, POS_A)) | ((u << POS_A) & MASK1(SIZE_A, POS_A)));
}
internal static int GETARG_B(Instruction i)
{
return (int)((i>>POS_B) & MASK1(SIZE_B,0));
}
internal static int GETARG_B(InstructionPtr i) { return GETARG_B(i[0]); }
internal static void SETARG_B(InstructionPtr i, int b)
{
i[0] = (Instruction)((i[0] & MASK0(SIZE_B, POS_B)) | ((b << POS_B) & MASK1(SIZE_B, POS_B)));
}
internal static int GETARG_C(Instruction i)
{
return (int)((i>>POS_C) & MASK1(SIZE_C,0));
}
internal static int GETARG_C(InstructionPtr i) { return GETARG_C(i[0]); }
internal static void SETARG_C(InstructionPtr i, int b)
{
i[0] = (Instruction)((i[0] & MASK0(SIZE_C, POS_C)) | ((b << POS_C) & MASK1(SIZE_C, POS_C)));
}
internal static int GETARG_Bx(Instruction i)
{
return (int)((i>>POS_Bx) & MASK1(SIZE_Bx,0));
}
internal static int GETARG_Bx(InstructionPtr i) { return GETARG_Bx(i[0]); }
internal static void SETARG_Bx(InstructionPtr i, int b)
{
i[0] = (Instruction)((i[0] & MASK0(SIZE_Bx, POS_Bx)) | ((b << POS_Bx) & MASK1(SIZE_Bx, POS_Bx)));
}
internal static int GETARG_sBx(Instruction i)
{
return (GETARG_Bx(i) - MAXARG_sBx);
}
internal static int GETARG_sBx(InstructionPtr i) { return GETARG_sBx(i[0]); }
internal static void SETARG_sBx(InstructionPtr i, int b)
{
SETARG_Bx(i, b + MAXARG_sBx);
}
internal static int CREATE_ABC(OpCode o, int a, int b, int c)
{
return (int)(((int)o << POS_OP) | (a << POS_A) | (b << POS_B) | (c << POS_C));
}
internal static int CREATE_ABx(OpCode o, int a, int bc)
{
int result = (int)(((int)o << POS_OP) | (a << POS_A) | (bc << POS_Bx));
return (int)(((int)o << POS_OP) | (a << POS_A) | (bc << POS_Bx));
}
/*
** Macros to operate RK indices
*/
/* this bit 1 means constant (0 means register) */
internal readonly static int BITRK = (1 << (SIZE_B - 1));
/* test whether value is a constant */
internal static int ISK(int x) { return x & BITRK; }
/* gets the index of the constant */
internal static int INDEXK(int r) { return r & (~BITRK); }
internal static readonly int MAXINDEXRK = BITRK - 1;
/* code a constant index as a RK value */
internal static int RKASK(int x) { return x | BITRK; }
/*
** invalid register that fits in 8 bits
*/
internal static readonly int NO_REG = (int)MAXARG_A;
/*
** R(x) - register
** Kst(x) - constant (in constant table)
** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
*/
/*
** grep "ORDER OP" if you change these enums
*/
public enum OpCode {
/*----------------------------------------------------------------------
name args description
------------------------------------------------------------------------*/
OP_MOVE,/* A B R(A) := R(B) */
OP_LOADK,/* A Bx R(A) := Kst(Bx) */
OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */
OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */
OP_GETUPVAL,/* A B R(A) := UpValue[B] */
OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx)] */
OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */
OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx)] := R(A) */
OP_SETUPVAL,/* A B UpValue[B] := R(A) */
OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */
OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */
OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
OP_ADD,/* A B C R(A) := RK(B) + RK(C) */
OP_SUB,/* A B C R(A) := RK(B) - RK(C) */
OP_MUL,/* A B C R(A) := RK(B) * RK(C) */
OP_DIV,/* A B C R(A) := RK(B) / RK(C) */
OP_MOD,/* A B C R(A) := RK(B) % RK(C) */
OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */
OP_UNM,/* A B R(A) := -R(B) */
OP_NOT,/* A B R(A) := not R(B) */
OP_LEN,/* A B R(A) := length of R(B) */
OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
OP_JMP,/* sBx pc+=sBx */
OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
OP_TEST,/* A C if not (R(A) <=> C) then pc++ */
OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */
OP_FORLOOP,/* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */
OP_TFORLOOP,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */
OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/
OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
};
public const int NUM_OPCODES = (int)OpCode.OP_VARARG;
/*===========================================================================
Notes:
(*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
and can be 0: OP_CALL then sets `top' to last_result+1, so
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
(*) In OP_VARARG, if (B == 0) then use actual number of varargs and
set top (like in OP_CALL with C == 0).
(*) In OP_RETURN, if (B == 0) then return up to `top'
(*) In OP_SETLIST, if (B == 0) then B = `top';
if (C == 0) then next `instruction' is real C
(*) For comparisons, A specifies what condition the test should accept
(true or false).
(*) All `skips' (pc++) assume that next instruction is a jump
===========================================================================*/
/*
** masks for instruction properties. The format is:
** bits 0-1: op mode
** bits 2-3: C arg mode
** bits 4-5: B arg mode
** bit 6: instruction set register A
** bit 7: operator is a test
*/
public enum OpArgMask {
OpArgN, /* argument is not used */
OpArgU, /* argument is used */
OpArgR, /* argument is a register or a jump offset */
OpArgK /* argument is a constant or register/constant */
};
public static OpMode getOpMode(OpCode m) {return (OpMode)(luaP_opmodes[(int)m] & 3);}
public static OpArgMask getBMode(OpCode m) { return (OpArgMask)((luaP_opmodes[(int)m] >> 4) & 3); }
public static OpArgMask getCMode(OpCode m) { return (OpArgMask)((luaP_opmodes[(int)m] >> 2) & 3); }
public static int testAMode(OpCode m) { return luaP_opmodes[(int)m] & (1 << 6); }
public static int testTMode(OpCode m) { return luaP_opmodes[(int)m] & (1 << 7); }
/* number of list items to accumulate before a SETLIST instruction */
public const int LFIELDS_PER_FLUSH = 50;
/* ORDER OP */
private readonly static CharPtr[] luaP_opnames = {
"MOVE",
"LOADK",
"LOADBOOL",
"LOADNIL",
"GETUPVAL",
"GETGLOBAL",
"GETTABLE",
"SETGLOBAL",
"SETUPVAL",
"SETTABLE",
"NEWTABLE",
"SELF",
"ADD",
"SUB",
"MUL",
"DIV",
"MOD",
"POW",
"UNM",
"NOT",
"LEN",
"CONCAT",
"JMP",
"EQ",
"LT",
"LE",
"TEST",
"TESTSET",
"CALL",
"TAILCALL",
"RETURN",
"FORLOOP",
"FORPREP",
"TFORLOOP",
"SETLIST",
"CLOSE",
"CLOSURE",
"VARARG",
};
private static lu_byte opmode(lu_byte t, lu_byte a, OpArgMask b, OpArgMask c, OpMode m)
{
return (lu_byte)(((t) << 7) | ((a) << 6) | (((lu_byte)b) << 4) | (((lu_byte)c) << 2) | ((lu_byte)m));
}
private readonly static lu_byte[] luaP_opmodes = {
/* T A B C mode opcode */
opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_MOVE */
,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgN, OpMode.iABx) /* OP_LOADK */
,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_LOADBOOL */
,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_LOADNIL */
,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_GETUPVAL */
,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgN, OpMode.iABx) /* OP_GETGLOBAL */
,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgK, OpMode.iABC) /* OP_GETTABLE */
,opmode(0, 0, OpArgMask.OpArgK, OpArgMask.OpArgN, OpMode.iABx) /* OP_SETGLOBAL */
,opmode(0, 0, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_SETUPVAL */
,opmode(0, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_SETTABLE */
,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_NEWTABLE */
,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgK, OpMode.iABC) /* OP_SELF */
,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_ADD */
,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_SUB */
,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_MUL */
,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_DIV */
,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_MOD */
,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_POW */
,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_UNM */
,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_NOT */
,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_LEN */
,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgR, OpMode.iABC) /* OP_CONCAT */
,opmode(0, 0, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iAsBx) /* OP_JMP */
,opmode(1, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_EQ */
,opmode(1, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_LT */
,opmode(1, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_LE */
,opmode(1, 1, OpArgMask.OpArgR, OpArgMask.OpArgU, OpMode.iABC) /* OP_TEST */
,opmode(1, 1, OpArgMask.OpArgR, OpArgMask.OpArgU, OpMode.iABC) /* OP_TESTSET */
,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_CALL */
,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_TAILCALL */
,opmode(0, 0, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_RETURN */
,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iAsBx) /* OP_FORLOOP */
,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iAsBx) /* OP_FORPREP */
,opmode(1, 0, OpArgMask.OpArgN, OpArgMask.OpArgU, OpMode.iABC) /* OP_TFORLOOP */
,opmode(0, 0, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_SETLIST */
,opmode(0, 0, OpArgMask.OpArgN, OpArgMask.OpArgN, OpMode.iABC) /* OP_CLOSE */
,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABx) /* OP_CLOSURE */
,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_VARARG */
};
}
}
/*
** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
using System;
using System.Threading;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace KopiLua
{
using TValue = Lua.lua_TValue;
using StkId = Lua.lua_TValue;
using lua_Integer = System.Int32;
using lua_Number = System.Double;
public partial class Lua
{
private static int os_pushresult (lua_State L, int i, CharPtr filename) {
int en = errno(); /* calls to Lua API may change this value */
if (i != 0) {
lua_pushboolean(L, 1);
return 1;
}
else {
lua_pushnil(L);
lua_pushfstring(L, "%s: %s", filename, strerror(en));
lua_pushinteger(L, en);
return 3;
}
}
private static int os_execute (lua_State L) {
#if XBOX || SILVERLIGHT
luaL_error(L, "os_execute not supported on XBox360");
#else
CharPtr strCmdLine = "/C regenresx " + luaL_optstring(L, 1, null);
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.EnableRaisingEvents=false;
proc.StartInfo.FileName = "CMD.exe";
proc.StartInfo.Arguments = strCmdLine.ToString();
proc.Start();
proc.WaitForExit();
lua_pushinteger(L, proc.ExitCode);
#endif
return 1;
}
private static int os_remove (lua_State L) {
CharPtr filename = luaL_checkstring(L, 1);
int result = 1;
try {File.Delete(filename.ToString());} catch {result = 0;}
return os_pushresult(L, result, filename);
}
private static int os_rename (lua_State L) {
CharPtr fromname = luaL_checkstring(L, 1);
CharPtr toname = luaL_checkstring(L, 2);
int result;
try
{
File.Move(fromname.ToString(), toname.ToString());
result = 0;
}
catch
{
result = 1; // todo: this should be a proper error code
}
return os_pushresult(L, result, fromname);
}
private static int os_tmpname (lua_State L) {
#if XBOX
luaL_error(L, "os_tmpname not supported on Xbox360");
#else
lua_pushstring(L, Path.GetTempFileName());
#endif
return 1;
}
private static int os_getenv (lua_State L) {
lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if null push nil */
return 1;
}
private static int os_clock (lua_State L) {
long ticks = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
lua_pushnumber(L, ((lua_Number)ticks)/(lua_Number)1000);
return 1;
}
/*
** {======================================================
** Time/Date operations
** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
** wday=%w+1, yday=%j, isdst=? }
** =======================================================
*/
private static void setfield (lua_State L, CharPtr key, int value) {
lua_pushinteger(L, value);
lua_setfield(L, -2, key);
}
private static void setboolfield (lua_State L, CharPtr key, int value) {
if (value < 0) /* undefined? */
return; /* does not set field */
lua_pushboolean(L, value);
lua_setfield(L, -2, key);
}
private static int getboolfield (lua_State L, CharPtr key) {
int res;
lua_getfield(L, -1, key);
res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1);
lua_pop(L, 1);
return res;
}
private static int getfield (lua_State L, CharPtr key, int d) {
int res;
lua_getfield(L, -1, key);
if (lua_isnumber(L, -1) != 0)
res = (int)lua_tointeger(L, -1);
else {
if (d < 0)
return luaL_error(L, "field " + LUA_QS + " missing in date table", key);
res = d;
}
lua_pop(L, 1);
return res;
}
private static int os_date (lua_State L) {
CharPtr s = luaL_optstring(L, 1, "%c");
DateTime stm;
if (s[0] == '!') { /* UTC? */
stm = DateTime.UtcNow;
s.inc(); /* skip `!' */
}
else
stm = DateTime.Now;
if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */
setfield(L, "sec", stm.Second);
setfield(L, "min", stm.Minute);
setfield(L, "hour", stm.Hour);
setfield(L, "day", stm.Day);
setfield(L, "month", stm.Month);
setfield(L, "year", stm.Year);
setfield(L, "wday", (int)stm.DayOfWeek);
setfield(L, "yday", stm.DayOfYear);
setboolfield(L, "isdst", stm.IsDaylightSavingTime() ? 1 : 0);
}
else {
luaL_error(L, "strftime not implemented yet"); // todo: implement this - mjf
#if false
CharPtr cc = new char[3];
luaL_Buffer b;
cc[0] = '%'; cc[2] = '\0';
luaL_buffinit(L, b);
for (; s[0] != 0; s.inc()) {
if (s[0] != '%' || s[1] == '\0') /* no conversion specifier? */
luaL_addchar(b, s[0]);
else {
uint reslen;
CharPtr buff = new char[200]; /* should be big enough for any conversion result */
s.inc();
cc[1] = s[0];
reslen = strftime(buff, buff.Length, cc, stm);
luaL_addlstring(b, buff, reslen);
}
}
luaL_pushresult(b);
#endif // #if 0
}
return 1;
}
private static int os_time (lua_State L) {
DateTime t;
if (lua_isnoneornil(L, 1)) /* called without args? */
t = DateTime.Now; /* get current time */
else {
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); /* make sure table is at the top */
int sec = getfield(L, "sec", 0);
int min = getfield(L, "min", 0);
int hour = getfield(L, "hour", 12);
int day = getfield(L, "day", -1);
int month = getfield(L, "month", -1) - 1;
int year = getfield(L, "year", -1) - 1900;
int isdst = getboolfield(L, "isdst"); // todo: implement this - mjf
t = new DateTime(year, month, day, hour, min, sec);
}
lua_pushnumber(L, t.Ticks);
return 1;
}
private static int os_difftime (lua_State L) {
long ticks = (long)luaL_checknumber(L, 1) - (long)luaL_optnumber(L, 2, 0);
lua_pushnumber(L, ticks/TimeSpan.TicksPerSecond);
return 1;
}
/* }====================================================== */
// locale not supported yet
private static int os_setlocale (lua_State L) {
/*
static string[] cat = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
LC_NUMERIC, LC_TIME};
static string[] catnames[] = {"all", "collate", "ctype", "monetary",
"numeric", "time", null};
CharPtr l = luaL_optstring(L, 1, null);
int op = luaL_checkoption(L, 2, "all", catnames);
lua_pushstring(L, setlocale(cat[op], l));
*/
CharPtr l = luaL_optstring(L, 1, null);
lua_pushstring(L, "C");
return (l.ToString() == "C") ? 1 : 0;
}
private static int os_exit (lua_State L) {
#if XBOX
luaL_error(L, "os_exit not supported on XBox360");
#else
#if SILVERLIGHT
throw new SystemException();
#else
Environment.Exit(EXIT_SUCCESS);
#endif
#endif
return 0;
}
private readonly static luaL_Reg[] syslib = {
new luaL_Reg("clock", os_clock),
new luaL_Reg("date", os_date),
new luaL_Reg("difftime", os_difftime),
new luaL_Reg("execute", os_execute),
new luaL_Reg("exit", os_exit),
new luaL_Reg("getenv", os_getenv),
new luaL_Reg("remove", os_remove),
new luaL_Reg("rename", os_rename),
new luaL_Reg("setlocale", os_setlocale),
new luaL_Reg("time", os_time),
new luaL_Reg("tmpname", os_tmpname),
new luaL_Reg(null, null)
};
/* }====================================================== */
public static int luaopen_os (lua_State L) {
luaL_register(L, LUA_OSLIBNAME, syslib);
return 1;
}
}
}
/*
** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace KopiLua
{
using lu_byte = System.Byte;
using lua_Number = System.Double;
using ZIO = Lua.Zio;
public partial class Lua
{
/*
** Expression descriptor
*/
public enum expkind {
VVOID, /* no value */
VNIL,
VTRUE,
VFALSE,
VK, /* info = index of constant in `k' */
VKNUM, /* nval = numerical value */
VLOCAL, /* info = local register */
VUPVAL, /* info = index of upvalue in `upvalues' */
VGLOBAL, /* info = index of table; aux = index of global name in `k' */
VINDEXED, /* info = table register; aux = index register (or `k') */
VJMP, /* info = instruction pc */
VRELOCABLE, /* info = instruction pc */
VNONRELOC, /* info = result register */
VCALL, /* info = instruction pc */
VVARARG /* info = instruction pc */
};
public class expdesc {
public void Copy(expdesc e)
{
this.k = e.k;
this.u.Copy(e.u);
this.t = e.t;
this.f = e.f;
}
public expkind k;
public class _u
{
public void Copy(_u u)
{
this.s.Copy(u.s);
this.nval = u.nval;
}
public class _s
{
public void Copy(_s s)
{
this.info = s.info;
this.aux = s.aux;
}
public int info, aux;
};
public _s s = new _s();
public lua_Number nval;
};
public _u u = new _u();
public int t; /* patch list of `exit when true' */
public int f; /* patch list of `exit when false' */
};
public class upvaldesc {
public lu_byte k;
public lu_byte info;
};
/* state needed to generate code for a given function */
public class FuncState {
public FuncState()
{
for (int i=0; i<this.upvalues.Length; i++)
this.upvalues[i] = new upvaldesc();
}
public Proto f; /* current function header */
public Table h; /* table to find (and reuse) elements in `k' */
public FuncState prev; /* enclosing function */
public LexState ls; /* lexical state */
public lua_State L; /* copy of the Lua state */
public BlockCnt bl; /* chain of current blocks */
public int pc; /* next position to code (equivalent to `ncode') */
public int lasttarget; /* `pc' of last `jump target' */
public int jpc; /* list of pending jumps to `pc' */
public int freereg; /* first free register */
public int nk; /* number of elements in `k' */
public int np; /* number of elements in `p' */
public short nlocvars; /* number of elements in `locvars' */
public lu_byte nactvar; /* number of active local variables */
public upvaldesc[] upvalues = new upvaldesc[LUAI_MAXUPVALUES]; /* upvalues */
public ushort[] actvar = new ushort[LUAI_MAXVARS]; /* declared-variable stack */
};
public static int hasmultret(expkind k) {return ((k) == expkind.VCALL || (k) == expkind.VVARARG) ? 1 : 0;}
public static LocVar getlocvar(FuncState fs, int i) {return fs.f.locvars[fs.actvar[i]];}
public static void luaY_checklimit(FuncState fs, int v, int l, CharPtr m) { if ((v) > (l)) errorlimit(fs, l, m); }
/*
** nodes for block list (list of active blocks)
*/
public class BlockCnt {
public BlockCnt previous; /* chain */
public int breaklist; /* list of jumps out of this loop */
public lu_byte nactvar; /* # active locals outside the breakable structure */
public lu_byte upval; /* true if some variable in the block is an upvalue */
public lu_byte isbreakable; /* true if `block' is a loop */
};
private static void anchor_token (LexState ls) {
if (ls.t.token == (int)RESERVED.TK_NAME || ls.t.token == (int)RESERVED.TK_STRING) {
TString ts = ls.t.seminfo.ts;
luaX_newstring(ls, getstr(ts), ts.tsv.len);
}
}
private static void error_expected (LexState ls, int token) {
luaX_syntaxerror(ls,
luaO_pushfstring(ls.L, LUA_QS + " expected", luaX_token2str(ls, token)));
}
private static void errorlimit (FuncState fs, int limit, CharPtr what) {
CharPtr msg = (fs.f.linedefined == 0) ?
luaO_pushfstring(fs.L, "main function has more than %d %s", limit, what) :
luaO_pushfstring(fs.L, "function at line %d has more than %d %s",
fs.f.linedefined, limit, what);
luaX_lexerror(fs.ls, msg, 0);
}
private static int testnext (LexState ls, int c) {
if (ls.t.token == c) {
luaX_next(ls);
return 1;
}
else return 0;
}
private static void check (LexState ls, int c) {
if (ls.t.token != c)
error_expected(ls, c);
}
private static void checknext (LexState ls, int c) {
check(ls, c);
luaX_next(ls);
}
public static void check_condition(LexState ls, bool c, CharPtr msg) {
if (!(c)) luaX_syntaxerror(ls, msg);
}
private static void check_match (LexState ls, int what, int who, int where) {
if (testnext(ls, what)==0) {
if (where == ls.linenumber)
error_expected(ls, what);
else {
luaX_syntaxerror(ls, luaO_pushfstring(ls.L,
LUA_QS + " expected (to close " + LUA_QS + " at line %d)",
luaX_token2str(ls, what), luaX_token2str(ls, who), where));
}
}
}
private static TString str_checkname (LexState ls) {
TString ts;
check(ls, (int)RESERVED.TK_NAME);
ts = ls.t.seminfo.ts;
luaX_next(ls);
return ts;
}
private static void init_exp (expdesc e, expkind k, int i) {
e.f = e.t = NO_JUMP;
e.k = k;
e.u.s.info = i;
}
private static void codestring (LexState ls, expdesc e, TString s) {
init_exp(e, expkind.VK, luaK_stringK(ls.fs, s));
}
private static void checkname(LexState ls, expdesc e) {
codestring(ls, e, str_checkname(ls));
}
private static int registerlocalvar (LexState ls, TString varname) {
FuncState fs = ls.fs;
Proto f = fs.f;
int oldsize = f.sizelocvars;
luaM_growvector(ls.L, ref f.locvars, fs.nlocvars, ref f.sizelocvars,
(int)SHRT_MAX, "too many local variables");
while (oldsize < f.sizelocvars) f.locvars[oldsize++].varname = null;
f.locvars[fs.nlocvars].varname = varname;
luaC_objbarrier(ls.L, f, varname);
return fs.nlocvars++;
}
public static void new_localvarliteral(LexState ls, CharPtr v, int n) {
new_localvar(ls, luaX_newstring(ls, "" + v, (uint)(v.chars.Length - 1)), n);
}
private static void new_localvar (LexState ls, TString name, int n) {
FuncState fs = ls.fs;
luaY_checklimit(fs, fs.nactvar+n+1, LUAI_MAXVARS, "local variables");
fs.actvar[fs.nactvar+n] = (ushort)registerlocalvar(ls, name);
}
private static void adjustlocalvars (LexState ls, int nvars) {
FuncState fs = ls.fs;
fs.nactvar = cast_byte(fs.nactvar + nvars);
for (; nvars!=0; nvars--) {
getlocvar(fs, fs.nactvar - nvars).startpc = fs.pc;
}
}
private static void removevars (LexState ls, int tolevel) {
FuncState fs = ls.fs;
while (fs.nactvar > tolevel)
getlocvar(fs, --fs.nactvar).endpc = fs.pc;
}
private static int indexupvalue (FuncState fs, TString name, expdesc v) {
int i;
Proto f = fs.f;
int oldsize = f.sizeupvalues;
for (i=0; i<f.nups; i++) {
if ((int)fs.upvalues[i].k == (int)v.k && fs.upvalues[i].info == v.u.s.info) {
lua_assert(f.upvalues[i] == name);
return i;
}
}
/* new one */
luaY_checklimit(fs, f.nups + 1, LUAI_MAXUPVALUES, "upvalues");
luaM_growvector(fs.L, ref f.upvalues, f.nups, ref f.sizeupvalues, MAX_INT, "");
while (oldsize < f.sizeupvalues) f.upvalues[oldsize++] = null;
f.upvalues[f.nups] = name;
luaC_objbarrier(fs.L, f, name);
lua_assert(v.k == expkind.VLOCAL || v.k == expkind.VUPVAL);
fs.upvalues[f.nups].k = cast_byte(v.k);
fs.upvalues[f.nups].info = cast_byte(v.u.s.info);
return f.nups++;
}
private static int searchvar (FuncState fs, TString n) {
int i;
for (i=fs.nactvar-1; i >= 0; i--) {
if (n == getlocvar(fs, i).varname)
return i;
}
return -1; /* not found */
}
private static void markupval (FuncState fs, int level) {
BlockCnt bl = fs.bl;
while ((bl!=null) && bl.nactvar > level) bl = bl.previous;
if (bl != null) bl.upval = 1;
}
private static expkind singlevaraux(FuncState fs, TString n, expdesc var, int base_)
{
if (fs == null) { /* no more levels? */
init_exp(var, expkind.VGLOBAL, NO_REG); /* default is global variable */
return expkind.VGLOBAL;
}
else {
int v = searchvar(fs, n); /* look up at current level */
if (v >= 0) {
init_exp(var, expkind.VLOCAL, v);
if (base_==0)
markupval(fs, v); /* local will be used as an upval */
return expkind.VLOCAL;
}
else { /* not found at current level; try upper one */
if (singlevaraux(fs.prev, n, var, 0) == expkind.VGLOBAL)
return expkind.VGLOBAL;
var.u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */
var.k = expkind.VUPVAL; /* upvalue in this level */
return expkind.VUPVAL;
}
}
}
private static void singlevar (LexState ls, expdesc var) {
TString varname = str_checkname(ls);
FuncState fs = ls.fs;
if (singlevaraux(fs, varname, var, 1) == expkind.VGLOBAL)
var.u.s.info = luaK_stringK(fs, varname); /* info points to global name */
}
private static void adjust_assign (LexState ls, int nvars, int nexps, expdesc e) {
FuncState fs = ls.fs;
int extra = nvars - nexps;
if (hasmultret(e.k) != 0) {
extra++; /* includes call itself */
if (extra < 0) extra = 0;
luaK_setreturns(fs, e, extra); /* last exp. provides the difference */
if (extra > 1) luaK_reserveregs(fs, extra-1);
}
else {
if (e.k != expkind.VVOID) luaK_exp2nextreg(fs, e); /* close last expression */
if (extra > 0) {
int reg = fs.freereg;
luaK_reserveregs(fs, extra);
luaK_nil(fs, reg, extra);
}
}
}
private static void enterlevel (LexState ls) {
if (++ls.L.nCcalls > LUAI_MAXCCALLS)
luaX_lexerror(ls, "chunk has too many syntax levels", 0);
}
private static void leavelevel(LexState ls) { ls.L.nCcalls--; }
private static void enterblock (FuncState fs, BlockCnt bl, lu_byte isbreakable) {
bl.breaklist = NO_JUMP;
bl.isbreakable = isbreakable;
bl.nactvar = fs.nactvar;
bl.upval = 0;
bl.previous = fs.bl;
fs.bl = bl;
lua_assert(fs.freereg == fs.nactvar);
}
private static void leaveblock (FuncState fs) {
BlockCnt bl = fs.bl;
fs.bl = bl.previous;
removevars(fs.ls, bl.nactvar);
if (bl.upval != 0)
luaK_codeABC(fs, OpCode.OP_CLOSE, bl.nactvar, 0, 0);
/* a block either controls scope or breaks (never both) */
lua_assert((bl.isbreakable==0) || (bl.upval==0));
lua_assert(bl.nactvar == fs.nactvar);
fs.freereg = fs.nactvar; /* free registers */
luaK_patchtohere(fs, bl.breaklist);
}
private static void pushclosure (LexState ls, FuncState func, expdesc v) {
FuncState fs = ls.fs;
Proto f = fs.f;
int oldsize = f.sizep;
int i;
luaM_growvector(ls.L, ref f.p, fs.np, ref f.sizep,
MAXARG_Bx, "constant table overflow");
while (oldsize < f.sizep) f.p[oldsize++] = null;
f.p[fs.np++] = func.f;
luaC_objbarrier(ls.L, f, func.f);
init_exp(v, expkind.VRELOCABLE, luaK_codeABx(fs, OpCode.OP_CLOSURE, 0, fs.np - 1));
for (i=0; i<func.f.nups; i++) {
OpCode o = ((int)func.upvalues[i].k == (int)expkind.VLOCAL) ? OpCode.OP_MOVE : OpCode.OP_GETUPVAL;
luaK_codeABC(fs, o, 0, func.upvalues[i].info, 0);
}
}
private static void open_func (LexState ls, FuncState fs) {
lua_State L = ls.L;
Proto f = luaF_newproto(L);
fs.f = f;
fs.prev = ls.fs; /* linked list of funcstates */
fs.ls = ls;
fs.L = L;
ls.fs = fs;
fs.pc = 0;
fs.lasttarget = -1;
fs.jpc = NO_JUMP;
fs.freereg = 0;
fs.nk = 0;
fs.np = 0;
fs.nlocvars = 0;
fs.nactvar = 0;
fs.bl = null;
f.source = ls.source;
f.maxstacksize = 2; /* registers 0/1 are always valid */
fs.h = luaH_new(L, 0, 0);
/* anchor table of constants and prototype (to avoid being collected) */
sethvalue2s(L, L.top, fs.h);
incr_top(L);
setptvalue2s(L, L.top, f);
incr_top(L);
}
private static void close_func (LexState ls) {
lua_State L = ls.L;
FuncState fs = ls.fs;
Proto f = fs.f;
removevars(ls, 0);
luaK_ret(fs, 0, 0); /* final return */
luaM_reallocvector(L, ref f.code, f.sizecode, fs.pc/*, typeof(Instruction)*/);
f.sizecode = fs.pc;
luaM_reallocvector(L, ref f.lineinfo, f.sizelineinfo, fs.pc/*, typeof(int)*/);
f.sizelineinfo = fs.pc;
luaM_reallocvector(L, ref f.k, f.sizek, fs.nk/*, TValue*/);
f.sizek = fs.nk;
luaM_reallocvector(L, ref f.p, f.sizep, fs.np/*, Proto*/);
f.sizep = fs.np;
for (int i = 0; i < f.p.Length; i++)
{
f.p[i].protos = f.p;
f.p[i].index = i;
}
luaM_reallocvector(L, ref f.locvars, f.sizelocvars, fs.nlocvars/*, LocVar*/);
f.sizelocvars = fs.nlocvars;
luaM_reallocvector(L, ref f.upvalues, f.sizeupvalues, f.nups/*, TString*/);
f.sizeupvalues = f.nups;
lua_assert(luaG_checkcode(f));
lua_assert(fs.bl == null);
ls.fs = fs.prev;
L.top -= 2; /* remove table and prototype from the stack */
/* last token read was anchored in defunct function; must reanchor it */
if (fs!=null) anchor_token(ls);
}
public static Proto luaY_parser (lua_State L, ZIO z, Mbuffer buff, CharPtr name) {
LexState lexstate = new LexState();
FuncState funcstate = new FuncState();
lexstate.buff = buff;
luaX_setinput(L, lexstate, z, luaS_new(L, name));
open_func(lexstate, funcstate);
funcstate.f.is_vararg = VARARG_ISVARARG; /* main func. is always vararg */
luaX_next(lexstate); /* read first token */
System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
chunk(lexstate);
check(lexstate, (int)RESERVED.TK_EOS);
close_func(lexstate);
lua_assert(funcstate.prev == null);
lua_assert(funcstate.f.nups == 0);
lua_assert(lexstate.fs == null);
return funcstate.f;
}
/*============================================================*/
/* GRAMMAR RULES */
/*============================================================*/
private static void field (LexState ls, expdesc v) {
/* field . ['.' | ':'] NAME */
FuncState fs = ls.fs;
expdesc key = new expdesc();
luaK_exp2anyreg(fs, v);
luaX_next(ls); /* skip the dot or colon */
checkname(ls, key);
luaK_indexed(fs, v, key);
}
private static void yindex (LexState ls, expdesc v) {
/* index . '[' expr ']' */
luaX_next(ls); /* skip the '[' */
expr(ls, v);
luaK_exp2val(ls.fs, v);
checknext(ls, ']');
}
/*
** {======================================================================
** Rules for Constructors
** =======================================================================
*/
public class ConsControl {
public expdesc v = new expdesc(); /* last list item read */
public expdesc t; /* table descriptor */
public int nh; /* total number of `record' elements */
public int na; /* total number of array elements */
public int tostore; /* number of array elements pending to be stored */
};
private static void recfield (LexState ls, ConsControl cc) {
/* recfield . (NAME | `['exp1`]') = exp1 */
FuncState fs = ls.fs;
int reg = ls.fs.freereg;
expdesc key = new expdesc(), val = new expdesc();
int rkkey;
if (ls.t.token == (int)RESERVED.TK_NAME) {
luaY_checklimit(fs, cc.nh, MAX_INT, "items in a constructor");
checkname(ls, key);
}
else /* ls.t.token == '[' */
yindex(ls, key);
cc.nh++;
checknext(ls, '=');
rkkey = luaK_exp2RK(fs, key);
expr(ls, val);
luaK_codeABC(fs, OpCode.OP_SETTABLE, cc.t.u.s.info, rkkey, luaK_exp2RK(fs, val));
fs.freereg = reg; /* free registers */
}
private static void closelistfield (FuncState fs, ConsControl cc) {
if (cc.v.k == expkind.VVOID) return; /* there is no list item */
luaK_exp2nextreg(fs, cc.v);
cc.v.k = expkind.VVOID;
if (cc.tostore == LFIELDS_PER_FLUSH) {
luaK_setlist(fs, cc.t.u.s.info, cc.na, cc.tostore); /* flush */
cc.tostore = 0; /* no more items pending */
}
}
private static void lastlistfield (FuncState fs, ConsControl cc) {
if (cc.tostore == 0) return;
if (hasmultret(cc.v.k) != 0) {
luaK_setmultret(fs, cc.v);
luaK_setlist(fs, cc.t.u.s.info, cc.na, LUA_MULTRET);
cc.na--; /* do not count last expression (unknown number of elements) */
}
else {
if (cc.v.k != expkind.VVOID)
luaK_exp2nextreg(fs, cc.v);
luaK_setlist(fs, cc.t.u.s.info, cc.na, cc.tostore);
}
}
private static void listfield (LexState ls, ConsControl cc) {
expr(ls, cc.v);
luaY_checklimit(ls.fs, cc.na, MAX_INT, "items in a constructor");
cc.na++;
cc.tostore++;
}
private static void constructor (LexState ls, expdesc t) {
/* constructor . ?? */
FuncState fs = ls.fs;
int line = ls.linenumber;
int pc = luaK_codeABC(fs, OpCode.OP_NEWTABLE, 0, 0, 0);
ConsControl cc = new ConsControl();
cc.na = cc.nh = cc.tostore = 0;
cc.t = t;
init_exp(t, expkind.VRELOCABLE, pc);
init_exp(cc.v, expkind.VVOID, 0); /* no value (yet) */
luaK_exp2nextreg(ls.fs, t); /* fix it at stack top (for gc) */
checknext(ls, '{');
do {
lua_assert(cc.v.k == expkind.VVOID || cc.tostore > 0);
if (ls.t.token == '}') break;
closelistfield(fs, cc);
switch(ls.t.token) {
case (int)RESERVED.TK_NAME: { /* may be listfields or recfields */
luaX_lookahead(ls);
if (ls.lookahead.token != '=') /* expression? */
listfield(ls, cc);
else
recfield(ls, cc);
break;
}
case '[': { /* constructor_item . recfield */
recfield(ls, cc);
break;
}
default: { /* constructor_part . listfield */
listfield(ls, cc);
break;
}
}
} while ((testnext(ls, ',')!=0) || (testnext(ls, ';')!=0));
check_match(ls, '}', '{', line);
lastlistfield(fs, cc);
SETARG_B(new InstructionPtr(fs.f.code, pc), luaO_int2fb((uint)cc.na)); /* set initial array size */
SETARG_C(new InstructionPtr(fs.f.code, pc), luaO_int2fb((uint)cc.nh)); /* set initial table size */
}
/* }====================================================================== */
private static void parlist (LexState ls) {
/* parlist . [ param { `,' param } ] */
FuncState fs = ls.fs;
Proto f = fs.f;
int nparams = 0;
f.is_vararg = 0;
if (ls.t.token != ')') { /* is `parlist' not empty? */
do {
switch (ls.t.token) {
case (int)RESERVED.TK_NAME: { /* param . NAME */
new_localvar(ls, str_checkname(ls), nparams++);
break;
}
case (int)RESERVED.TK_DOTS: { /* param . `...' */
luaX_next(ls);
#if LUA_COMPAT_VARARG
/* use `arg' as default name */
new_localvarliteral(ls, "arg", nparams++);
f.is_vararg = VARARG_HASARG | VARARG_NEEDSARG;
#endif
f.is_vararg |= VARARG_ISVARARG;
break;
}
default: luaX_syntaxerror(ls, "<name> or " + LUA_QL("...") + " expected"); break;
}
} while ((f.is_vararg==0) && (testnext(ls, ',')!=0));
}
adjustlocalvars(ls, nparams);
f.numparams = cast_byte(fs.nactvar - (f.is_vararg & VARARG_HASARG));
luaK_reserveregs(fs, fs.nactvar); /* reserve register for parameters */
}
private static void body (LexState ls, expdesc e, int needself, int line) {
/* body . `(' parlist `)' chunk END */
FuncState new_fs = new FuncState();
open_func(ls, new_fs);
new_fs.f.linedefined = line;
checknext(ls, '(');
if (needself != 0) {
new_localvarliteral(ls, "self", 0);
adjustlocalvars(ls, 1);
}
parlist(ls);
checknext(ls, ')');
chunk(ls);
new_fs.f.lastlinedefined = ls.linenumber;
check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_FUNCTION, line);
close_func(ls);
pushclosure(ls, new_fs, e);
}
private static int explist1 (LexState ls, expdesc v) {
/* explist1 . expr { `,' expr } */
int n = 1; /* at least one expression */
expr(ls, v);
while (testnext(ls, ',') != 0) {
luaK_exp2nextreg(ls.fs, v);
expr(ls, v);
n++;
}
return n;
}
private static void funcargs (LexState ls, expdesc f) {
FuncState fs = ls.fs;
expdesc args = new expdesc();
int base_, nparams;
int line = ls.linenumber;
switch (ls.t.token) {
case '(': { /* funcargs . `(' [ explist1 ] `)' */
if (line != ls.lastline)
luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
luaX_next(ls);
if (ls.t.token == ')') /* arg list is empty? */
args.k = expkind.VVOID;
else {
explist1(ls, args);
luaK_setmultret(fs, args);
}
check_match(ls, ')', '(', line);
break;
}
case '{': { /* funcargs . constructor */
constructor(ls, args);
break;
}
case (int)RESERVED.TK_STRING: { /* funcargs . STRING */
codestring(ls, args, ls.t.seminfo.ts);
luaX_next(ls); /* must use `seminfo' before `next' */
break;
}
default: {
luaX_syntaxerror(ls, "function arguments expected");
return;
}
}
lua_assert(f.k == expkind.VNONRELOC);
base_ = f.u.s.info; /* base_ register for call */
if (hasmultret(args.k) != 0)
nparams = LUA_MULTRET; /* open call */
else {
if (args.k != expkind.VVOID)
luaK_exp2nextreg(fs, args); /* close last argument */
nparams = fs.freereg - (base_+1);
}
init_exp(f, expkind.VCALL, luaK_codeABC(fs, OpCode.OP_CALL, base_, nparams + 1, 2));
luaK_fixline(fs, line);
fs.freereg = base_+1; /* call remove function and arguments and leaves
(unless changed) one result */
}
/*
** {======================================================================
** Expression parsing
** =======================================================================
*/
private static void prefixexp (LexState ls, expdesc v) {
/* prefixexp . NAME | '(' expr ')' */
switch (ls.t.token) {
case '(': {
int line = ls.linenumber;
luaX_next(ls);
expr(ls, v);
check_match(ls, ')', '(', line);
luaK_dischargevars(ls.fs, v);
return;
}
case (int)RESERVED.TK_NAME: {
singlevar(ls, v);
return;
}
default: {
luaX_syntaxerror(ls, "unexpected symbol");
return;
}
}
}
private static void primaryexp (LexState ls, expdesc v) {
/* primaryexp .
prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
FuncState fs = ls.fs;
prefixexp(ls, v);
for (;;) {
switch (ls.t.token) {
case '.': { /* field */
field(ls, v);
break;
}
case '[': { /* `[' exp1 `]' */
expdesc key = new expdesc();
luaK_exp2anyreg(fs, v);
yindex(ls, key);
luaK_indexed(fs, v, key);
break;
}
case ':': { /* `:' NAME funcargs */
expdesc key = new expdesc();
luaX_next(ls);
checkname(ls, key);
luaK_self(fs, v, key);
funcargs(ls, v);
break;
}
case '(': case (int)RESERVED.TK_STRING: case '{': { /* funcargs */
luaK_exp2nextreg(fs, v);
funcargs(ls, v);
break;
}
default: return;
}
}
}
private static void simpleexp (LexState ls, expdesc v) {
/* simpleexp . NUMBER | STRING | NIL | true | false | ... |
constructor | FUNCTION body | primaryexp */
switch (ls.t.token) {
case (int)RESERVED.TK_NUMBER: {
init_exp(v, expkind.VKNUM, 0);
v.u.nval = ls.t.seminfo.r;
break;
}
case (int)RESERVED.TK_STRING: {
codestring(ls, v, ls.t.seminfo.ts);
break;
}
case (int)RESERVED.TK_NIL: {
init_exp(v, expkind.VNIL, 0);
break;
}
case (int)RESERVED.TK_TRUE: {
init_exp(v, expkind.VTRUE, 0);
break;
}
case (int)RESERVED.TK_FALSE: {
init_exp(v, expkind.VFALSE, 0);
break;
}
case (int)RESERVED.TK_DOTS: { /* vararg */
FuncState fs = ls.fs;
check_condition(ls, fs.f.is_vararg!=0,
"cannot use " + LUA_QL("...") + " outside a vararg function");
fs.f.is_vararg &= unchecked((lu_byte)(~VARARG_NEEDSARG)); /* don't need 'arg' */
init_exp(v, expkind.VVARARG, luaK_codeABC(fs, OpCode.OP_VARARG, 0, 1, 0));
break;
}
case '{': { /* constructor */
constructor(ls, v);
return;
}
case (int)RESERVED.TK_FUNCTION: {
luaX_next(ls);
body(ls, v, 0, ls.linenumber);
return;
}
default: {
primaryexp(ls, v);
return;
}
}
luaX_next(ls);
}
private static UnOpr getunopr (int op) {
switch (op) {
case (int)RESERVED.TK_NOT: return UnOpr.OPR_NOT;
case '-': return UnOpr.OPR_MINUS;
case '#': return UnOpr.OPR_LEN;
default: return UnOpr.OPR_NOUNOPR;
}
}
private static BinOpr getbinopr (int op) {
switch (op) {
case '+': return BinOpr.OPR_ADD;
case '-': return BinOpr.OPR_SUB;
case '*': return BinOpr.OPR_MUL;
case '/': return BinOpr.OPR_DIV;
case '%': return BinOpr.OPR_MOD;
case '^': return BinOpr.OPR_POW;
case (int)RESERVED.TK_CONCAT: return BinOpr.OPR_CONCAT;
case (int)RESERVED.TK_NE: return BinOpr.OPR_NE;
case (int)RESERVED.TK_EQ: return BinOpr.OPR_EQ;
case '<': return BinOpr.OPR_LT;
case (int)RESERVED.TK_LE: return BinOpr.OPR_LE;
case '>': return BinOpr.OPR_GT;
case (int)RESERVED.TK_GE: return BinOpr.OPR_GE;
case (int)RESERVED.TK_AND: return BinOpr.OPR_AND;
case (int)RESERVED.TK_OR: return BinOpr.OPR_OR;
default: return BinOpr.OPR_NOBINOPR;
}
}
private class priority_ {
public priority_(lu_byte left, lu_byte right)
{
this.left = left;
this.right = right;
}
public lu_byte left; /* left priority for each binary operator */
public lu_byte right; /* right priority */
}
private static priority_[] priority = { /* ORDER OPR */
new priority_(6, 6),
new priority_(6, 6),
new priority_(7, 7),
new priority_(7, 7),
new priority_(7, 7), /* `+' `-' `/' `%' */
new priority_(10, 9),
new priority_(5, 4), /* power and concat (right associative) */
new priority_(3, 3),
new priority_(3, 3), /* equality and inequality */
new priority_(3, 3),
new priority_(3, 3),
new priority_(3, 3),
new priority_(3, 3), /* order */
new priority_(2, 2),
new priority_(1, 1) /* logical (and/or) */
};
public const int UNARY_PRIORITY = 8; /* priority for unary operators */
/*
** subexpr . (simpleexp | unop subexpr) { binop subexpr }
** where `binop' is any binary operator with a priority higher than `limit'
*/
private static BinOpr subexpr (LexState ls, expdesc v, uint limit) {
BinOpr op = new BinOpr();
UnOpr uop = new UnOpr();
enterlevel(ls);
uop = getunopr(ls.t.token);
if (uop != UnOpr.OPR_NOUNOPR) {
luaX_next(ls);
subexpr(ls, v, UNARY_PRIORITY);
luaK_prefix(ls.fs, uop, v);
}
else simpleexp(ls, v);
/* expand while operators have priorities higher than `limit' */
op = getbinopr(ls.t.token);
while (op != BinOpr.OPR_NOBINOPR && priority[(int)op].left > limit)
{
expdesc v2 = new expdesc();
BinOpr nextop;
luaX_next(ls);
luaK_infix(ls.fs, op, v);
/* read sub-expression with higher priority */
nextop = subexpr(ls, v2, priority[(int)op].right);
luaK_posfix(ls.fs, op, v, v2);
op = nextop;
}
leavelevel(ls);
return op; /* return first untreated operator */
}
private static void expr (LexState ls, expdesc v) {
subexpr(ls, v, 0);
}
/* }==================================================================== */
/*
** {======================================================================
** Rules for Statements
** =======================================================================
*/
private static int block_follow (int token) {
switch (token) {
case (int)RESERVED.TK_ELSE: case (int)RESERVED.TK_ELSEIF: case (int)RESERVED.TK_END:
case (int)RESERVED.TK_UNTIL: case (int)RESERVED.TK_EOS:
return 1;
default: return 0;
}
}
private static void block (LexState ls) {
/* block . chunk */
FuncState fs = ls.fs;
BlockCnt bl = new BlockCnt();
enterblock(fs, bl, 0);
chunk(ls);
lua_assert(bl.breaklist == NO_JUMP);
leaveblock(fs);
}
/*
** structure to chain all variables in the left-hand side of an
** assignment
*/
public class LHS_assign {
public LHS_assign prev;
public expdesc v = new expdesc(); /* variable (global, local, upvalue, or indexed) */
};
/*
** check whether, in an assignment to a local variable, the local variable
** is needed in a previous assignment (to a table). If so, save original
** local value in a safe place and use this safe copy in the previous
** assignment.
*/
private static void check_conflict (LexState ls, LHS_assign lh, expdesc v) {
FuncState fs = ls.fs;
int extra = fs.freereg; /* eventual position to save local variable */
int conflict = 0;
for (; lh!=null; lh = lh.prev) {
if (lh.v.k == expkind.VINDEXED) {
if (lh.v.u.s.info == v.u.s.info) { /* conflict? */
conflict = 1;
lh.v.u.s.info = extra; /* previous assignment will use safe copy */
}
if (lh.v.u.s.aux == v.u.s.info) { /* conflict? */
conflict = 1;
lh.v.u.s.aux = extra; /* previous assignment will use safe copy */
}
}
}
if (conflict != 0) {
luaK_codeABC(fs, OpCode.OP_MOVE, fs.freereg, v.u.s.info, 0); /* make copy */
luaK_reserveregs(fs, 1);
}
}
private static void assignment (LexState ls, LHS_assign lh, int nvars) {
expdesc e = new expdesc();
check_condition(ls, expkind.VLOCAL <= lh.v.k && lh.v.k <= expkind.VINDEXED,
"syntax error");
if (testnext(ls, ',') != 0) { /* assignment . `,' primaryexp assignment */
LHS_assign nv = new LHS_assign();
nv.prev = lh;
primaryexp(ls, nv.v);
if (nv.v.k == expkind.VLOCAL)
check_conflict(ls, lh, nv.v);
luaY_checklimit(ls.fs, nvars, LUAI_MAXCCALLS - ls.L.nCcalls,
"variables in assignment");
assignment(ls, nv, nvars+1);
}
else { /* assignment . `=' explist1 */
int nexps;
checknext(ls, '=');
nexps = explist1(ls, e);
if (nexps != nvars) {
adjust_assign(ls, nvars, nexps, e);
if (nexps > nvars)
ls.fs.freereg -= nexps - nvars; /* remove extra values */
}
else {
luaK_setoneret(ls.fs, e); /* close last expression */
luaK_storevar(ls.fs, lh.v, e);
return; /* avoid default */
}
}
init_exp(e, expkind.VNONRELOC, ls.fs.freereg - 1); /* default assignment */
luaK_storevar(ls.fs, lh.v, e);
}
private static int cond (LexState ls) {
/* cond . exp */
expdesc v = new expdesc();
expr(ls, v); /* read condition */
if (v.k == expkind.VNIL) v.k = expkind.VFALSE; /* `falses' are all equal here */
luaK_goiftrue(ls.fs, v);
return v.f;
}
private static void breakstat (LexState ls) {
FuncState fs = ls.fs;
BlockCnt bl = fs.bl;
int upval = 0;
while ((bl!=null) && (bl.isbreakable==0)) {
upval |= bl.upval;
bl = bl.previous;
}
if (bl==null)
luaX_syntaxerror(ls, "no loop to break");
if (upval != 0)
luaK_codeABC(fs, OpCode.OP_CLOSE, bl.nactvar, 0, 0);
luaK_concat(fs, ref bl.breaklist, luaK_jump(fs));
}
private static void whilestat (LexState ls, int line) {
/* whilestat . WHILE cond DO block END */
FuncState fs = ls.fs;
int whileinit;
int condexit;
BlockCnt bl = new BlockCnt();
luaX_next(ls); /* skip WHILE */
whileinit = luaK_getlabel(fs);
condexit = cond(ls);
enterblock(fs, bl, 1);
checknext(ls, (int)RESERVED.TK_DO);
block(ls);
luaK_patchlist(fs, luaK_jump(fs), whileinit);
check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_WHILE, line);
leaveblock(fs);
luaK_patchtohere(fs, condexit); /* false conditions finish the loop */
}
private static void repeatstat (LexState ls, int line) {
/* repeatstat . REPEAT block UNTIL cond */
int condexit;
FuncState fs = ls.fs;
int repeat_init = luaK_getlabel(fs);
BlockCnt bl1 = new BlockCnt(), bl2 = new BlockCnt();
enterblock(fs, bl1, 1); /* loop block */
enterblock(fs, bl2, 0); /* scope block */
luaX_next(ls); /* skip REPEAT */
chunk(ls);
check_match(ls, (int)RESERVED.TK_UNTIL, (int)RESERVED.TK_REPEAT, line);
condexit = cond(ls); /* read condition (inside scope block) */
if (bl2.upval==0) { /* no upvalues? */
leaveblock(fs); /* finish scope */
luaK_patchlist(ls.fs, condexit, repeat_init); /* close the loop */
}
else { /* complete semantics when there are upvalues */
breakstat(ls); /* if condition then break */
luaK_patchtohere(ls.fs, condexit); /* else... */
leaveblock(fs); /* finish scope... */
luaK_patchlist(ls.fs, luaK_jump(fs), repeat_init); /* and repeat */
}
leaveblock(fs); /* finish loop */
}
private static int exp1 (LexState ls) {
expdesc e = new expdesc();
int k;
expr(ls, e);
k = (int)e.k;
luaK_exp2nextreg(ls.fs, e);
return k;
}
private static void forbody (LexState ls, int base_, int line, int nvars, int isnum) {
/* forbody . DO block */
BlockCnt bl = new BlockCnt();
FuncState fs = ls.fs;
int prep, endfor;
adjustlocalvars(ls, 3); /* control variables */
checknext(ls, (int)RESERVED.TK_DO);
prep = (isnum != 0) ? luaK_codeAsBx(fs, OpCode.OP_FORPREP, base_, NO_JUMP) : luaK_jump(fs);
enterblock(fs, bl, 0); /* scope for declared variables */
adjustlocalvars(ls, nvars);
luaK_reserveregs(fs, nvars);
block(ls);
leaveblock(fs); /* end of scope for declared variables */
luaK_patchtohere(fs, prep);
endfor = (isnum!=0) ? luaK_codeAsBx(fs, OpCode.OP_FORLOOP, base_, NO_JUMP) :
luaK_codeABC(fs, OpCode.OP_TFORLOOP, base_, 0, nvars);
luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */
luaK_patchlist(fs, ((isnum!=0) ? endfor : luaK_jump(fs)), prep + 1);
}
private static void fornum (LexState ls, TString varname, int line) {
/* fornum . NAME = exp1,exp1[,exp1] forbody */
FuncState fs = ls.fs;
int base_ = fs.freereg;
new_localvarliteral(ls, "(for index)", 0);
new_localvarliteral(ls, "(for limit)", 1);
new_localvarliteral(ls, "(for step)", 2);
new_localvar(ls, varname, 3);
checknext(ls, '=');
exp1(ls); /* initial value */
checknext(ls, ',');
exp1(ls); /* limit */
if (testnext(ls, ',') != 0)
exp1(ls); /* optional step */
else { /* default step = 1 */
luaK_codeABx(fs, OpCode.OP_LOADK, fs.freereg, luaK_numberK(fs, 1));
luaK_reserveregs(fs, 1);
}
forbody(ls, base_, line, 1, 1);
}
private static void forlist (LexState ls, TString indexname) {
/* forlist . NAME {,NAME} IN explist1 forbody */
FuncState fs = ls.fs;
expdesc e = new expdesc();
int nvars = 0;
int line;
int base_ = fs.freereg;
/* create control variables */
new_localvarliteral(ls, "(for generator)", nvars++);
new_localvarliteral(ls, "(for state)", nvars++);
new_localvarliteral(ls, "(for control)", nvars++);
/* create declared variables */
new_localvar(ls, indexname, nvars++);
while (testnext(ls, ',') != 0)
new_localvar(ls, str_checkname(ls), nvars++);
checknext(ls, (int)RESERVED.TK_IN);
line = ls.linenumber;
adjust_assign(ls, 3, explist1(ls, e), e);
luaK_checkstack(fs, 3); /* extra space to call generator */
forbody(ls, base_, line, nvars - 3, 0);
}
private static void forstat (LexState ls, int line) {
/* forstat . FOR (fornum | forlist) END */
FuncState fs = ls.fs;
TString varname;
BlockCnt bl = new BlockCnt();
enterblock(fs, bl, 1); /* scope for loop and control variables */
luaX_next(ls); /* skip `for' */
varname = str_checkname(ls); /* first variable name */
switch (ls.t.token) {
case '=': fornum(ls, varname, line); break;
case ',':
case (int)RESERVED.TK_IN:
forlist(ls, varname);
break;
default: luaX_syntaxerror(ls, LUA_QL("=") + " or " + LUA_QL("in") + " expected"); break;
}
check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_FOR, line);
leaveblock(fs); /* loop scope (`break' jumps to this point) */
}
private static int test_then_block (LexState ls) {
/* test_then_block . [IF | ELSEIF] cond THEN block */
int condexit;
luaX_next(ls); /* skip IF or ELSEIF */
condexit = cond(ls);
checknext(ls, (int)RESERVED.TK_THEN);
block(ls); /* `then' part */
return condexit;
}
private static void ifstat (LexState ls, int line) {
/* ifstat . IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
FuncState fs = ls.fs;
int flist;
int escapelist = NO_JUMP;
flist = test_then_block(ls); /* IF cond THEN block */
while (ls.t.token == (int)RESERVED.TK_ELSEIF) {
luaK_concat(fs, ref escapelist, luaK_jump(fs));
luaK_patchtohere(fs, flist);
flist = test_then_block(ls); /* ELSEIF cond THEN block */
}
if (ls.t.token == (int)RESERVED.TK_ELSE) {
luaK_concat(fs, ref escapelist, luaK_jump(fs));
luaK_patchtohere(fs, flist);
luaX_next(ls); /* skip ELSE (after patch, for correct line info) */
block(ls); /* `else' part */
}
else
luaK_concat(fs, ref escapelist, flist);
luaK_patchtohere(fs, escapelist);
check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_IF, line);
}
private static void localfunc (LexState ls) {
expdesc v = new expdesc(), b = new expdesc();
FuncState fs = ls.fs;
new_localvar(ls, str_checkname(ls), 0);
init_exp(v, expkind.VLOCAL, fs.freereg);
luaK_reserveregs(fs, 1);
adjustlocalvars(ls, 1);
body(ls, b, 0, ls.linenumber);
luaK_storevar(fs, v, b);
/* debug information will only see the variable after this point! */
getlocvar(fs, fs.nactvar - 1).startpc = fs.pc;
}
private static void localstat (LexState ls) {
/* stat . LOCAL NAME {`,' NAME} [`=' explist1] */
int nvars = 0;
int nexps;
expdesc e = new expdesc();
do {
new_localvar(ls, str_checkname(ls), nvars++);
} while (testnext(ls, ',') != 0);
if (testnext(ls, '=') != 0)
nexps = explist1(ls, e);
else {
e.k = expkind.VVOID;
nexps = 0;
}
adjust_assign(ls, nvars, nexps, e);
adjustlocalvars(ls, nvars);
}
private static int funcname (LexState ls, expdesc v) {
/* funcname . NAME {field} [`:' NAME] */
int needself = 0;
singlevar(ls, v);
while (ls.t.token == '.')
field(ls, v);
if (ls.t.token == ':') {
needself = 1;
field(ls, v);
}
return needself;
}
private static void funcstat (LexState ls, int line) {
/* funcstat . FUNCTION funcname body */
int needself;
expdesc v = new expdesc(), b = new expdesc();
luaX_next(ls); /* skip FUNCTION */
needself = funcname(ls, v);
body(ls, b, needself, line);
luaK_storevar(ls.fs, v, b);
luaK_fixline(ls.fs, line); /* definition `happens' in the first line */
}
private static void exprstat (LexState ls) {
/* stat . func | assignment */
FuncState fs = ls.fs;
LHS_assign v = new LHS_assign();
primaryexp(ls, v.v);
if (v.v.k == expkind.VCALL) /* stat . func */
SETARG_C(getcode(fs, v.v), 1); /* call statement uses no results */
else { /* stat . assignment */
v.prev = null;
assignment(ls, v, 1);
}
}
private static void retstat (LexState ls) {
/* stat . RETURN explist */
FuncState fs = ls.fs;
expdesc e = new expdesc();
int first, nret; /* registers with returned values */
luaX_next(ls); /* skip RETURN */
if ((block_follow(ls.t.token)!=0) || ls.t.token == ';')
first = nret = 0; /* return no values */
else {
nret = explist1(ls, e); /* optional return values */
if (hasmultret(e.k) != 0) {
luaK_setmultret(fs, e);
if (e.k == expkind.VCALL && nret == 1) { /* tail call? */
SET_OPCODE(getcode(fs,e), OpCode.OP_TAILCALL);
lua_assert(GETARG_A(getcode(fs,e)) == fs.nactvar);
}
first = fs.nactvar;
nret = LUA_MULTRET; /* return all values */
}
else {
if (nret == 1) /* only one single value? */
first = luaK_exp2anyreg(fs, e);
else {
luaK_exp2nextreg(fs, e); /* values must go to the `stack' */
first = fs.nactvar; /* return all `active' values */
lua_assert(nret == fs.freereg - first);
}
}
}
luaK_ret(fs, first, nret);
}
private static int statement (LexState ls) {
int line = ls.linenumber; /* may be needed for error messages */
switch (ls.t.token) {
case (int)RESERVED.TK_IF: { /* stat . ifstat */
ifstat(ls, line);
return 0;
}
case (int)RESERVED.TK_WHILE: { /* stat . whilestat */
whilestat(ls, line);
return 0;
}
case (int)RESERVED.TK_DO: { /* stat . DO block END */
luaX_next(ls); /* skip DO */
block(ls);
check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_DO, line);
return 0;
}
case (int)RESERVED.TK_FOR: { /* stat . forstat */
forstat(ls, line);
return 0;
}
case (int)RESERVED.TK_REPEAT: { /* stat . repeatstat */
repeatstat(ls, line);
return 0;
}
case (int)RESERVED.TK_FUNCTION: {
funcstat(ls, line); /* stat . funcstat */
return 0;
}
case (int)RESERVED.TK_LOCAL: { /* stat . localstat */
luaX_next(ls); /* skip LOCAL */
if (testnext(ls, (int)RESERVED.TK_FUNCTION) != 0) /* local function? */
localfunc(ls);
else
localstat(ls);
return 0;
}
case (int)RESERVED.TK_RETURN: { /* stat . retstat */
retstat(ls);
return 1; /* must be last statement */
}
case (int)RESERVED.TK_BREAK: { /* stat . breakstat */
luaX_next(ls); /* skip BREAK */
breakstat(ls);
return 1; /* must be last statement */
}
default: {
exprstat(ls);
return 0; /* to avoid warnings */
}
}
}
private static void chunk (LexState ls) {
/* chunk . { stat [`;'] } */
int islast = 0;
enterlevel(ls);
while ((islast==0) && (block_follow(ls.t.token)==0)) {
islast = statement(ls);
testnext(ls, ';');
lua_assert(ls.fs.f.maxstacksize >= ls.fs.freereg &&
ls.fs.freereg >= ls.fs.nactvar);
ls.fs.freereg = ls.fs.nactvar; /* free registers */
}
leavelevel(ls);
}
/* }====================================================================== */
}
}
/*
** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace KopiLua
{
using lu_byte = System.Byte;
using lu_int32 = System.Int32;
using lu_mem = System.UInt32;
using TValue = Lua.lua_TValue;
using StkId = Lua.lua_TValue;
using ptrdiff_t = System.Int32;
using Instruction = System.UInt32;
public partial class Lua
{
/* table of globals */
public static TValue gt(lua_State L) {return L.l_gt;}
/* registry */
public static TValue registry(lua_State L) {return G(L).l_registry;}
/* extra stack space to handle TM calls and some other extras */
public const int EXTRA_STACK = 5;
public const int BASIC_CI_SIZE = 8;
public const int BASIC_STACK_SIZE = (2*LUA_MINSTACK);
public class stringtable {
public GCObject[] hash;
public lu_int32 nuse; /* number of elements */
public int size;
};
/*
** informations about a call
*/
public class CallInfo : ArrayElement
{
private CallInfo[] values = null;
private int index = -1;
public void set_index(int index)
{
this.index = index;
}
public void set_array(object array)
{
this.values = (CallInfo[])array;
Debug.Assert(this.values != null);
}
public CallInfo this[int offset]
{
get { return values[index+offset]; }
}
public static CallInfo operator +(CallInfo value, int offset)
{
return value.values[value.index + offset];
}
public static CallInfo operator -(CallInfo value, int offset)
{
return value.values[value.index - offset];
}
public static int operator -(CallInfo ci, CallInfo[] values)
{
Debug.Assert(ci.values == values);
return ci.index;
}
public static int operator -(CallInfo ci1, CallInfo ci2)
{
Debug.Assert(ci1.values == ci2.values);
return ci1.index - ci2.index;
}
public static bool operator <(CallInfo ci1, CallInfo ci2)
{
Debug.Assert(ci1.values == ci2.values);
return ci1.index < ci2.index;
}
public static bool operator <=(CallInfo ci1, CallInfo ci2)
{
Debug.Assert(ci1.values == ci2.values);
return ci1.index <= ci2.index;
}
public static bool operator >(CallInfo ci1, CallInfo ci2)
{
Debug.Assert(ci1.values == ci2.values);
return ci1.index > ci2.index;
}
public static bool operator >=(CallInfo ci1, CallInfo ci2)
{
Debug.Assert(ci1.values == ci2.values);
return ci1.index >= ci2.index;
}
public static CallInfo inc(ref CallInfo value)
{
value = value[1];
return value[-1];
}
public static CallInfo dec(ref CallInfo value)
{
value = value[-1];
return value[1];
}
public StkId base_; /* base for this function */
public StkId func; /* function index in the stack */
public StkId top; /* top for this function */
public InstructionPtr savedpc;
public int nresults; /* expected number of results from this function */
public int tailcalls; /* number of tail calls lost under this entry */
};
public static Closure curr_func(lua_State L) { return (clvalue(L.ci.func)); }
public static Closure ci_func(CallInfo ci) { return (clvalue(ci.func)); }
public static bool f_isLua(CallInfo ci) {return ci_func(ci).c.isC==0;}
public static bool isLua(CallInfo ci) {return (ttisfunction((ci).func) && f_isLua(ci));}
/*
** `global state', shared by all threads of this state
*/
public class global_State {
public stringtable strt = new stringtable(); /* hash table for strings */
public lua_Alloc frealloc; /* function to reallocate memory */
public object ud; /* auxiliary data to `frealloc' */
public lu_byte currentwhite;
public lu_byte gcstate; /* state of garbage collector */
public int sweepstrgc; /* position of sweep in `strt' */
public GCObject rootgc; /* list of all collectable objects */
public GCObjectRef sweepgc; /* position of sweep in `rootgc' */
public GCObject gray; /* list of gray objects */
public GCObject grayagain; /* list of objects to be traversed atomically */
public GCObject weak; /* list of weak tables (to be cleared) */
public GCObject tmudata; /* last element of list of userdata to be GC */
public Mbuffer buff = new Mbuffer(); /* temporary buffer for string concatentation */
public lu_mem GCthreshold;
public lu_mem totalbytes; /* number of bytes currently allocated */
public lu_mem estimate; /* an estimate of number of bytes actually in use */
public lu_mem gcdept; /* how much GC is `behind schedule' */
public int gcpause; /* size of pause between successive GCs */
public int gcstepmul; /* GC `granularity' */
public lua_CFunction panic; /* to be called in unprotected errors */
public TValue l_registry = new TValue();
public lua_State mainthread;
public UpVal uvhead = new UpVal(); /* head of double-linked list of all open upvalues */
public Table[] mt = new Table[NUM_TAGS]; /* metatables for basic types */
public TString[] tmname = new TString[(int)TMS.TM_N]; /* array with tag-method names */
};
/*
** `per thread' state
*/
public class lua_State : GCObject {
public lu_byte status;
public StkId top; /* first free slot in the stack */
public StkId base_; /* base of current function */
public global_State l_G;
public CallInfo ci; /* call info for current function */
public InstructionPtr savedpc = new InstructionPtr(); /* `savedpc' of current function */
public StkId stack_last; /* last free slot in the stack */
public StkId[] stack; /* stack base */
public CallInfo end_ci; /* points after end of ci array*/
public CallInfo[] base_ci; /* array of CallInfo's */
public int stacksize;
public int size_ci; /* size of array `base_ci' */
public ushort nCcalls; /* number of nested C calls */
public ushort baseCcalls; /* nested C calls when resuming coroutine */
public lu_byte hookmask;
public lu_byte allowhook;
public int basehookcount;
public int hookcount;
public lua_Hook hook;
public TValue l_gt = new TValue(); /* table of globals */
public TValue env = new TValue(); /* temporary place for environments */
public GCObject openupval; /* list of open upvalues in this stack */
public GCObject gclist;
public lua_longjmp errorJmp; /* current error recover point */
public ptrdiff_t errfunc; /* current error handling function (stack index) */
};
public static global_State G(lua_State L) {return L.l_G;}
public static void G_set(lua_State L, global_State s) { L.l_G = s; }
/*
** Union of all collectable objects (not a union anymore in the C# port)
*/
public class GCObject : GCheader, ArrayElement
{
public void set_index(int index)
{
//this.index = index;
}
public void set_array(object array)
{
//this.values = (GCObject[])array;
//Debug.Assert(this.values != null);
}
public GCheader gch {get{return (GCheader)this;}}
public TString ts {get{return (TString)this;}}
public Udata u {get{return (Udata)this;}}
public Closure cl {get{return (Closure)this;}}
public Table h {get{return (Table)this;}}
public Proto p {get{return (Proto)this;}}
public UpVal uv {get{return (UpVal)this;}}
public lua_State th {get{return (lua_State)this;}}
};
/* this interface and is used for implementing GCObject references,
it's used to emulate the behaviour of a C-style GCObject **
*/
public interface GCObjectRef
{
void set(GCObject value);
GCObject get();
}
public class ArrayRef : GCObjectRef, ArrayElement
{
public ArrayRef()
{
this.array_elements = null;
this.array_index = 0;
this.vals = null;
this.index = 0;
}
public ArrayRef(GCObject[] array_elements, int array_index)
{
this.array_elements = array_elements;
this.array_index = array_index;
this.vals = null;
this.index = 0;
}
public void set(GCObject value) { array_elements[array_index] = value; }
public GCObject get() { return array_elements[array_index]; }
public void set_index(int index)
{
this.index = index;
}
public void set_array(object vals)
{
// don't actually need this
this.vals = (ArrayRef[])vals;
Debug.Assert(this.vals != null);
}
// ArrayRef is used to reference GCObject objects in an array, the next two members
// point to that array and the index of the GCObject element we are referencing
GCObject[] array_elements;
int array_index;
// ArrayRef is itself stored in an array and derived from ArrayElement, the next
// two members refer to itself i.e. the array and index of it's own instance.
ArrayRef[] vals;
int index;
}
public class OpenValRef : GCObjectRef
{
public OpenValRef(lua_State L) { this.L = L; }
public void set(GCObject value) { this.L.openupval = value; }
public GCObject get() { return this.L.openupval; }
lua_State L;
}
public class RootGCRef : GCObjectRef
{
public RootGCRef(global_State g) { this.g = g; }
public void set(GCObject value) { this.g.rootgc = value; }
public GCObject get() { return this.g.rootgc; }
global_State g;
}
public class NextRef : GCObjectRef
{
public NextRef(GCheader header) { this.header = header; }
public void set(GCObject value) { this.header.next = value; }
public GCObject get() { return this.header.next; }
GCheader header;
}
/* macros to convert a GCObject into a specific value */
public static TString rawgco2ts(GCObject o) { return (TString)check_exp(o.gch.tt == LUA_TSTRING, o.ts); }
public static TString gco2ts(GCObject o) { return (TString)(rawgco2ts(o).tsv); }
public static Udata rawgco2u(GCObject o) { return (Udata)check_exp(o.gch.tt == LUA_TUSERDATA, o.u); }
public static Udata gco2u(GCObject o) { return (Udata)(rawgco2u(o).uv); }
public static Closure gco2cl(GCObject o) { return (Closure)check_exp(o.gch.tt == LUA_TFUNCTION, o.cl); }
public static Table gco2h(GCObject o) { return (Table)check_exp(o.gch.tt == LUA_TTABLE, o.h); }
public static Proto gco2p(GCObject o) { return (Proto)check_exp(o.gch.tt == LUA_TPROTO, o.p); }
public static UpVal gco2uv(GCObject o) { return (UpVal)check_exp(o.gch.tt == LUA_TUPVAL, o.uv); }
public static UpVal ngcotouv(GCObject o) {return (UpVal)check_exp((o == null) || (o.gch.tt == LUA_TUPVAL), o.uv); }
public static lua_State gco2th(GCObject o) { return (lua_State)check_exp(o.gch.tt == LUA_TTHREAD, o.th); }
/* macro to convert any Lua object into a GCObject */
public static GCObject obj2gco(object v) {return (GCObject)v;}
public static int state_size(object x) { return Marshal.SizeOf(x) + LUAI_EXTRASPACE; }
/*
public static lu_byte fromstate(object l)
{
return (lu_byte)(l - LUAI_EXTRASPACE);
}
*/
public static lua_State tostate(object l)
{
Debug.Assert(LUAI_EXTRASPACE == 0, "LUAI_EXTRASPACE not supported");
return (lua_State)l;
}
/*
** Main thread combines a thread state and the global state
*/
public class LG : lua_State {
public lua_State l {get {return this;}}
public global_State g = new global_State();
};
private static void stack_init (lua_State L1, lua_State L) {
/* initialize CallInfo array */
L1.base_ci = luaM_newvector<CallInfo>(L, BASIC_CI_SIZE);
L1.ci = L1.base_ci[0];
L1.size_ci = BASIC_CI_SIZE;
L1.end_ci = L1.base_ci[L1.size_ci - 1];
/* initialize stack array */
L1.stack = luaM_newvector<TValue>(L, BASIC_STACK_SIZE + EXTRA_STACK);
L1.stacksize = BASIC_STACK_SIZE + EXTRA_STACK;
L1.top = L1.stack[0];
L1.stack_last = L1.stack[L1.stacksize - EXTRA_STACK - 1];
/* initialize first ci */
L1.ci.func = L1.top;
setnilvalue(StkId.inc(ref L1.top)); /* `function' entry for this `ci' */
L1.base_ = L1.ci.base_ = L1.top;
L1.ci.top = L1.top + LUA_MINSTACK;
}
private static void freestack (lua_State L, lua_State L1) {
luaM_freearray(L, L1.base_ci);
luaM_freearray(L, L1.stack);
}
/*
** open parts that may cause memory-allocation errors
*/
private static void f_luaopen (lua_State L, object ud) {
global_State g = G(L);
//UNUSED(ud);
stack_init(L, L); /* init stack */
sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */
sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
luaT_init(L);
luaX_init(L);
luaS_fix(luaS_newliteral(L, MEMERRMSG));
g.GCthreshold = 4*g.totalbytes;
}
private static void preinit_state (lua_State L, global_State g) {
G_set(L, g);
L.stack = null;
L.stacksize = 0;
L.errorJmp = null;
L.hook = null;
L.hookmask = 0;
L.basehookcount = 0;
L.allowhook = 1;
resethookcount(L);
L.openupval = null;
L.size_ci = 0;
L.nCcalls = L.baseCcalls = 0;
L.status = 0;
L.base_ci = null;
L.ci = null;
L.savedpc = new InstructionPtr();
L.errfunc = 0;
setnilvalue(gt(L));
}
private static void close_state (lua_State L) {
global_State g = G(L);
luaF_close(L, L.stack[0]); /* close all upvalues for this thread */
luaC_freeall(L); /* collect all objects */
lua_assert(g.rootgc == obj2gco(L));
lua_assert(g.strt.nuse == 0);
luaM_freearray(L, G(L).strt.hash);
luaZ_freebuffer(L, g.buff);
freestack(L, L);
lua_assert(g.totalbytes == GetUnmanagedSize(typeof(LG)));
//g.frealloc(g.ud, fromstate(L), (uint)state_size(typeof(LG)), 0);
}
private static lua_State luaE_newthread (lua_State L) {
//lua_State L1 = tostate(luaM_malloc(L, state_size(typeof(lua_State))));
lua_State L1 = luaM_new<lua_State>(L);
luaC_link(L, obj2gco(L1), LUA_TTHREAD);
preinit_state(L1, G(L));
stack_init(L1, L); /* init stack */
setobj2n(L, gt(L1), gt(L)); /* share table of globals */
L1.hookmask = L.hookmask;
L1.basehookcount = L.basehookcount;
L1.hook = L.hook;
resethookcount(L1);
lua_assert(iswhite(obj2gco(L1)));
return L1;
}
private static void luaE_freethread (lua_State L, lua_State L1) {
luaF_close(L1, L1.stack[0]); /* close all upvalues for this thread */
lua_assert(L1.openupval == null);
luai_userstatefree(L1);
freestack(L, L1);
//luaM_freemem(L, fromstate(L1));
}
public static lua_State lua_newstate (lua_Alloc f, object ud) {
int i;
lua_State L;
global_State g;
//object l = f(ud, null, 0, (uint)state_size(typeof(LG)));
object l = f(typeof(LG));
if (l == null) return null;
L = tostate(l);
g = (L as LG).g;
L.next = null;
L.tt = LUA_TTHREAD;
g.currentwhite = (lu_byte)bit2mask(WHITE0BIT, FIXEDBIT);
L.marked = luaC_white(g);
lu_byte marked = L.marked; // can't pass properties in as ref
set2bits(ref marked, FIXEDBIT, SFIXEDBIT);
L.marked = marked;
preinit_state(L, g);
g.frealloc = f;
g.ud = ud;
g.mainthread = L;
g.uvhead.u.l.prev = g.uvhead;
g.uvhead.u.l.next = g.uvhead;
g.GCthreshold = 0; /* mark it as unfinished state */
g.strt.size = 0;
g.strt.nuse = 0;
g.strt.hash = null;
setnilvalue(registry(L));
luaZ_initbuffer(L, g.buff);
g.panic = null;
g.gcstate = GCSpause;
g.rootgc = obj2gco(L);
g.sweepstrgc = 0;
g.sweepgc = new RootGCRef(g);
g.gray = null;
g.grayagain = null;
g.weak = null;
g.tmudata = null;
g.totalbytes = (uint)GetUnmanagedSize(typeof(LG));
g.gcpause = LUAI_GCPAUSE;
g.gcstepmul = LUAI_GCMUL;
g.gcdept = 0;
for (i=0; i<NUM_TAGS; i++) g.mt[i] = null;
if (luaD_rawrunprotected(L, f_luaopen, null) != 0) {
/* memory allocation error: free partial state */
close_state(L);
L = null;
}
else
luai_userstateopen(L);
return L;
}
private static void callallgcTM (lua_State L, object ud) {
//UNUSED(ud);
luaC_callGCTM(L); /* call GC metamethods for all udata */
}
public static void lua_close (lua_State L) {
L = G(L).mainthread; /* only the main thread can be closed */
lua_lock(L);
luaF_close(L, L.stack[0]); /* close all upvalues for this thread */
luaC_separateudata(L, 1); /* separate udata that have GC metamethods */
L.errfunc = 0; /* no error function during GC metamethods */
do { /* repeat until no more errors */
L.ci = L.base_ci[0];
L.base_ = L.top = L.ci.base_;
L.nCcalls = L.baseCcalls = 0;
} while (luaD_rawrunprotected(L, callallgcTM, null) != 0);
lua_assert(G(L).tmudata == null);
luai_userstateclose(L);
close_state(L);
}
}
}
/*
** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace KopiLua
{
using lu_byte = System.Byte;
public partial class Lua
{
public static int sizestring(TString s) {return ((int)s.len + 1) * GetUnmanagedSize(typeof(char)); }
public static int sizeudata(Udata u) { return (int)u.len; }
public static TString luaS_new(lua_State L, CharPtr s) { return luaS_newlstr(L, s, (uint)strlen(s)); }
public static TString luaS_newliteral(lua_State L, CharPtr s) { return luaS_newlstr(L, s, (uint)strlen(s)); }
public static void luaS_fix(TString s)
{
lu_byte marked = s.tsv.marked; // can't pass properties in as ref
l_setbit(ref marked, FIXEDBIT);
s.tsv.marked = marked;
}
public static void luaS_resize (lua_State L, int newsize) {
GCObject[] newhash;
stringtable tb;
int i;
if (G(L).gcstate == GCSsweepstring)
return; /* cannot resize during GC traverse */
newhash = new GCObject[newsize];
AddTotalBytes(L, newsize * GetUnmanagedSize(typeof(GCObjectRef)));
tb = G(L).strt;
for (i=0; i<newsize; i++) newhash[i] = null;
/* rehash */
for (i=0; i<tb.size; i++) {
GCObject p = tb.hash[i];
while (p != null) { /* for each node in the list */
GCObject next = p.gch.next; /* save next */
uint h = gco2ts(p).hash;
int h1 = (int)lmod(h, newsize); /* new position */
lua_assert((int)(h%newsize) == lmod(h, newsize));
p.gch.next = newhash[h1]; /* chain it */
newhash[h1] = p;
p = next;
}
}
//luaM_freearray(L, tb.hash);
if (tb.hash != null)
SubtractTotalBytes(L, tb.hash.Length * GetUnmanagedSize(typeof(GCObjectRef)));
tb.size = newsize;
tb.hash = newhash;
}
public static TString newlstr (lua_State L, CharPtr str, uint l,
uint h) {
TString ts;
stringtable tb;
if (l+1 > MAX_SIZET /GetUnmanagedSize(typeof(char)))
luaM_toobig(L);
ts = new TString(new char[l+1]);
AddTotalBytes(L, (int)(l + 1) * GetUnmanagedSize(typeof(char)) + GetUnmanagedSize(typeof(TString)));
ts.tsv.len = l;
ts.tsv.hash = h;
ts.tsv.marked = luaC_white(G(L));
ts.tsv.tt = LUA_TSTRING;
ts.tsv.reserved = 0;
//memcpy(ts+1, str, l*GetUnmanagedSize(typeof(char)));
memcpy(ts.str.chars, str.chars, str.index, (int)l);
ts.str[l] = '\0'; /* ending 0 */
tb = G(L).strt;
h = (uint)lmod(h, tb.size);
ts.tsv.next = tb.hash[h]; /* chain new entry */
tb.hash[h] = obj2gco(ts);
tb.nuse++;
if ((tb.nuse > (int)tb.size) && (tb.size <= MAX_INT/2))
luaS_resize(L, tb.size*2); /* too crowded */
return ts;
}
public static TString luaS_newlstr (lua_State L, CharPtr str, uint l) {
GCObject o;
uint h = (uint)l; /* seed */
uint step = (l>>5)+1; /* if string is too long, don't hash all its chars */
uint l1;
for (l1=l; l1>=step; l1-=step) /* compute hash */
h = h ^ ((h<<5)+(h>>2)+(byte)str[l1-1]);
for (o = G(L).strt.hash[lmod(h, G(L).strt.size)];
o != null;
o = o.gch.next) {
TString ts = rawgco2ts(o);
if (ts.tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) {
/* string may be dead */
if (isdead(G(L), o)) changewhite(o);
return ts;
}
}
//return newlstr(L, str, l, h); /* not found */
TString res = newlstr(L, str, l, h);
Console.WriteLine(res);
return res;
}
public static Udata luaS_newudata(lua_State L, uint s, Table e)
{
Udata u = new Udata();
u.uv.marked = luaC_white(G(L)); /* is not finalized */
u.uv.tt = LUA_TUSERDATA;
u.uv.len = s;
u.uv.metatable = null;
u.uv.env = e;
u.user_data = new byte[s];
/* chain it on udata list (after main thread) */
u.uv.next = G(L).mainthread.next;
G(L).mainthread.next = obj2gco(u);
return u;
}
internal static Udata luaS_newudata(lua_State L, Type t, Table e)
{
Udata u = new Udata();
u.uv.marked = luaC_white(G(L)); /* is not finalized */
u.uv.tt = LUA_TUSERDATA;
u.uv.len = 0;
u.uv.metatable = null;
u.uv.env = e;
u.user_data = luaM_realloc_(L, t);
AddTotalBytes(L, GetUnmanagedSize(typeof(Udata)));
/* chain it on udata list (after main thread) */
u.uv.next = G(L).mainthread.next;
G(L).mainthread.next = obj2gco(u);
return u;
}
}
}
/*
** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace KopiLua
{
using ptrdiff_t = System.Int32;
using lua_Integer = System.Int32;
using LUA_INTFRM_T = System.Int64;
using UNSIGNED_LUA_INTFRM_T = System.UInt64;
public partial class Lua
{
private static int str_len (lua_State L) {
uint l;
luaL_checklstring(L, 1, out l);
lua_pushinteger(L, (int)l);
return 1;
}
private static ptrdiff_t posrelat (ptrdiff_t pos, uint len) {
/* relative string position: negative means back from end */
if (pos < 0) pos += (ptrdiff_t)len + 1;
return (pos >= 0) ? pos : 0;
}
private static int str_sub (lua_State L) {
uint l;
CharPtr s = luaL_checklstring(L, 1, out l);
ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
if (start < 1) start = 1;
if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
if (start <= end)
lua_pushlstring(L, s+start-1, (uint)(end-start+1));
else lua_pushliteral(L, "");
return 1;
}
private static int str_reverse (lua_State L) {
uint l;
luaL_Buffer b = new luaL_Buffer();
CharPtr s = luaL_checklstring(L, 1, out l);
luaL_buffinit(L, b);
while ((l--) != 0) luaL_addchar(b, s[l]);
luaL_pushresult(b);
return 1;
}
private static int str_lower (lua_State L) {
uint l;
uint i;
luaL_Buffer b = new luaL_Buffer();
CharPtr s = luaL_checklstring(L, 1, out l);
luaL_buffinit(L, b);
for (i=0; i<l; i++)
luaL_addchar(b, tolower(s[i]));
luaL_pushresult(b);
return 1;
}
private static int str_upper (lua_State L) {
uint l;
uint i;
luaL_Buffer b = new luaL_Buffer();
CharPtr s = luaL_checklstring(L, 1, out l);
luaL_buffinit(L, b);
for (i=0; i<l; i++)
luaL_addchar(b, toupper(s[i]));
luaL_pushresult(b);
return 1;
}
private static int str_rep (lua_State L) {
uint l;
luaL_Buffer b = new luaL_Buffer();
CharPtr s = luaL_checklstring(L, 1, out l);
int n = luaL_checkint(L, 2);
luaL_buffinit(L, b);
while (n-- > 0)
luaL_addlstring(b, s, l);
luaL_pushresult(b);
return 1;
}
private static int str_byte (lua_State L) {
uint l;
CharPtr s = luaL_checklstring(L, 1, out l);
ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l);
int n, i;
if (posi <= 0) posi = 1;
if ((uint)pose > l) pose = (int)l;
if (posi > pose) return 0; /* empty interval; return no values */
n = (int)(pose - posi + 1);
if (posi + n <= pose) /* overflow? */
luaL_error(L, "string slice too long");
luaL_checkstack(L, n, "string slice too long");
for (i=0; i<n; i++)
lua_pushinteger(L, (byte)(s[posi + i - 1]));
return n;
}
private static int str_char (lua_State L) {
int n = lua_gettop(L); /* number of arguments */
int i;
luaL_Buffer b = new luaL_Buffer();
luaL_buffinit(L, b);
for (i=1; i<=n; i++) {
int c = luaL_checkint(L, i);
luaL_argcheck(L, (byte)(c) == c, i, "invalid value");
luaL_addchar(b, (char)(byte)c);
}
luaL_pushresult(b);
return 1;
}
private static int writer (lua_State L, object b, uint size, object B)
{
if (b.GetType() != typeof(CharPtr))
{
using (MemoryStream stream = new MemoryStream())
{
// todo: figure out a way to do this
/*
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, b);
stream.Flush();
byte[] bytes = stream.GetBuffer();
char[] chars = new char[bytes.Length];
for (int i = 0; i < bytes.Length; i++)
chars[i] = (char)bytes[i];
b = new CharPtr(chars);
* */
}
}
luaL_addlstring((luaL_Buffer)B, (CharPtr)b, size);
return 0;
}
private static int str_dump (lua_State L) {
luaL_Buffer b = new luaL_Buffer();
luaL_checktype(L, 1, LUA_TFUNCTION);
lua_settop(L, 1);
luaL_buffinit(L,b);
if (lua_dump(L, writer, b) != 0)
luaL_error(L, "unable to dump given function");
luaL_pushresult(b);
return 1;
}
/*
** {======================================================
** PATTERN MATCHING
** =======================================================
*/
public const int CAP_UNFINISHED = (-1);
public const int CAP_POSITION = (-2);
public class MatchState {
public MatchState()
{
for (int i = 0; i < LUA_MAXCAPTURES; i++)
capture[i] = new capture_();
}
public CharPtr src_init; /* init of source string */
public CharPtr src_end; /* end (`\0') of source string */
public lua_State L;
public int level; /* total number of captures (finished or unfinished) */
public class capture_{
public CharPtr init;
public ptrdiff_t len;
};
public capture_[] capture = new capture_[LUA_MAXCAPTURES];
};
public const char L_ESC = '%';
public const string SPECIALS = "^$*+?.([%-";
private static int check_capture (MatchState ms, int l) {
l -= '1';
if (l < 0 || l >= ms.level || ms.capture[l].len == CAP_UNFINISHED)
return luaL_error(ms.L, "invalid capture index");
return l;
}
private static int capture_to_close (MatchState ms) {
int level = ms.level;
for (level--; level>=0; level--)
if (ms.capture[level].len == CAP_UNFINISHED) return level;
return luaL_error(ms.L, "invalid pattern capture");
}
private static CharPtr classend (MatchState ms, CharPtr p) {
p = new CharPtr(p);
char c = p[0];
p = p.next();
switch (c) {
case L_ESC: {
if (p[0] == '\0')
luaL_error(ms.L, "malformed pattern (ends with " + LUA_QL("%%") + ")");
return p+1;
}
case '[': {
if (p[0] == '^') p = p.next();
do { /* look for a `]' */
if (p[0] == '\0')
luaL_error(ms.L, "malformed pattern (missing " + LUA_QL("]") + ")");
c = p[0];
p = p.next();
if (c == L_ESC && p[0] != '\0')
p = p.next(); /* skip escapes (e.g. `%]') */
} while (p[0] != ']');
return p+1;
}
default: {
return p;
}
}
}
private static int match_class (int c, int cl) {
bool res;
switch (tolower(cl)) {
case 'a' : res = isalpha(c); break;
case 'c' : res = iscntrl(c); break;
case 'd' : res = isdigit(c); break;
case 'l' : res = islower(c); break;
case 'p' : res = ispunct(c); break;
case 's' : res = isspace(c); break;
case 'u' : res = isupper(c); break;
case 'w' : res = isalnum(c); break;
case 'x' : res = isxdigit((char)c); break;
case 'z' : res = (c == 0); break;
default: return (cl == c) ? 1 : 0;
}
return (islower(cl) ? (res ? 1 : 0) : ((!res) ? 1 : 0));
}
private static int matchbracketclass (int c, CharPtr p, CharPtr ec) {
int sig = 1;
if (p[1] == '^') {
sig = 0;
p = p.next(); /* skip the `^' */
}
while ((p=p.next()) < ec) {
if (p == L_ESC) {
p = p.next();
if (match_class(c, (byte)(p[0])) != 0)
return sig;
}
else if ((p[1] == '-') && (p + 2 < ec)) {
p+=2;
if ((byte)((p[-2])) <= c && (c <= (byte)p[0]))
return sig;
}
else if ((byte)(p[0]) == c) return sig;
}
return (sig == 0) ? 1 : 0;
}
private static int singlematch (int c, CharPtr p, CharPtr ep) {
switch (p[0]) {
case '.': return 1; /* matches any char */
case L_ESC: return match_class(c, (byte)(p[1]));
case '[': return matchbracketclass(c, p, ep-1);
default: return ((byte)(p[0]) == c) ? 1 : 0;
}
}
private static CharPtr matchbalance (MatchState ms, CharPtr s,
CharPtr p) {
if ((p[0] == 0) || (p[1] == 0))
luaL_error(ms.L, "unbalanced pattern");
if (s[0] != p[0]) return null;
else {
int b = p[0];
int e = p[1];
int cont = 1;
while ((s=s.next()) < ms.src_end) {
if (s[0] == e) {
if (--cont == 0) return s+1;
}
else if (s[0] == b) cont++;
}
}
return null; /* string ends out of balance */
}
private static CharPtr max_expand (MatchState ms, CharPtr s,
CharPtr p, CharPtr ep) {
ptrdiff_t i = 0; /* counts maximum expand for item */
while ( (s+i < ms.src_end) && (singlematch((byte)(s[i]), p, ep) != 0) )
i++;
/* keeps trying to match with the maximum repetitions */
while (i>=0) {
CharPtr res = match(ms, (s+i), ep+1);
if (res != null) return res;
i--; /* else didn't match; reduce 1 repetition to try again */
}
return null;
}
private static CharPtr min_expand (MatchState ms, CharPtr s,
CharPtr p, CharPtr ep) {
for (;;) {
CharPtr res = match(ms, s, ep+1);
if (res != null)
return res;
else if ( (s < ms.src_end) && (singlematch((byte)(s[0]), p, ep) != 0) )
s = s.next(); /* try with one more repetition */
else return null;
}
}
private static CharPtr start_capture (MatchState ms, CharPtr s,
CharPtr p, int what) {
CharPtr res;
int level = ms.level;
if (level >= LUA_MAXCAPTURES) luaL_error(ms.L, "too many captures");
ms.capture[level].init = s;
ms.capture[level].len = what;
ms.level = level+1;
if ((res=match(ms, s, p)) == null) /* match failed? */
ms.level--; /* undo capture */
return res;
}
private static CharPtr end_capture(MatchState ms, CharPtr s,
CharPtr p) {
int l = capture_to_close(ms);
CharPtr res;
ms.capture[l].len = s - ms.capture[l].init; /* close capture */
if ((res = match(ms, s, p)) == null) /* match failed? */
ms.capture[l].len = CAP_UNFINISHED; /* undo capture */
return res;
}
private static CharPtr match_capture(MatchState ms, CharPtr s, int l)
{
uint len;
l = check_capture(ms, l);
len = (uint)ms.capture[l].len;
if ((uint)(ms.src_end-s) >= len &&
memcmp(ms.capture[l].init, s, len) == 0)
return s+len;
else return null;
}
private static CharPtr match (MatchState ms, CharPtr s, CharPtr p) {
s = new CharPtr(s);
p = new CharPtr(p);
init: /* using goto's to optimize tail recursion */
switch (p[0]) {
case '(': { /* start capture */
if (p[1] == ')') /* position capture? */
return start_capture(ms, s, p+2, CAP_POSITION);
else
return start_capture(ms, s, p+1, CAP_UNFINISHED);
}
case ')': { /* end capture */
return end_capture(ms, s, p+1);
}
case L_ESC: {
switch (p[1]) {
case 'b': { /* balanced string? */
s = matchbalance(ms, s, p+2);
if (s == null) return null;
p+=4; goto init; /* else return match(ms, s, p+4); */
}
case 'f': { /* frontier? */
CharPtr ep; char previous;
p += 2;
if (p[0] != '[')
luaL_error(ms.L, "missing " + LUA_QL("[") + " after " +
LUA_QL("%%f") + " in pattern");
ep = classend(ms, p); /* points to what is next */
previous = (s == ms.src_init) ? '\0' : s[-1];
if ((matchbracketclass((byte)(previous), p, ep-1)!=0) ||
(matchbracketclass((byte)(s[0]), p, ep-1)==0)) return null;
p=ep; goto init; /* else return match(ms, s, ep); */
}
default: {
if (isdigit((byte)(p[1]))) { /* capture results (%0-%9)? */
s = match_capture(ms, s, (byte)(p[1]));
if (s == null) return null;
p+=2; goto init; /* else return match(ms, s, p+2) */
}
goto dflt; /* case default */
}
}
}
case '\0': { /* end of pattern */
return s; /* match succeeded */
}
case '$': {
if (p[1] == '\0') /* is the `$' the last char in pattern? */
return (s == ms.src_end) ? s : null; /* check end of string */
else goto dflt;
}
default: dflt: { /* it is a pattern item */
CharPtr ep = classend(ms, p); /* points to what is next */
int m = (s<ms.src_end) && (singlematch((byte)(s[0]), p, ep)!=0) ? 1 : 0;
switch (ep[0]) {
case '?': { /* optional */
CharPtr res;
if ((m!=0) && ((res=match(ms, s+1, ep+1)) != null))
return res;
p=ep+1; goto init; /* else return match(ms, s, ep+1); */
}
case '*': { /* 0 or more repetitions */
return max_expand(ms, s, p, ep);
}
case '+': { /* 1 or more repetitions */
return ((m!=0) ? max_expand(ms, s+1, p, ep) : null);
}
case '-': { /* 0 or more repetitions (minimum) */
return min_expand(ms, s, p, ep);
}
default: {
if (m==0) return null;
s = s.next(); p=ep; goto init; /* else return match(ms, s+1, ep); */
}
}
}
}
}
private static CharPtr lmemfind (CharPtr s1, uint l1,
CharPtr s2, uint l2) {
if (l2 == 0) return s1; /* empty strings are everywhere */
else if (l2 > l1) return null; /* avoids a negative `l1' */
else {
CharPtr init; /* to search for a `*s2' inside `s1' */
l2--; /* 1st char will be checked by `memchr' */
l1 = l1-l2; /* `s2' cannot be found after that */
while (l1 > 0 && (init = memchr(s1, s2[0], l1)) != null) {
init = init.next(); /* 1st char is already checked */
if (memcmp(init, s2+1, l2) == 0)
return init-1;
else { /* correct `l1' and `s1' to try again */
l1 -= (uint)(init-s1);
s1 = init;
}
}
return null; /* not found */
}
}
private static void push_onecapture (MatchState ms, int i, CharPtr s,
CharPtr e) {
if (i >= ms.level) {
if (i == 0) /* ms.level == 0, too */
lua_pushlstring(ms.L, s, (uint)(e - s)); /* add whole match */
else
luaL_error(ms.L, "invalid capture index");
}
else {
ptrdiff_t l = ms.capture[i].len;
if (l == CAP_UNFINISHED) luaL_error(ms.L, "unfinished capture");
if (l == CAP_POSITION)
lua_pushinteger(ms.L, ms.capture[i].init - ms.src_init + 1);
else
lua_pushlstring(ms.L, ms.capture[i].init, (uint)l);
}
}
private static int push_captures (MatchState ms, CharPtr s, CharPtr e) {
int i;
int nlevels = ((ms.level == 0) && (s!=null)) ? 1 : ms.level;
luaL_checkstack(ms.L, nlevels, "too many captures");
for (i = 0; i < nlevels; i++)
push_onecapture(ms, i, s, e);
return nlevels; /* number of strings pushed */
}
private static int str_find_aux (lua_State L, int find) {
uint l1, l2;
CharPtr s = luaL_checklstring(L, 1, out l1);
CharPtr p = luaL_checklstring(L, 2, out l2);
ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
if (init < 0) init = 0;
else if ((uint)(init) > l1) init = (ptrdiff_t)l1;
if ((find!=0) && ((lua_toboolean(L, 4)!=0) || /* explicit request? */
strpbrk(p, SPECIALS) == null)) { /* or no special characters? */
/* do a plain search */
CharPtr s2 = lmemfind(s+init, (uint)(l1-init), p, (uint)(l2));
if (s2 != null) {
lua_pushinteger(L, s2-s+1);
lua_pushinteger(L, (int)(s2-s+l2));
return 2;
}
}
else {
MatchState ms = new MatchState();
int anchor = 0;
if (p[0] == '^')
{
p = p.next();
anchor = 1;
}
CharPtr s1=s+init;
ms.L = L;
ms.src_init = s;
ms.src_end = s+l1;
do {
CharPtr res;
ms.level = 0;
if ((res=match(ms, s1, p)) != null) {
if (find != 0) {
lua_pushinteger(L, s1-s+1); /* start */
lua_pushinteger(L, res-s); /* end */
return push_captures(ms, null, null) + 2;
}
else
return push_captures(ms, s1, res);
}
} while (((s1=s1.next()) <= ms.src_end) && (anchor==0));
}
lua_pushnil(L); /* not found */
return 1;
}
private static int str_find (lua_State L) {
return str_find_aux(L, 1);
}
private static int str_match (lua_State L) {
return str_find_aux(L, 0);
}
private static int gmatch_aux (lua_State L) {
MatchState ms = new MatchState();
uint ls;
CharPtr s = lua_tolstring(L, lua_upvalueindex(1), out ls);
CharPtr p = lua_tostring(L, lua_upvalueindex(2));
CharPtr src;
ms.L = L;
ms.src_init = s;
ms.src_end = s+ls;
for (src = s + (uint)lua_tointeger(L, lua_upvalueindex(3));
src <= ms.src_end;
src = src.next()) {
CharPtr e;
ms.level = 0;
if ((e = match(ms, src, p)) != null) {
lua_Integer newstart = e-s;
if (e == src) newstart++; /* empty match? go at least one position */
lua_pushinteger(L, newstart);
lua_replace(L, lua_upvalueindex(3));
return push_captures(ms, src, e);
}
}
return 0; /* not found */
}
private static int gmatch (lua_State L) {
luaL_checkstring(L, 1);
luaL_checkstring(L, 2);
lua_settop(L, 2);
lua_pushinteger(L, 0);
lua_pushcclosure(L, gmatch_aux, 3);
return 1;
}
private static int gfind_nodef (lua_State L) {
return luaL_error(L, LUA_QL("string.gfind") + " was renamed to " +
LUA_QL("string.gmatch"));
}
private static void add_s (MatchState ms, luaL_Buffer b, CharPtr s,
CharPtr e) {
uint l, i;
CharPtr news = lua_tolstring(ms.L, 3, out l);
for (i = 0; i < l; i++) {
if (news[i] != L_ESC)
luaL_addchar(b, news[i]);
else {
i++; /* skip ESC */
if (!isdigit((byte)(news[i])))
luaL_addchar(b, news[i]);
else if (news[i] == '0')
luaL_addlstring(b, s, (uint)(e - s));
else {
push_onecapture(ms, news[i] - '1', s, e);
luaL_addvalue(b); /* add capture to accumulated result */
}
}
}
}
private static void add_value (MatchState ms, luaL_Buffer b, CharPtr s,
CharPtr e) {
lua_State L = ms.L;
switch (lua_type(L, 3)) {
case LUA_TNUMBER:
case LUA_TSTRING: {
add_s(ms, b, s, e);
return;
}
case LUA_TFUNCTION: {
int n;
lua_pushvalue(L, 3);
n = push_captures(ms, s, e);
lua_call(L, n, 1);
break;
}
case LUA_TTABLE: {
push_onecapture(ms, 0, s, e);
lua_gettable(L, 3);
break;
}
}
if (lua_toboolean(L, -1)==0) { /* nil or false? */
lua_pop(L, 1);
lua_pushlstring(L, s, (uint)(e - s)); /* keep original text */
}
else if (lua_isstring(L, -1)==0)
luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));
luaL_addvalue(b); /* add result to accumulator */
}
private static int str_gsub (lua_State L) {
uint srcl;
CharPtr src = luaL_checklstring(L, 1, out srcl);
CharPtr p = luaL_checkstring(L, 2);
int tr = lua_type(L, 3);
int max_s = luaL_optint(L, 4, (int)(srcl+1));
int anchor = 0;
if (p[0] == '^')
{
p = p.next();
anchor = 1;
}
int n = 0;
MatchState ms = new MatchState();
luaL_Buffer b = new luaL_Buffer();
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
"string/function/table expected");
luaL_buffinit(L, b);
ms.L = L;
ms.src_init = src;
ms.src_end = src+srcl;
while (n < max_s) {
CharPtr e;
ms.level = 0;
e = match(ms, src, p);
if (e != null) {
n++;
add_value(ms, b, src, e);
}
if ((e!=null) && e>src) /* non empty match? */
src = e; /* skip it */
else if (src < ms.src_end)
{
char c = src[0];
src = src.next();
luaL_addchar(b, c);
}
else break;
if (anchor != 0) break;
}
luaL_addlstring(b, src, (uint)(ms.src_end-src));
luaL_pushresult(b);
lua_pushinteger(L, n); /* number of substitutions */
return 2;
}
/* }====================================================== */
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
public const int MAX_ITEM = 512;
/* valid flags in a format specification */
public const string FLAGS = "-+ #0";
/*
** maximum size of each format specification (such as '%-099.99d')
** (+10 accounts for %99.99x plus margin of error)
*/
public static readonly int MAX_FORMAT = (FLAGS.Length+1) + (LUA_INTFRMLEN.Length+1) + 10;
private static void addquoted (lua_State L, luaL_Buffer b, int arg) {
uint l;
CharPtr s = luaL_checklstring(L, arg, out l);
luaL_addchar(b, '"');
while ((l--) != 0) {
switch (s[0]) {
case '"': case '\\': case '\n': {
luaL_addchar(b, '\\');
luaL_addchar(b, s[0]);
break;
}
case '\r': {
luaL_addlstring(b, "\\r", 2);
break;
}
case '\0': {
luaL_addlstring(b, "\\000", 4);
break;
}
default: {
luaL_addchar(b, s[0]);
break;
}
}
s = s.next();
}
luaL_addchar(b, '"');
}
private static CharPtr scanformat (lua_State L, CharPtr strfrmt, CharPtr form) {
CharPtr p = strfrmt;
while (p[0] != '\0' && strchr(FLAGS, p[0]) != null) p = p.next(); /* skip flags */
if ((uint)(p - strfrmt) >= (FLAGS.Length+1))
luaL_error(L, "invalid format (repeated flags)");
if (isdigit((byte)(p[0]))) p = p.next(); /* skip width */
if (isdigit((byte)(p[0]))) p = p.next(); /* (2 digits at most) */
if (p[0] == '.') {
p = p.next();
if (isdigit((byte)(p[0]))) p = p.next(); /* skip precision */
if (isdigit((byte)(p[0]))) p = p.next(); /* (2 digits at most) */
}
if (isdigit((byte)(p[0])))
luaL_error(L, "invalid format (width or precision too long)");
form[0] = '%';
form = form.next();
strncpy(form, strfrmt, p - strfrmt + 1);
form += p - strfrmt + 1;
form[0] = '\0';
return p;
}
private static void addintlen (CharPtr form) {
uint l = (uint)strlen(form);
char spec = form[l - 1];
strcpy(form + l - 1, LUA_INTFRMLEN);
form[l + (LUA_INTFRMLEN.Length + 1) - 2] = spec;
form[l + (LUA_INTFRMLEN.Length + 1) - 1] = '\0';
}
private static int str_format (lua_State L) {
int arg = 1;
uint sfl;
CharPtr strfrmt = luaL_checklstring(L, arg, out sfl);
CharPtr strfrmt_end = strfrmt+sfl;
luaL_Buffer b = new luaL_Buffer();
luaL_buffinit(L, b);
while (strfrmt < strfrmt_end) {
if (strfrmt[0] != L_ESC)
{
luaL_addchar(b, strfrmt[0]);
strfrmt = strfrmt.next();
}
else if (strfrmt[1] == L_ESC)
{
luaL_addchar(b, strfrmt[0]); /* %% */
strfrmt = strfrmt + 2;
}
else
{ /* format item */
strfrmt = strfrmt.next();
CharPtr form = new char[MAX_FORMAT]; /* to store the format (`%...') */
CharPtr buff = new char[MAX_ITEM]; /* to store the formatted item */
arg++;
strfrmt = scanformat(L, strfrmt, form);
char ch = strfrmt[0];
strfrmt = strfrmt.next();
switch (ch)
{
case 'c':
{
sprintf(buff, form, (int)luaL_checknumber(L, arg));
break;
}
case 'd':
case 'i':
{
addintlen(form);
sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
break;
}
case 'o':
case 'u':
case 'x':
case 'X':
{
addintlen(form);
sprintf(buff, form, (UNSIGNED_LUA_INTFRM_T)luaL_checknumber(L, arg));
break;
}
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
{
sprintf(buff, form, (double)luaL_checknumber(L, arg));
break;
}
case 'q':
{
addquoted(L, b, arg);
continue; /* skip the 'addsize' at the end */
}
case 's':
{
uint l;
CharPtr s = luaL_checklstring(L, arg, out l);
if ((strchr(form, '.') == null) && l >= 100)
{
/* no precision and string is too long to be formatted;
keep original string */
lua_pushvalue(L, arg);
luaL_addvalue(b);
continue; /* skip the `addsize' at the end */
}
else
{
sprintf(buff, form, s);
break;
}
}
default:
{ /* also treat cases `pnLlh' */
return luaL_error(L, "invalid option " + LUA_QL("%%%c") + " to " +
LUA_QL("format"), strfrmt[-1]);
}
}
luaL_addlstring(b, buff, (uint)strlen(buff));
}
}
luaL_pushresult(b);
return 1;
}
private readonly static luaL_Reg[] strlib = {
new luaL_Reg("byte", str_byte),
new luaL_Reg("char", str_char),
new luaL_Reg("dump", str_dump),
new luaL_Reg("find", str_find),
new luaL_Reg("format", str_format),
new luaL_Reg("gfind", gfind_nodef),
new luaL_Reg("gmatch", gmatch),
new luaL_Reg("gsub", str_gsub),
new luaL_Reg("len", str_len),
new luaL_Reg("lower", str_lower),
new luaL_Reg("match", str_match),
new luaL_Reg("rep", str_rep),
new luaL_Reg("reverse", str_reverse),
new luaL_Reg("sub", str_sub),
new luaL_Reg("upper", str_upper),
new luaL_Reg(null, null)
};
private static void createmetatable (lua_State L) {
lua_createtable(L, 0, 1); /* create metatable for strings */
lua_pushliteral(L, ""); /* dummy string */
lua_pushvalue(L, -2);
lua_setmetatable(L, -2); /* set string metatable */
lua_pop(L, 1); /* pop dummy string */
lua_pushvalue(L, -2); /* string library... */
lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */
lua_pop(L, 1); /* pop metatable */
}
/*
** Open string library
*/
public static int luaopen_string (lua_State L) {
luaL_register(L, LUA_STRLIBNAME, strlib);
#if LUA_COMPAT_GFIND
lua_getfield(L, -1, "gmatch");
lua_setfield(L, -2, "gfind");
#endif
createmetatable(L);
return 1;
}
}
}
/*
** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace KopiLua
{
using TValue = Lua.lua_TValue;
using StkId = Lua.lua_TValue;
using lua_Number = System.Double;
public partial class Lua
{
/*
** Implementation of tables (aka arrays, objects, or hash tables).
** Tables keep its elements in two parts: an array part and a hash part.
** Non-negative integer keys are all candidates to be kept in the array
** part. The actual size of the array is the largest `n' such that at
** least half the slots between 0 and n are in use.
** Hash uses a mix of chained scatter table with Brent's variation.
** A main invariant of these tables is that, if an element is not
** in its main position (i.e. the `original' position that its hash gives
** to it), then the colliding element is in its own main position.
** Hence even when the load factor reaches 100%, performance remains good.
*/
internal static Node gnode(Table t, int i) { return t.node[i]; }
internal static TKey_nk gkey(Node n) { return n.i_key.nk; }
internal static TValue gval(Node n) { return n.i_val; }
internal static Node gnext(Node n) { return n.i_key.nk.next; }
internal static void gnext_set(Node n, Node v) { n.i_key.nk.next = v; }
internal static TValue key2tval(Node n) { return n.i_key.tvk; }
/*
** max size of array part is 2^MAXBITS
*/
//#if LUAI_BITSINT > 26
public const int MAXBITS = 26; /* in the dotnet port LUAI_BITSINT is 32 */
//#else
//public const int MAXBITS = (LUAI_BITSINT-2);
//#endif
public const int MAXASIZE = (1 << MAXBITS);
//public static Node gnode(Table t, int i) {return t.node[i];}
internal static Node hashpow2(Table t, lua_Number n) { return gnode(t, (int)lmod(n, sizenode(t))); }
public static Node hashstr(Table t, TString str) {return hashpow2(t, str.tsv.hash);}
public static Node hashboolean(Table t, int p) {return hashpow2(t, p);}
/*
** for some types, it is better to avoid modulus by power of 2, as
** they tend to have many 2 factors.
*/
public static Node hashmod(Table t, int n) { return gnode(t, (n % ((sizenode(t) - 1) | 1))); }
public static Node hashpointer(Table t, object p) { return hashmod(t, p.GetHashCode()); }
/*
** number of ints inside a lua_Number
*/
public const int numints = sizeof(lua_Number) / sizeof(int);
//static const Node dummynode_ = {
//{{null}, LUA_TNIL}, /* value */
//{{{null}, LUA_TNIL, null}} /* key */
//};
public static Node dummynode_ = new Node(new TValue(new Value(), LUA_TNIL), new TKey(new Value(), LUA_TNIL, null));
public static Node dummynode = dummynode_;
/*
** hash for lua_Numbers
*/
private static Node hashnum (Table t, lua_Number n) {
byte[] a = BitConverter.GetBytes(n);
for (int i = 1; i < a.Length; i++) a[0] += a[i];
return hashmod(t, (int)a[0]);
}
/*
** returns the `main' position of an element in a table (that is, the index
** of its hash value)
*/
private static Node mainposition (Table t, TValue key) {
switch (ttype(key)) {
case LUA_TNUMBER:
return hashnum(t, nvalue(key));
case LUA_TSTRING:
return hashstr(t, rawtsvalue(key));
case LUA_TBOOLEAN:
return hashboolean(t, bvalue(key));
case LUA_TLIGHTUSERDATA:
return hashpointer(t, pvalue(key));
default:
return hashpointer(t, gcvalue(key));
}
}
/*
** returns the index for `key' if `key' is an appropriate key to live in
** the array part of the table, -1 otherwise.
*/
private static int arrayindex (TValue key) {
if (ttisnumber(key)) {
lua_Number n = nvalue(key);
int k;
lua_number2int(out k, n);
if (luai_numeq(cast_num(k), n))
return k;
}
return -1; /* `key' did not match some condition */
}
/*
** returns the index of a `key' for table traversals. First goes all
** elements in the array part, then elements in the hash part. The
** beginning of a traversal is signalled by -1.
*/
private static int findindex (lua_State L, Table t, StkId key) {
int i;
if (ttisnil(key)) return -1; /* first iteration */
i = arrayindex(key);
if (0 < i && i <= t.sizearray) /* is `key' inside array part? */
return i-1; /* yes; that's the index (corrected to C) */
else {
Node n = mainposition(t, key);
do { /* check whether `key' is somewhere in the chain */
/* key may be dead already, but it is ok to use it in `next' */
if ((luaO_rawequalObj(key2tval(n), key) != 0) ||
(ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) &&
gcvalue(gkey(n)) == gcvalue(key))) {
i = cast_int(n - gnode(t, 0)); /* key index in hash table */
/* hash elements are numbered after array ones */
return i + t.sizearray;
}
else n = gnext(n);
} while (n != null);
luaG_runerror(L, "invalid key to " + LUA_QL("next")); /* key not found */
return 0; /* to avoid warnings */
}
}
public static int luaH_next (lua_State L, Table t, StkId key) {
int i = findindex(L, t, key); /* find original element */
for (i++; i < t.sizearray; i++) { /* try first array part */
if (!ttisnil(t.array[i])) { /* a non-nil value? */
setnvalue(key, cast_num(i+1));
setobj2s(L, key+1, t.array[i]);
return 1;
}
}
for (i -= t.sizearray; i < sizenode(t); i++) { /* then hash part */
if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */
setobj2s(L, key, key2tval(gnode(t, i)));
setobj2s(L, key+1, gval(gnode(t, i)));
return 1;
}
}
return 0; /* no more elements */
}
/*
** {=============================================================
** Rehash
** ==============================================================
*/
private static int computesizes (int[] nums, ref int narray) {
int i;
int twotoi; /* 2^i */
int a = 0; /* number of elements smaller than 2^i */
int na = 0; /* number of elements to go to array part */
int n = 0; /* optimal size for array part */
for (i = 0, twotoi = 1; twotoi/2 < narray; i++, twotoi *= 2) {
if (nums[i] > 0) {
a += nums[i];
if (a > twotoi/2) { /* more than half elements present? */
n = twotoi; /* optimal size (till now) */
na = a; /* all elements smaller than n will go to array part */
}
}
if (a == narray) break; /* all elements already counted */
}
narray = n;
lua_assert(narray/2 <= na && na <= narray);
return na;
}
private static int countint (TValue key, int[] nums) {
int k = arrayindex(key);
if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */
nums[ceillog2(k)]++; /* count as such */
return 1;
}
else
return 0;
}
private static int numusearray (Table t, int[] nums) {
int lg;
int ttlg; /* 2^lg */
int ause = 0; /* summation of `nums' */
int i = 1; /* count to traverse all array keys */
for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */
int lc = 0; /* counter */
int lim = ttlg;
if (lim > t.sizearray) {
lim = t.sizearray; /* adjust upper limit */
if (i > lim)
break; /* no more elements to count */
}
/* count elements in range (2^(lg-1), 2^lg] */
for (; i <= lim; i++) {
if (!ttisnil(t.array[i-1]))
lc++;
}
nums[lg] += lc;
ause += lc;
}
return ause;
}
private static int numusehash (Table t, int[] nums, ref int pnasize) {
int totaluse = 0; /* total number of elements */
int ause = 0; /* summation of `nums' */
int i = sizenode(t);
while ((i--) != 0) {
Node n = t.node[i];
if (!ttisnil(gval(n))) {
ause += countint(key2tval(n), nums);
totaluse++;
}
}
pnasize += ause;
return totaluse;
}
private static void setarrayvector (lua_State L, Table t, int size) {
int i;
luaM_reallocvector<TValue>(L, ref t.array, t.sizearray, size/*, TValue*/);
for (i=t.sizearray; i<size; i++)
setnilvalue(t.array[i]);
t.sizearray = size;
}
private static void setnodevector (lua_State L, Table t, int size) {
int lsize;
if (size == 0) { /* no elements to hash part? */
t.node = new Node[] { dummynode }; /* use common `dummynode' */
lsize = 0;
}
else {
int i;
lsize = ceillog2(size);
if (lsize > MAXBITS)
luaG_runerror(L, "table overflow");
size = twoto(lsize);
Node[] nodes = luaM_newvector<Node>(L, size);
t.node = nodes;
for (i=0; i<size; i++) {
Node n = gnode(t, i);
gnext_set(n, null);
setnilvalue(gkey(n));
setnilvalue(gval(n));
}
}
t.lsizenode = cast_byte(lsize);
t.lastfree = size; /* all positions are free */
}
private static void resize (lua_State L, Table t, int nasize, int nhsize) {
int i;
int oldasize = t.sizearray;
int oldhsize = t.lsizenode;
Node[] nold = t.node; /* save old hash ... */
if (nasize > oldasize) /* array part must grow? */
setarrayvector(L, t, nasize);
/* create new hash part with appropriate size */
setnodevector(L, t, nhsize);
if (nasize < oldasize) { /* array part must shrink? */
t.sizearray = nasize;
/* re-insert elements from vanishing slice */
for (i=nasize; i<oldasize; i++) {
if (!ttisnil(t.array[i]))
setobjt2t(L, luaH_setnum(L, t, i+1), t.array[i]);
}
/* shrink array */
luaM_reallocvector<TValue>(L, ref t.array, oldasize, nasize/*, TValue*/);
}
/* re-insert elements from hash part */
for (i = twoto(oldhsize) - 1; i >= 0; i--) {
Node old = nold[i];
if (!ttisnil(gval(old)))
setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old));
}
if (nold[0] != dummynode)
luaM_freearray(L, nold); /* free old array */
}
public static void luaH_resizearray (lua_State L, Table t, int nasize) {
int nsize = (t.node[0] == dummynode) ? 0 : sizenode(t);
resize(L, t, nasize, nsize);
}
private static void rehash (lua_State L, Table t, TValue ek) {
int nasize, na;
int[] nums = new int[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */
int i;
int totaluse;
for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */
nasize = numusearray(t, nums); /* count keys in array part */
totaluse = nasize; /* all those keys are integer keys */
totaluse += numusehash(t, nums, ref nasize); /* count keys in hash part */
/* count extra key */
nasize += countint(ek, nums);
totaluse++;
/* compute new size for array part */
na = computesizes(nums, ref nasize);
/* resize the table to new computed sizes */
resize(L, t, nasize, totaluse - na);
}
/*
** }=============================================================
*/
public static Table luaH_new (lua_State L, int narray, int nhash) {
Table t = luaM_new<Table>(L);
luaC_link(L, obj2gco(t), LUA_TTABLE);
t.metatable = null;
t.flags = cast_byte(~0);
/* temporary values (kept only if some malloc fails) */
t.array = null;
t.sizearray = 0;
t.lsizenode = 0;
t.node = new Node[] { dummynode };
setarrayvector(L, t, narray);
setnodevector(L, t, nhash);
return t;
}
public static void luaH_free (lua_State L, Table t) {
if (t.node[0] != dummynode)
luaM_freearray(L, t.node);
luaM_freearray(L, t.array);
luaM_free(L, t);
}
private static Node getfreepos (Table t) {
while (t.lastfree-- > 0) {
if (ttisnil(gkey(t.node[t.lastfree])))
return t.node[t.lastfree];
}
return null; /* could not find a free place */
}
/*
** inserts a new key into a hash table; first, check whether key's main
** position is free. If not, check whether colliding node is in its main
** position or not: if it is not, move colliding node to an empty place and
** put new key in its main position; otherwise (colliding node is in its main
** position), new key goes to an empty position.
*/
private static TValue newkey (lua_State L, Table t, TValue key) {
Node mp = mainposition(t, key);
if (!ttisnil(gval(mp)) || mp == dummynode) {
Node othern;
Node n = getfreepos(t); /* get a free place */
if (n == null) { /* cannot find a free place? */
rehash(L, t, key); /* grow table */
return luaH_set(L, t, key); /* re-insert key into grown table */
}
lua_assert(n != dummynode);
othern = mainposition(t, key2tval(mp));
if (othern != mp) { /* is colliding node out of its main position? */
/* yes; move colliding node into free position */
while (gnext(othern) != mp) othern = gnext(othern); /* find previous */
gnext_set(othern, n); /* redo the chain with `n' in place of `mp' */
n.i_val = new TValue(mp.i_val); /* copy colliding node into free pos. (mp.next also goes) */
n.i_key = new TKey(mp.i_key);
gnext_set(mp, null); /* now `mp' is free */
setnilvalue(gval(mp));
}
else { /* colliding node is in its own main position */
/* new node will go into free position */
gnext_set(n, gnext(mp)); /* chain new position */
gnext_set(mp, n);
mp = n;
}
}
gkey(mp).value.Copy(key.value); gkey(mp).tt = key.tt;
luaC_barriert(L, t, key);
lua_assert(ttisnil(gval(mp)));
return gval(mp);
}
/*
** search function for integers
*/
public static TValue luaH_getnum(Table t, int key)
{
/* (1 <= key && key <= t.sizearray) */
if ((uint)(key-1) < (uint)t.sizearray)
return t.array[key-1];
else {
lua_Number nk = cast_num(key);
Node n = hashnum(t, nk);
do { /* check whether `key' is somewhere in the chain */
if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk))
return gval(n); /* that's it */
else n = gnext(n);
} while (n != null);
return luaO_nilobject;
}
}
/*
** search function for strings
*/
public static TValue luaH_getstr (Table t, TString key) {
Node n = hashstr(t, key);
do { /* check whether `key' is somewhere in the chain */
if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key)
return gval(n); /* that's it */
else n = gnext(n);
} while (n != null);
return luaO_nilobject;
}
/*
** main search function
*/
public static TValue luaH_get (Table t, TValue key) {
switch (ttype(key)) {
case LUA_TNIL: return luaO_nilobject;
case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
case LUA_TNUMBER: {
int k;
lua_Number n = nvalue(key);
lua_number2int(out k, n);
if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
return luaH_getnum(t, k); /* use specialized version */
/* else go through ... actually on second thoughts don't, because this is C#*/
Node node = mainposition(t, key);
do
{ /* check whether `key' is somewhere in the chain */
if (luaO_rawequalObj(key2tval(node), key) != 0)
return gval(node); /* that's it */
else node = gnext(node);
} while (node != null);
return luaO_nilobject;
}
default: {
Node node = mainposition(t, key);
do { /* check whether `key' is somewhere in the chain */
if (luaO_rawequalObj(key2tval(node), key) != 0)
return gval(node); /* that's it */
else node = gnext(node);
} while (node != null);
return luaO_nilobject;
}
}
}
public static TValue luaH_set (lua_State L, Table t, TValue key) {
TValue p = luaH_get(t, key);
t.flags = 0;
if (p != luaO_nilobject)
return (TValue)p;
else {
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
luaG_runerror(L, "table index is NaN");
return newkey(L, t, key);
}
}
public static TValue luaH_setnum (lua_State L, Table t, int key) {
TValue p = luaH_getnum(t, key);
if (p != luaO_nilobject)
return (TValue)p;
else {
TValue k = new TValue();
setnvalue(k, cast_num(key));
return newkey(L, t, k);
}
}
public static TValue luaH_setstr (lua_State L, Table t, TString key) {
TValue p = luaH_getstr(t, key);
if (p != luaO_nilobject)
return (TValue)p;
else {
TValue k = new TValue();
setsvalue(L, k, key);
return newkey(L, t, k);
}
}
public static int unbound_search (Table t, uint j) {
uint i = j; /* i is zero or a present index */
j++;
/* find `i' and `j' such that i is present and j is not */
while (!ttisnil(luaH_getnum(t, (int)j))) {
i = j;
j *= 2;
if (j > (uint)MAX_INT) { /* overflow? */
/* table was built with bad purposes: resort to linear search */
i = 1;
while (!ttisnil(luaH_getnum(t, (int)i))) i++;
return (int)(i - 1);
}
}
/* now do a binary search between them */
while (j - i > 1) {
uint m = (i+j)/2;
if (ttisnil(luaH_getnum(t, (int)m))) j = m;
else i = m;
}
return (int)i;
}
/*
** Try to find a boundary in table `t'. A `boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
*/
public static int luaH_getn (Table t) {
uint j = (uint)t.sizearray;
if (j > 0 && ttisnil(t.array[j - 1])) {
/* there is a boundary in the array part: (binary) search for it */
uint i = 0;
while (j - i > 1) {
uint m = (i+j)/2;
if (ttisnil(t.array[m - 1])) j = m;
else i = m;
}
return (int)i;
}
/* else must find a boundary in hash part */
else if (t.node[0] == dummynode) /* hash part is empty? */
return (int)j; /* that is easy... */
else return unbound_search(t, j);
}
//#if defined(LUA_DEBUG)
//Node *luaH_mainposition (const Table *t, const TValue *key) {
// return mainposition(t, key);
//}
//int luaH_isdummy (Node *n) { return n == dummynode; }
//#endif
}
}
/*
** $Id: ltablib.c,v 1.38.1.3 2008/02/14 16:46:58 roberto Exp $
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace KopiLua
{
using lua_Number = System.Double;
public partial class Lua
{
private static int aux_getn(lua_State L, int n) {luaL_checktype(L, n, LUA_TTABLE); return luaL_getn(L, n);}
private static int foreachi (lua_State L) {
int i;
int n = aux_getn(L, 1);
luaL_checktype(L, 2, LUA_TFUNCTION);
for (i=1; i <= n; i++) {
lua_pushvalue(L, 2); /* function */
lua_pushinteger(L, i); /* 1st argument */
lua_rawgeti(L, 1, i); /* 2nd argument */
lua_call(L, 2, 1);
if (!lua_isnil(L, -1))
return 1;
lua_pop(L, 1); /* remove nil result */
}
return 0;
}
private static int _foreach (lua_State L) {
luaL_checktype(L, 1, LUA_TTABLE);
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_pushnil(L); /* first key */
while (lua_next(L, 1) != 0) {
lua_pushvalue(L, 2); /* function */
lua_pushvalue(L, -3); /* key */
lua_pushvalue(L, -3); /* value */
lua_call(L, 2, 1);
if (!lua_isnil(L, -1))
return 1;
lua_pop(L, 2); /* remove value and result */
}
return 0;
}
private static int maxn (lua_State L) {
lua_Number max = 0;
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushnil(L); /* first key */
while (lua_next(L, 1) != 0) {
lua_pop(L, 1); /* remove value */
if (lua_type(L, -1) == LUA_TNUMBER) {
lua_Number v = lua_tonumber(L, -1);
if (v > max) max = v;
}
}
lua_pushnumber(L, max);
return 1;
}
private static int getn (lua_State L) {
lua_pushinteger(L, aux_getn(L, 1));
return 1;
}
private static int setn (lua_State L) {
luaL_checktype(L, 1, LUA_TTABLE);
//#ifndef luaL_setn
//luaL_setn(L, 1, luaL_checkint(L, 2));
//#else
luaL_error(L, LUA_QL("setn") + " is obsolete");
//#endif
lua_pushvalue(L, 1);
return 1;
}
private static int tinsert (lua_State L) {
int e = aux_getn(L, 1) + 1; /* first empty element */
int pos; /* where to insert new element */
switch (lua_gettop(L)) {
case 2: { /* called with only 2 arguments */
pos = e; /* insert new element at the end */
break;
}
case 3: {
int i;
pos = luaL_checkint(L, 2); /* 2nd argument is the position */
if (pos > e) e = pos; /* `grow' array if necessary */
for (i = e; i > pos; i--) { /* move up elements */
lua_rawgeti(L, 1, i-1);
lua_rawseti(L, 1, i); /* t[i] = t[i-1] */
}
break;
}
default: {
return luaL_error(L, "wrong number of arguments to " + LUA_QL("insert"));
}
}
luaL_setn(L, 1, e); /* new size */
lua_rawseti(L, 1, pos); /* t[pos] = v */
return 0;
}
private static int tremove (lua_State L) {
int e = aux_getn(L, 1);
int pos = luaL_optint(L, 2, e);
if (!(1 <= pos && pos <= e)) /* position is outside bounds? */
return 0; /* nothing to remove */
luaL_setn(L, 1, e - 1); /* t.n = n-1 */
lua_rawgeti(L, 1, pos); /* result = t[pos] */
for ( ;pos<e; pos++) {
lua_rawgeti(L, 1, pos+1);
lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */
}
lua_pushnil(L);
lua_rawseti(L, 1, e); /* t[e] = nil */
return 1;
}
private static void addfield (lua_State L, luaL_Buffer b, int i) {
lua_rawgeti(L, 1, i);
if (lua_isstring(L, -1)==0)
luaL_error(L, "invalid value (%s) at index %d in table for " +
LUA_QL("concat"), luaL_typename(L, -1), i);
luaL_addvalue(b);
}
private static int tconcat (lua_State L) {
luaL_Buffer b = new luaL_Buffer();
uint lsep;
int i, last;
CharPtr sep = luaL_optlstring(L, 2, "", out lsep);
luaL_checktype(L, 1, LUA_TTABLE);
i = luaL_optint(L, 3, 1);
last = luaL_opt_integer(L, luaL_checkint, 4, luaL_getn(L, 1));
luaL_buffinit(L, b);
for (; i < last; i++) {
addfield(L, b, i);
luaL_addlstring(b, sep, lsep);
}
if (i == last) /* add last value (if interval was not empty) */
addfield(L, b, i);
luaL_pushresult(b);
return 1;
}
/*
** {======================================================
** Quicksort
** (based on `Algorithms in MODULA-3', Robert Sedgewick;
** Addison-Wesley, 1993.)
*/
private static void set2 (lua_State L, int i, int j) {
lua_rawseti(L, 1, i);
lua_rawseti(L, 1, j);
}
private static int sort_comp (lua_State L, int a, int b) {
if (!lua_isnil(L, 2)) { /* function? */
int res;
lua_pushvalue(L, 2);
lua_pushvalue(L, a-1); /* -1 to compensate function */
lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */
lua_call(L, 2, 1);
res = lua_toboolean(L, -1);
lua_pop(L, 1);
return res;
}
else /* a < b? */
return lua_lessthan(L, a, b);
}
private static int auxsort_loop1(lua_State L, ref int i)
{
lua_rawgeti(L, 1, ++i);
return sort_comp(L, -1, -2);
}
private static int auxsort_loop2(lua_State L, ref int j)
{
lua_rawgeti(L, 1, --j);
return sort_comp(L, -3, -1);
}
private static void auxsort (lua_State L, int l, int u) {
while (l < u) { /* for tail recursion */
int i, j;
/* sort elements a[l], a[(l+u)/2] and a[u] */
lua_rawgeti(L, 1, l);
lua_rawgeti(L, 1, u);
if (sort_comp(L, -1, -2) != 0) /* a[u] < a[l]? */
set2(L, l, u); /* swap a[l] - a[u] */
else
lua_pop(L, 2);
if (u-l == 1) break; /* only 2 elements */
i = (l+u)/2;
lua_rawgeti(L, 1, i);
lua_rawgeti(L, 1, l);
if (sort_comp(L, -2, -1) != 0) /* a[i]<a[l]? */
set2(L, i, l);
else {
lua_pop(L, 1); /* remove a[l] */
lua_rawgeti(L, 1, u);
if (sort_comp(L, -1, -2) != 0) /* a[u]<a[i]? */
set2(L, i, u);
else
lua_pop(L, 2);
}
if (u-l == 2) break; /* only 3 elements */
lua_rawgeti(L, 1, i); /* Pivot */
lua_pushvalue(L, -1);
lua_rawgeti(L, 1, u-1);
set2(L, i, u-1);
/* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
i = l; j = u-1;
for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
/* repeat ++i until a[i] >= P */
while (auxsort_loop1(L, ref i) != 0) {
if (i>u) luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[i] */
}
/* repeat --j until a[j] <= P */
while (auxsort_loop2(L, ref j) != 0) {
if (j<l) luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[j] */
}
if (j<i) {
lua_pop(L, 3); /* pop pivot, a[i], a[j] */
break;
}
set2(L, i, j);
}
lua_rawgeti(L, 1, u-1);
lua_rawgeti(L, 1, i);
set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */
/* a[l..i-1] <= a[i] == P <= a[i+1..u] */
/* adjust so that smaller half is in [j..i] and larger one in [l..u] */
if (i-l < u-i) {
j=l; i=i-1; l=i+2;
}
else {
j=i+1; i=u; u=j-2;
}
auxsort(L, j, i); /* call recursively the smaller one */
} /* repeat the routine for the larger one */
}
private static int sort (lua_State L) {
int n = aux_getn(L, 1);
luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_settop(L, 2); /* make sure there is two arguments */
auxsort(L, 1, n);
return 0;
}
/* }====================================================== */
private readonly static luaL_Reg[] tab_funcs = {
new luaL_Reg("concat", tconcat),
new luaL_Reg("foreach", _foreach),
new luaL_Reg("foreachi", foreachi),
new luaL_Reg("getn", getn),
new luaL_Reg("maxn", maxn),
new luaL_Reg("insert", tinsert),
new luaL_Reg("remove", tremove),
new luaL_Reg("setn", setn),
new luaL_Reg("sort", sort),
new luaL_Reg(null, null)
};
public static int luaopen_table (lua_State L) {
luaL_register(L, LUA_TABLIBNAME, tab_funcs);
return 1;
}
}
}
/*
** $Id: ltm.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace KopiLua
{
using TValue = Lua.lua_TValue;
public partial class Lua
{
/*
* WARNING: if you change the order of this enumeration,
* grep "ORDER TM"
*/
public enum TMS {
TM_INDEX,
TM_NEWINDEX,
TM_GC,
TM_MODE,
TM_EQ, /* last tag method with `fast' access */
TM_ADD,
TM_SUB,
TM_MUL,
TM_DIV,
TM_MOD,
TM_POW,
TM_UNM,
TM_LEN,
TM_LT,
TM_LE,
TM_CONCAT,
TM_CALL,
TM_N /* number of elements in the enum */
};
public static TValue gfasttm(global_State g, Table et, TMS e)
{
return (et == null) ? null :
((et.flags & (1 << (int)e)) != 0) ? null :
luaT_gettm(et, e, g.tmname[(int)e]);
}
public static TValue fasttm(lua_State l, Table et, TMS e) {return gfasttm(G(l), et, e);}
public readonly static CharPtr[] luaT_typenames = {
"nil", "boolean", "userdata", "number",
"string", "table", "function", "userdata", "thread",
"proto", "upval"
};
private readonly static CharPtr[] luaT_eventname = { /* ORDER TM */
"__index", "__newindex",
"__gc", "__mode", "__eq",
"__add", "__sub", "__mul", "__div", "__mod",
"__pow", "__unm", "__len", "__lt", "__le",
"__concat", "__call"
};
public static void luaT_init (lua_State L) {
int i;
for (i=0; i<(int)TMS.TM_N; i++) {
G(L).tmname[i] = luaS_new(L, luaT_eventname[i]);
luaS_fix(G(L).tmname[i]); /* never collect these names */
}
}
/*
** function to be used with macro "fasttm": optimized for absence of
** tag methods
*/
public static TValue luaT_gettm (Table events, TMS event_, TString ename) {
/*const*/ TValue tm = luaH_getstr(events, ename);
lua_assert(event_ <= TMS.TM_EQ);
if (ttisnil(tm)) { /* no tag method? */
events.flags |= (byte)(1<<(int)event_); /* cache this fact */
return null;
}
else return tm;
}
public static TValue luaT_gettmbyobj (lua_State L, TValue o, TMS event_) {
Table mt;
switch (ttype(o)) {
case LUA_TTABLE:
mt = hvalue(o).metatable;
break;
case LUA_TUSERDATA:
mt = uvalue(o).metatable;
break;
default:
mt = G(L).mt[ttype(o)];
break;
}
return ((mt!=null) ? luaH_getstr(mt, G(L).tmname[(int)event_]) : luaO_nilobject);
}
}
}
/*
** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $
** Lua - An Extensible Extension Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace KopiLua
{
using lua_Number = Double;
using lua_Integer = System.Int32;
public partial class Lua
{
public const string LUA_VERSION = "Lua 5.1";
public const string LUA_RELEASE = "Lua 5.1.4";
public const int LUA_VERSION_NUM = 501;
public const string LUA_COPYRIGHT = "Copyright (C) 1994-2008 Lua.org, PUC-Rio";
public const string LUA_AUTHORS = "R. Ierusalimschy, L. H. de Figueiredo & W. Celes";
/* mark for precompiled code (`<esc>Lua') */
public const string LUA_SIGNATURE = "\x01bLua";
/* option for multiple returns in `lua_pcall' and `lua_call' */
public const int LUA_MULTRET = (-1);
/*
** pseudo-indices
*/
public const int LUA_REGISTRYINDEX = (-10000);
public const int LUA_ENVIRONINDEX = (-10001);
public const int LUA_GLOBALSINDEX = (-10002);
public static int lua_upvalueindex(int i) {return LUA_GLOBALSINDEX-i;}
/* thread status; 0 is OK */
public const int LUA_YIELD = 1;
public const int LUA_ERRRUN = 2;
public const int LUA_ERRSYNTAX = 3;
public const int LUA_ERRMEM = 4;
public const int LUA_ERRERR = 5;
public delegate int lua_CFunction(lua_State L);
/*
** functions that read/write blocks when loading/dumping Lua chunks
*/
public delegate CharPtr lua_Reader(lua_State L, object ud, out uint sz);
public delegate int lua_Writer(lua_State L, CharPtr p, uint sz, object ud);
/*
** prototype for memory-allocation functions
*/
//public delegate object lua_Alloc(object ud, object ptr, uint osize, uint nsize);
public delegate object lua_Alloc(Type t);
/*
** basic types
*/
public const int LUA_TNONE = -1;
public const int LUA_TNIL = 0;
public const int LUA_TBOOLEAN = 1;
public const int LUA_TLIGHTUSERDATA = 2;
public const int LUA_TNUMBER = 3;
public const int LUA_TSTRING = 4;
public const int LUA_TTABLE = 5;
public const int LUA_TFUNCTION = 6;
public const int LUA_TUSERDATA = 7;
public const int LUA_TTHREAD = 8;
/* minimum Lua stack available to a C function */
public const int LUA_MINSTACK = 20;
/* type of numbers in Lua */
//typedef LUA_NUMBER lua_Number;
/* type for integer functions */
//typedef LUA_INTEGER lua_Integer;
/*
** garbage-collection function and options
*/
public const int LUA_GCSTOP = 0;
public const int LUA_GCRESTART = 1;
public const int LUA_GCCOLLECT = 2;
public const int LUA_GCCOUNT = 3;
public const int LUA_GCCOUNTB = 4;
public const int LUA_GCSTEP = 5;
public const int LUA_GCSETPAUSE = 6;
public const int LUA_GCSETSTEPMUL = 7;
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
public static void lua_pop(lua_State L, int n)
{
lua_settop(L, -(n) - 1);
}
public static void lua_newtable(lua_State L)
{
lua_createtable(L, 0, 0);
}
public static void lua_register(lua_State L, CharPtr n, lua_CFunction f)
{
lua_pushcfunction(L, f);
lua_setglobal(L, n);
}
public static void lua_pushcfunction(lua_State L, lua_CFunction f)
{
lua_pushcclosure(L, f, 0);
}
public static uint lua_strlen(lua_State L, int i)
{
return lua_objlen(L, i);
}
public static bool lua_isfunction(lua_State L, int n)
{
return lua_type(L, n) == LUA_TFUNCTION;
}
public static bool lua_istable(lua_State L, int n)
{
return lua_type(L, n) == LUA_TTABLE;
}
public static bool lua_islightuserdata(lua_State L, int n)
{
return lua_type(L, n) == LUA_TLIGHTUSERDATA;
}
public static bool lua_isnil(lua_State L, int n)
{
return lua_type(L, n) == LUA_TNIL;
}
public static bool lua_isboolean(lua_State L, int n)
{
return lua_type(L, n) == LUA_TBOOLEAN;
}
public static bool lua_isthread(lua_State L, int n)
{
return lua_type(L, n) == LUA_TTHREAD;
}
public static bool lua_isnone(lua_State L, int n)
{
return lua_type(L, n) == LUA_TNONE;
}
public static bool lua_isnoneornil(lua_State L, lua_Number n)
{
return lua_type(L, (int)n) <= 0;
}
public static void lua_pushliteral(lua_State L, CharPtr s)
{
//TODO: Implement use using lua_pushlstring instead of lua_pushstring
//lua_pushlstring(L, "" s, (sizeof(s)/GetUnmanagedSize(typeof(char)))-1)
lua_pushstring(L, s);
}
public static void lua_setglobal(lua_State L, CharPtr s)
{
lua_setfield(L, LUA_GLOBALSINDEX, s);
}
public static void lua_getglobal(lua_State L, CharPtr s)
{
lua_getfield(L, LUA_GLOBALSINDEX, s);
}
public static CharPtr lua_tostring(lua_State L, int i)
{
uint blah;
return lua_tolstring(L, i, out blah);
}
////#define lua_open() luaL_newstate()
public static lua_State lua_open()
{
return luaL_newstate();
}
////#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX)
public static void lua_getregistry(lua_State L)
{
lua_pushvalue(L, LUA_REGISTRYINDEX);
}
////#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0)
public static int lua_getgccount(lua_State L)
{
return lua_gc(L, LUA_GCCOUNT, 0);
}
//#define lua_Chunkreader lua_Reader
//#define lua_Chunkwriter lua_Writer
/*
** {======================================================================
** Debug API
** =======================================================================
*/
/*
** Event codes
*/
public const int LUA_HOOKCALL = 0;
public const int LUA_HOOKRET = 1;
public const int LUA_HOOKLINE = 2;
public const int LUA_HOOKCOUNT = 3;
public const int LUA_HOOKTAILRET = 4;
/*
** Event masks
*/
public const int LUA_MASKCALL = (1 << LUA_HOOKCALL);
public const int LUA_MASKRET = (1 << LUA_HOOKRET);
public const int LUA_MASKLINE = (1 << LUA_HOOKLINE);
public const int LUA_MASKCOUNT = (1 << LUA_HOOKCOUNT);
/* Functions to be called by the debuger in specific events */
public delegate void lua_Hook(lua_State L, lua_Debug ar);
public class lua_Debug {
public int event_;
public CharPtr name; /* (n) */
public CharPtr namewhat; /* (n) `global', `local', `field', `method' */
public CharPtr what; /* (S) `Lua', `C', `main', `tail' */
public CharPtr source; /* (S) */
public int currentline; /* (l) */
public int nups; /* (u) number of upvalues */
public int linedefined; /* (S) */
public int lastlinedefined; /* (S) */
public CharPtr short_src = new char[LUA_IDSIZE]; /* (S) */
/* private part */
public int i_ci; /* active function */
};
/* }====================================================================== */
/******************************************************************************
* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
}
}
/*
** $Id: luaconf.h,v 1.82.1.7 2008/02/11 16:25:08 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using AT.MIN;
namespace KopiLua
{
using LUA_INTEGER = System.Int32;
using LUA_NUMBER = System.Double;
using LUAI_UACNUMBER = System.Double;
using LUA_INTFRM_T = System.Int64;
using TValue = Lua.lua_TValue;
using lua_Number = System.Double;
using System.Globalization;
public partial class Lua
{
/*
** ==================================================================
** Search for "@@" to find all configurable definitions.
** ===================================================================
*/
/*
@@ LUA_ANSI controls the use of non-ansi features.
** CHANGE it (define it) if you want Lua to avoid the use of any
** non-ansi feature or library.
*/
//#if defined(__STRICT_ANSI__)
//#define LUA_ANSI
//#endif
//#if !defined(LUA_ANSI) && _WIN32
//#define LUA_WIN
//#endif
//#if defined(LUA_USE_LINUX)
//#define LUA_USE_POSIX
//#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
//#define LUA_USE_READLINE /* needs some extra libraries */
//#endif
//#if defined(LUA_USE_MACOSX)
//#define LUA_USE_POSIX
//#define LUA_DL_DYLD /* does not need extra library */
//#endif
/*
@@ LUA_USE_POSIX includes all functionallity listed as X/Open System
@* Interfaces Extension (XSI).
** CHANGE it (define it) if your system is XSI compatible.
*/
//#if defined(LUA_USE_POSIX)
//#define LUA_USE_MKSTEMP
//#define LUA_USE_ISATTY
//#define LUA_USE_POPEN
//#define LUA_USE_ULONGJMP
//#endif
/*
@@ LUA_PATH and LUA_CPATH are the names of the environment variables that
@* Lua check to set its paths.
@@ LUA_INIT is the name of the environment variable that Lua
@* checks for initialization code.
** CHANGE them if you want different names.
*/
public const string LUA_PATH = "LUA_PATH";
public const string LUA_CPATH = "LUA_CPATH";
public const string LUA_INIT = "LUA_INIT";
/*
@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
@* Lua libraries.
@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
@* C libraries.
** CHANGE them if your machine has a non-conventional directory
** hierarchy or if you want to install your libraries in
** non-conventional directories.
*/
#if _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.
*/
public const string LUA_LDIR = "!\\lua\\";
public const string LUA_CDIR = "!\\";
public const string LUA_PATH_DEFAULT =
".\\?.lua;" + LUA_LDIR + "?.lua;" + LUA_LDIR + "?\\init.lua;"
+ LUA_CDIR + "?.lua;" + LUA_CDIR + "?\\init.lua";
public const string LUA_CPATH_DEFAULT =
".\\?.dll;" + LUA_CDIR + "?.dll;" + LUA_CDIR + "loadall.dll";
#else
public const string LUA_ROOT = "/usr/local/";
public const string LUA_LDIR = LUA_ROOT + "share/lua/5.1/";
public const string LUA_CDIR = LUA_ROOT + "lib/lua/5.1/";
public const string LUA_PATH_DEFAULT =
"./?.lua;" + LUA_LDIR + "?.lua;" + LUA_LDIR + "?/init.lua;" +
LUA_CDIR + "?.lua;" + LUA_CDIR + "?/init.lua";
public const string LUA_CPATH_DEFAULT =
"./?.so;" + LUA_CDIR + "?.so;" + LUA_CDIR + "loadall.so";
#endif
/*
@@ LUA_DIRSEP is the directory separator (for submodules).
** CHANGE it if your machine does not use "/" as the directory separator
** and is not Windows. (On Windows Lua automatically uses "\".)
*/
#if _WIN32
public const string LUA_DIRSEP = "\\";
#else
public const string LUA_DIRSEP = "/";
#endif
/*
@@ LUA_PATHSEP is the character that separates templates in a path.
@@ LUA_PATH_MARK is the string that marks the substitution points in a
@* template.
@@ LUA_EXECDIR in a Windows path is replaced by the executable's
@* directory.
@@ LUA_IGMARK is a mark to ignore all before it when bulding the
@* luaopen_ function name.
** CHANGE them if for some reason your system cannot use those
** characters. (E.g., if one of those characters is a common character
** in file/directory names.) Probably you do not need to change them.
*/
public const string LUA_PATHSEP = ";";
public const string LUA_PATH_MARK = "?";
public const string LUA_EXECDIR = "!";
public const string LUA_IGMARK = "-";
/*
@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger.
** CHANGE that if ptrdiff_t is not adequate on your machine. (On most
** machines, ptrdiff_t gives a good choice between int or long.)
*/
//#define LUA_INTEGER ptrdiff_t
/*
@@ LUA_API is a mark for all core API functions.
@@ LUALIB_API is a mark for all standard library functions.
** CHANGE them if you need to define those functions in some special way.
** For instance, if you want to create one Windows DLL with the core and
** the libraries, you may want to use the following definition (define
** LUA_BUILD_AS_DLL to get it).
*/
//#if LUA_BUILD_AS_DLL
//#if defined(LUA_CORE) || defined(LUA_LIB)
//#define LUA_API __declspec(dllexport)
//#else
//#define LUA_API __declspec(dllimport)
//#endif
//#else
//#define LUA_API extern
//#endif
/* more often than not the libs go together with the core */
//#define LUALIB_API LUA_API
/*
@@ LUAI_FUNC is a mark for all extern functions that are not to be
@* exported to outside modules.
@@ LUAI_DATA is a mark for all extern (const) variables that are not to
@* be exported to outside modules.
** CHANGE them if you need to mark them in some special way. Elf/gcc
** (versions 3.2 and later) mark them as "hidden" to optimize access
** when Lua is compiled as a shared library.
*/
//#if defined(luaall_c)
//#define LUAI_FUNC static
//#define LUAI_DATA /* empty */
//#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
// defined(__ELF__)
//#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
//#define LUAI_DATA LUAI_FUNC
//#else
//#define LUAI_FUNC extern
//#define LUAI_DATA extern
//#endif
/*
@@ LUA_QL describes how error messages quote program elements.
** CHANGE it if you want a different appearance.
*/
public static CharPtr LUA_QL(string x) {return "'" + x + "'";}
public static CharPtr LUA_QS {get {return LUA_QL("%s"); }}
/*
@@ LUA_IDSIZE gives the maximum size for the description of the source
@* of a function in debug information.
** CHANGE it if you want a different size.
*/
public const int LUA_IDSIZE = 60;
/*
** {==================================================================
** Stand-alone configuration
** ===================================================================
*/
//#if lua_c || luaall_c
/*
@@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that
@* is, whether we're running lua interactively).
** CHANGE it if you have a better definition for non-POSIX/non-Windows
** systems.
*/
#if LUA_USE_ISATTY
//#include <unistd.h>
//#define lua_stdin_is_tty() isatty(0)
#elif LUA_WIN
//#include <io.h>
//#include <stdio.h>
//#define lua_stdin_is_tty() _isatty(_fileno(stdin))
#else
public static int lua_stdin_is_tty() { return 1; } /* assume stdin is a tty */
#endif
/*
@@ LUA_PROMPT is the default prompt used by stand-alone Lua.
@@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua.
** CHANGE them if you want different prompts. (You can also change the
** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.)
*/
public const string LUA_PROMPT = "> ";
public const string LUA_PROMPT2 = ">> ";
/*
@@ LUA_PROGNAME is the default name for the stand-alone Lua program.
** CHANGE it if your stand-alone interpreter has a different name and
** your system is not able to detect that name automatically.
*/
public const string LUA_PROGNAME = "lua";
/*
@@ LUA_MAXINPUT is the maximum length for an input line in the
@* stand-alone interpreter.
** CHANGE it if you need longer lines.
*/
public const int LUA_MAXINPUT = 512;
/*
@@ lua_readline defines how to show a prompt and then read a line from
@* the standard input.
@@ lua_saveline defines how to "save" a read line in a "history".
@@ lua_freeline defines how to free a line read by lua_readline.
** CHANGE them if you want to improve this functionality (e.g., by using
** GNU readline and history facilities).
*/
#if LUA_USE_READLINE
//#include <stdio.h>
//#include <readline/readline.h>
//#include <readline/history.h>
//#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != null)
//#define lua_saveline(L,idx) \
// if (lua_strlen(L,idx) > 0) /* non-empty line? */ \
// add_history(lua_tostring(L, idx)); /* add it to history */
//#define lua_freeline(L,b) ((void)L, free(b))
#else
public static bool lua_readline(lua_State L, CharPtr b, CharPtr p)
{
fputs(p, stdout);
fflush(stdout); /* show prompt */
return (fgets(b, stdin) != null); /* get line */
}
public static void lua_saveline(lua_State L, int idx) {}
public static void lua_freeline(lua_State L, CharPtr b) {}
#endif
//#endif
/* }================================================================== */
/*
@@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles
@* as a percentage.
** CHANGE it if you want the GC to run faster or slower (higher values
** mean larger pauses which mean slower collection.) You can also change
** this value dynamically.
*/
public const int LUAI_GCPAUSE = 200; /* 200% (wait memory to double before next GC) */
/*
@@ LUAI_GCMUL defines the default speed of garbage collection relative to
@* memory allocation as a percentage.
** CHANGE it if you want to change the granularity of the garbage
** collection. (Higher values mean coarser collections. 0 represents
** infinity, where each step performs a full collection.) You can also
** change this value dynamically.
*/
public const int LUAI_GCMUL = 200; /* GC runs 'twice the speed' of memory allocation */
/*
@@ LUA_COMPAT_GETN controls compatibility with old getn behavior.
** CHANGE it (define it) if you want exact compatibility with the
** behavior of setn/getn in Lua 5.0.
*/
//#undef LUA_COMPAT_GETN /* dotnet port doesn't define in the first place */
/*
@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib.
** CHANGE it to undefined as soon as you do not need a global 'loadlib'
** function (the function is still available as 'package.loadlib').
*/
//#undef LUA_COMPAT_LOADLIB /* dotnet port doesn't define in the first place */
/*
@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature.
** CHANGE it to undefined as soon as your programs use only '...' to
** access vararg parameters (instead of the old 'arg' table).
*/
//#define LUA_COMPAT_VARARG /* defined higher up */
/*
@@ LUA_COMPAT_MOD controls compatibility with old math.mod function.
** CHANGE it to undefined as soon as your programs use 'math.fmod' or
** the new '%' operator instead of 'math.mod'.
*/
//#define LUA_COMPAT_MOD /* defined higher up */
/*
@@ LUA_COMPAT_LSTR controls compatibility with old long string nesting
@* facility.
** CHANGE it to 2 if you want the old behaviour, or undefine it to turn
** off the advisory error when nesting [[...]].
*/
//#define LUA_COMPAT_LSTR 1
//#define LUA_COMPAT_LSTR /* defined higher up */
/*
@@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name.
** CHANGE it to undefined as soon as you rename 'string.gfind' to
** 'string.gmatch'.
*/
//#define LUA_COMPAT_GFIND /* defined higher up */
/*
@@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib'
@* behavior.
** CHANGE it to undefined as soon as you replace to 'luaL_register'
** your uses of 'luaL_openlib'
*/
//#define LUA_COMPAT_OPENLIB /* defined higher up */
/*
@@ luai_apicheck is the assert macro used by the Lua-C API.
** CHANGE luai_apicheck if you want Lua to perform some checks in the
** parameters it gets from API calls. This may slow down the interpreter
** a bit, but may be quite useful when debugging C code that interfaces
** with Lua. A useful redefinition is to use assert.h.
*/
#if LUA_USE_APICHECK
public static void luai_apicheck(lua_State L, bool o) {Debug.Assert(o);}
public static void luai_apicheck(lua_State L, int o) {Debug.Assert(o != 0);}
#else
public static void luai_apicheck(lua_State L, bool o) {}
public static void luai_apicheck(lua_State L, int o) { }
#endif
/*
@@ LUAI_BITSINT defines the number of bits in an int.
** CHANGE here if Lua cannot automatically detect the number of bits of
** your machine. Probably you do not need to change this.
*/
/* avoid overflows in comparison */
//#if INT_MAX-20 < 32760
//public const int LUAI_BITSINT = 16
//#elif INT_MAX > 2147483640L
/* int has at least 32 bits */
public const int LUAI_BITSINT = 32;
//#else
//#error "you must define LUA_BITSINT with number of bits in an integer"
//#endif
/*
@@ LUAI_UINT32 is an unsigned integer with at least 32 bits.
@@ LUAI_INT32 is an signed integer with at least 32 bits.
@@ LUAI_UMEM is an unsigned integer big enough to count the total
@* memory used by Lua.
@@ LUAI_MEM is a signed integer big enough to count the total memory
@* used by Lua.
** CHANGE here if for some weird reason the default definitions are not
** good enough for your machine. (The definitions in the 'else'
** part always works, but may waste space on machines with 64-bit
** longs.) Probably you do not need to change this.
*/
//#if LUAI_BITSINT >= 32
//#define LUAI_UINT32 unsigned int
//#define LUAI_INT32 int
//#define LUAI_MAXINT32 INT_MAX
//#define LUAI_UMEM uint
//#define LUAI_MEM ptrdiff_t
//#else
///* 16-bit ints */
//#define LUAI_UINT32 unsigned long
//#define LUAI_INT32 long
//#define LUAI_MAXINT32 LONG_MAX
//#define LUAI_UMEM unsigned long
//#define LUAI_MEM long
//#endif
/*
@@ LUAI_MAXCALLS limits the number of nested calls.
** CHANGE it if you need really deep recursive calls. This limit is
** arbitrary; its only purpose is to stop infinite recursion before
** exhausting memory.
*/
public const int LUAI_MAXCALLS = 20000;
/*
@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function
@* can use.
** CHANGE it if you need lots of (Lua) stack space for your C
** functions. This limit is arbitrary; its only purpose is to stop C
** functions to consume unlimited stack space. (must be smaller than
** -LUA_REGISTRYINDEX)
*/
public const int LUAI_MAXCSTACK = 8000;
/*
** {==================================================================
** CHANGE (to smaller values) the following definitions if your system
** has a small C stack. (Or you may want to change them to larger
** values if your system has a large C stack and these limits are
** too rigid for you.) Some of these constants control the size of
** stack-allocated arrays used by the compiler or the interpreter, while
** others limit the maximum number of recursive calls that the compiler
** or the interpreter can perform. Values too large may cause a C stack
** overflow for some forms of deep constructs.
** ===================================================================
*/
/*
@@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and
@* syntactical nested non-terminals in a program.
*/
public const int LUAI_MAXCCALLS = 200;
/*
@@ LUAI_MAXVARS is the maximum number of local variables per function
@* (must be smaller than 250).
*/
public const int LUAI_MAXVARS = 200;
/*
@@ LUAI_MAXUPVALUES is the maximum number of upvalues per function
@* (must be smaller than 250).
*/
public const int LUAI_MAXUPVALUES = 60;
/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
*/
public const int LUAL_BUFFERSIZE = 1024; // BUFSIZ; todo: check this - mjf
/* }================================================================== */
/*
** {==================================================================
@@ LUA_NUMBER is the type of numbers in Lua.
** CHANGE the following definitions only if you want to build Lua
** with a number type different from double. You may also need to
** change lua_number2int & lua_number2integer.
** ===================================================================
*/
//#define LUA_NUMBER_DOUBLE
//#define LUA_NUMBER double /* declared in dotnet build with using statement */
/*
@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
@* over a number.
*/
//#define LUAI_UACNUMBER double /* declared in dotnet build with using statement */
/*
@@ LUA_NUMBER_SCAN is the format for reading numbers.
@@ LUA_NUMBER_FMT is the format for writing numbers.
@@ lua_number2str converts a number to a string.
@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion.
@@ lua_str2number converts a string to a number.
*/
public const string LUA_NUMBER_SCAN = "%lf";
public const string LUA_NUMBER_FMT = "%.14g";
public static CharPtr lua_number2str(double n) { return String.Format("{0}", n); }
public const int LUAI_MAXNUMBER2STR = 32; /* 16 digits, sign, point, and \0 */
private const string number_chars = "0123456789+-eE.";
public static double lua_str2number(CharPtr s, out CharPtr end)
{
end = new CharPtr(s.chars, s.index);
string str = "";
while (end[0] == ' ')
end = end.next();
while (number_chars.IndexOf(end[0]) >= 0)
{
str += end[0];
end = end.next();
}
try
{
return Convert.ToDouble(str.ToString(), Culture("en-US"));
}
catch (System.OverflowException)
{
// this is a hack, fix it - mjf
if (str[0] == '-')
return System.Double.NegativeInfinity;
else
return System.Double.PositiveInfinity;
}
catch
{
end = new CharPtr(s.chars, s.index);
return 0;
}
}
private static IFormatProvider Culture(string p)
{
#if SILVERLIGHT
return new CultureInfo(p);
#else
return CultureInfo.GetCultureInfo(p);
#endif
}
/*
@@ The luai_num* macros define the primitive operations over numbers.
*/
#if LUA_CORE
//#include <math.h>
public delegate lua_Number op_delegate(lua_Number a, lua_Number b);
public static lua_Number luai_numadd(lua_Number a, lua_Number b) { return ((a) + (b)); }
public static lua_Number luai_numsub(lua_Number a, lua_Number b) { return ((a) - (b)); }
public static lua_Number luai_nummul(lua_Number a, lua_Number b) { return ((a) * (b)); }
public static lua_Number luai_numdiv(lua_Number a, lua_Number b) { return ((a) / (b)); }
public static lua_Number luai_nummod(lua_Number a, lua_Number b) { return ((a) - Math.Floor((a) / (b)) * (b)); }
public static lua_Number luai_numpow(lua_Number a, lua_Number b) { return (Math.Pow(a, b)); }
public static lua_Number luai_numunm(lua_Number a) { return (-(a)); }
public static bool luai_numeq(lua_Number a, lua_Number b) { return ((a) == (b)); }
public static bool luai_numlt(lua_Number a, lua_Number b) { return ((a) < (b)); }
public static bool luai_numle(lua_Number a, lua_Number b) { return ((a) <= (b)); }
public static bool luai_numisnan(lua_Number a) { return lua_Number.IsNaN(a); }
#endif
/*
@@ lua_number2int is a macro to convert lua_Number to int.
@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
** CHANGE them if you know a faster way to convert a lua_Number to
** int (with any rounding method and without throwing errors) in your
** system. In Pentium machines, a naive typecast from double to int
** in C is extremely slow, so any alternative is worth trying.
*/
/* On a Pentium, resort to a trick */
//#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
// (defined(__i386) || defined (_M_IX86) || defined(__i386__))
/* On a Microsoft compiler, use assembler */
//#if defined(_MSC_VER)
//#define lua_number2int(i,d) __asm fld d __asm fistp i
//#define lua_number2integer(i,n) lua_number2int(i, n)
/* the next trick should work on any Pentium, but sometimes clashes
with a DirectX idiosyncrasy */
//#else
//union luai_Cast { double l_d; long l_l; };
//#define lua_number2int(i,d) \
// { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
//#define lua_number2integer(i,n) lua_number2int(i, n)
//#endif
/* this option always works, but may be slow */
//#else
//#define lua_number2int(i,d) ((i)=(int)(d))
//#define lua_number2integer(i,d) ((i)=(lua_Integer)(d))
//#endif
private static void lua_number2int(out int i,lua_Number d) {i = (int)d;}
private static void lua_number2integer(out int i, lua_Number n) { i = (int)n; }
/* }================================================================== */
/*
@@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment.
** CHANGE it if your system requires alignments larger than double. (For
** instance, if your system supports long doubles and they must be
** aligned in 16-byte boundaries, then you should add long double in the
** union.) Probably you do not need to change this.
*/
//#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; }
public class LuaException : Exception
{
public lua_State L;
public lua_longjmp c;
public LuaException(lua_State L, lua_longjmp c) { this.L = L; this.c = c; }
}
/*
@@ LUAI_THROW/LUAI_TRY define how Lua does exception handling.
** CHANGE them if you prefer to use longjmp/setjmp even with C++
** or if want/don't to use _longjmp/_setjmp instead of regular
** longjmp/setjmp. By default, Lua handles errors with exceptions when
** compiling as C++ code, with _longjmp/_setjmp when asked to use them,
** and with longjmp/setjmp otherwise.
*/
//#if defined(__cplusplus)
///* C++ exceptions */
public static void LUAI_THROW(lua_State L, lua_longjmp c) {throw new LuaException(L, c);}
//#define LUAI_TRY(L,c,a) try { a } catch(...) \
// { if ((c).status == 0) (c).status = -1; }
public static void LUAI_TRY(lua_State L, lua_longjmp c, object a) {
if (c.status == 0) c.status = -1;
}
//#define luai_jmpbuf int /* dummy variable */
//#elif defined(LUA_USE_ULONGJMP)
///* in Unix, try _longjmp/_setjmp (more efficient) */
//#define LUAI_THROW(L,c) _longjmp((c).b, 1)
//#define LUAI_TRY(L,c,a) if (_setjmp((c).b) == 0) { a }
//#define luai_jmpbuf jmp_buf
//#else
///* default handling with long jumps */
//public static void LUAI_THROW(lua_State L, lua_longjmp c) { c.b(1); }
//#define LUAI_TRY(L,c,a) if (setjmp((c).b) == 0) { a }
//#define luai_jmpbuf jmp_buf
//#endif
/*
@@ LUA_MAXCAPTURES is the maximum number of captures that a pattern
@* can do during pattern-matching.
** CHANGE it if you need more captures. This limit is arbitrary.
*/
public const int LUA_MAXCAPTURES = 32;
/*
@@ lua_tmpnam is the function that the OS library uses to create a
@* temporary name.
@@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam.
** CHANGE them if you have an alternative to tmpnam (which is considered
** insecure) or if you want the original tmpnam anyway. By default, Lua
** uses tmpnam except when POSIX is available, where it uses mkstemp.
*/
#if loslib_c || luaall_c
#if LUA_USE_MKSTEMP
//#include <unistd.h>
public const int LUA_TMPNAMBUFSIZE = 32;
//#define lua_tmpnam(b,e) { \
// strcpy(b, "/tmp/lua_XXXXXX"); \
// e = mkstemp(b); \
// if (e != -1) close(e); \
// e = (e == -1); }
#else
public const int LUA_TMPNAMBUFSIZE = L_tmpnam;
public static void lua_tmpnam(CharPtr b, int e) { e = (tmpnam(b) == null) ? 1 : 0; }
#endif
#endif
/*
@@ lua_popen spawns a new process connected to the current one through
@* the file streams.
** CHANGE it if you have a way to implement it in your system.
*/
//#if LUA_USE_POPEN
//#define lua_popen(L,c,m) ((void)L, fflush(null), popen(c,m))
//#define lua_pclose(L,file) ((void)L, (pclose(file) != -1))
//#elif LUA_WIN
//#define lua_popen(L,c,m) ((void)L, _popen(c,m))
//#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1))
//#else
public static Stream lua_popen(lua_State L, CharPtr c, CharPtr m) { luaL_error(L, LUA_QL("popen") + " not supported"); return null; }
public static int lua_pclose(lua_State L, Stream file) { return 0; }
//#endif
/*
@@ LUA_DL_* define which dynamic-library system Lua should use.
** CHANGE here if Lua has problems choosing the appropriate
** dynamic-library system for your platform (either Windows' DLL, Mac's
** dyld, or Unix's dlopen). If your system is some kind of Unix, there
** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for
** it. To use dlopen you also need to adapt the src/Makefile (probably
** adding -ldl to the linker options), so Lua does not select it
** automatically. (When you change the makefile to add -ldl, you must
** also add -DLUA_USE_DLOPEN.)
** If you do not want any kind of dynamic library, undefine all these
** options.
** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD.
*/
//#if LUA_USE_DLOPEN
//#define LUA_DL_DLOPEN
//#endif
//#if LUA_WIN
//#define LUA_DL_DLL
//#endif
/*
@@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State
@* (the data goes just *before* the lua_State pointer).
** CHANGE (define) this if you really need that. This value must be
** a multiple of the maximum alignment required for your machine.
*/
public const int LUAI_EXTRASPACE = 0;
/*
@@ luai_userstate* allow user-specific actions on threads.
** CHANGE them if you defined LUAI_EXTRASPACE and need to do something
** extra when a thread is created/deleted/resumed/yielded.
*/
public static void luai_userstateopen(lua_State L) {}
public static void luai_userstateclose(lua_State L) {}
public static void luai_userstatethread(lua_State L, lua_State L1) {}
public static void luai_userstatefree(lua_State L) {}
public static void luai_userstateresume(lua_State L,int n) {}
public static void luai_userstateyield(lua_State L,int n) {}
/*
@@ LUA_INTFRMLEN is the length modifier for integer conversions
@* in 'string.format'.
@@ LUA_INTFRM_T is the integer type correspoding to the previous length
@* modifier.
** CHANGE them if your system supports long long or does not support long.
*/
#if LUA_USELONGLONG
public const string LUA_INTFRMLEN = "ll";
//#define LUA_INTFRM_T long long
#else
public const string LUA_INTFRMLEN = "l";
//#define LUA_INTFRM_T long /* declared in dotnet build with using statement */
#endif
/* =================================================================== */
/*
** Local configuration. You can use this space to add your redefinitions
** without modifying the main part of the file.
*/
// misc stuff needed for the compile
public static bool isalpha(char c) { return Char.IsLetter(c); }
public static bool iscntrl(char c) { return Char.IsControl(c); }
public static bool isdigit(char c) { return Char.IsDigit(c); }
public static bool islower(char c) { return Char.IsLower(c); }
public static bool ispunct(char c) { return Char.IsPunctuation(c); }
public static bool isspace(char c) { return (c==' ') || (c>=(char)0x09 && c<=(char)0x0D); }
public static bool isupper(char c) { return Char.IsUpper(c); }
public static bool isalnum(char c) { return Char.IsLetterOrDigit(c); }
public static bool isxdigit(char c) { return "0123456789ABCDEFabcdef".IndexOf(c) >= 0; }
public static bool isalpha(int c) { return Char.IsLetter((char)c); }
public static bool iscntrl(int c) { return Char.IsControl((char)c); }
public static bool isdigit(int c) { return Char.IsDigit((char)c); }
public static bool islower(int c) { return Char.IsLower((char)c); }
public static bool ispunct(int c) { return ((char)c != ' ') && !isalnum((char)c); } // *not* the same as Char.IsPunctuation
public static bool isspace(int c) { return ((char)c == ' ') || ((char)c >= (char)0x09 && (char)c <= (char)0x0D); }
public static bool isupper(int c) { return Char.IsUpper((char)c); }
public static bool isalnum(int c) { return Char.IsLetterOrDigit((char)c); }
public static char tolower(char c) { return Char.ToLower(c); }
public static char toupper(char c) { return Char.ToUpper(c); }
public static char tolower(int c) { return Char.ToLower((char)c); }
public static char toupper(int c) { return Char.ToUpper((char)c); }
public static ulong strtoul(CharPtr s, out CharPtr end, int base_)
{
try
{
end = new CharPtr(s.chars, s.index);
// skip over any leading whitespace
while (end[0] == ' ')
end = end.next();
// ignore any leading 0x
if ((end[0] == '0') && (end[1] == 'x'))
end = end.next().next();
else if ((end[0] == '0') && (end[1] == 'X'))
end = end.next().next();
// do we have a leading + or - sign?
bool negate = false;
if (end[0] == '+')
end = end.next();
else if (end[0] == '-')
{
negate = true;
end = end.next();
}
// loop through all chars
bool invalid = false;
bool had_digits = false;
ulong result = 0;
while (true)
{
// get this char
char ch = end[0];
// which digit is this?
int this_digit = 0;
if (isdigit(ch))
this_digit = ch - '0';
else if (isalpha(ch))
this_digit = tolower(ch) - 'a' + 10;
else
break;
// is this digit valid?
if (this_digit >= base_)
invalid = true;
else
{
had_digits = true;
result = result * (ulong)base_ + (ulong)this_digit;
}
end = end.next();
}
// were any of the digits invalid?
if (invalid || (!had_digits))
{
end = s;
return System.UInt64.MaxValue;
}
// if the value was a negative then negate it here
if (negate)
result = (ulong)-(long)result;
// ok, we're done
return (ulong)result;
}
catch
{
end = s;
return 0;
}
}
public static void putchar(char ch)
{
Console.Write(ch);
}
public static void putchar(int ch)
{
Console.Write((char)ch);
}
public static bool isprint(byte c)
{
return (c >= (byte)' ') && (c <= (byte)127);
}
public static int parse_scanf(string str, CharPtr fmt, params object[] argp)
{
int parm_index = 0;
int index = 0;
while (fmt[index] != 0)
{
if (fmt[index++]=='%')
switch (fmt[index++])
{
case 's':
{
argp[parm_index++] = str;
break;
}
case 'c':
{
argp[parm_index++] = Convert.ToChar(str, Culture("en-US"));
break;
}
case 'd':
{
argp[parm_index++] = Convert.ToInt32(str, Culture("en-US"));
break;
}
case 'l':
{
argp[parm_index++] = Convert.ToDouble(str, Culture("en-US"));
break;
}
case 'f':
{
argp[parm_index++] = Convert.ToDouble(str, Culture("en-US"));
break;
}
//case 'p':
// {
// result += "(pointer)";
// break;
// }
}
}
return parm_index;
}
public static void printf(CharPtr str, params object[] argv)
{
Tools.printf(str.ToString(), argv);
}
public static void sprintf(CharPtr buffer, CharPtr str, params object[] argv)
{
string temp = Tools.sprintf(str.ToString(), argv);
strcpy(buffer, temp);
}
public static int fprintf(Stream stream, CharPtr str, params object[] argv)
{
string result = Tools.sprintf(str.ToString(), argv);
char[] chars = result.ToCharArray();
byte[] bytes = new byte[chars.Length];
for (int i=0; i<chars.Length; i++)
bytes[i] = (byte)chars[i];
stream.Write(bytes, 0, bytes.Length);
return 1;
}
public const int EXIT_SUCCESS = 0;
public const int EXIT_FAILURE = 1;
public static int errno()
{
return -1; // todo: fix this - mjf
}
public static CharPtr strerror(int error)
{
return String.Format("error #{0}", error); // todo: check how this works - mjf
}
public static CharPtr getenv(CharPtr envname)
{
// todo: fix this - mjf
//if (envname == "LUA_PATH)
//return "MyPath";
return null;
}
public class CharPtr
{
public char[] chars;
public int index;
public char this[int offset]
{
get { return chars[index + offset]; }
set { chars[index + offset] = value; }
}
public char this[uint offset]
{
get { return chars[index + offset]; }
set { chars[index + offset] = value; }
}
public char this[long offset]
{
get { return chars[index + (int)offset]; }
set { chars[index + (int)offset] = value; }
}
public static implicit operator CharPtr(string str) { return new CharPtr(str); }
public static implicit operator CharPtr(char[] chars) { return new CharPtr(chars); }
public CharPtr()
{
this.chars = null;
this.index = 0;
}
public CharPtr(string str)
{
this.chars = (str + '\0').ToCharArray();
this.index = 0;
}
public CharPtr(CharPtr ptr)
{
this.chars = ptr.chars;
this.index = ptr.index;
}
public CharPtr(CharPtr ptr, int index)
{
this.chars = ptr.chars;
this.index = index;
}
public CharPtr(char[] chars)
{
this.chars = chars;
this.index = 0;
}
public CharPtr(char[] chars, int index)
{
this.chars = chars;
this.index = index;
}
public CharPtr(IntPtr ptr)
{
this.chars = new char[0];
this.index = 0;
}
public static CharPtr operator +(CharPtr ptr, int offset) {return new CharPtr(ptr.chars, ptr.index+offset);}
public static CharPtr operator -(CharPtr ptr, int offset) {return new CharPtr(ptr.chars, ptr.index-offset);}
public static CharPtr operator +(CharPtr ptr, uint offset) { return new CharPtr(ptr.chars, ptr.index + (int)offset); }
public static CharPtr operator -(CharPtr ptr, uint offset) { return new CharPtr(ptr.chars, ptr.index - (int)offset); }
public void inc() { this.index++; }
public void dec() { this.index--; }
public CharPtr next() { return new CharPtr(this.chars, this.index + 1); }
public CharPtr prev() { return new CharPtr(this.chars, this.index - 1); }
public CharPtr add(int ofs) { return new CharPtr(this.chars, this.index + ofs); }
public CharPtr sub(int ofs) { return new CharPtr(this.chars, this.index - ofs); }
public static bool operator ==(CharPtr ptr, char ch) { return ptr[0] == ch; }
public static bool operator ==(char ch, CharPtr ptr) { return ptr[0] == ch; }
public static bool operator !=(CharPtr ptr, char ch) { return ptr[0] != ch; }
public static bool operator !=(char ch, CharPtr ptr) { return ptr[0] != ch; }
public static CharPtr operator +(CharPtr ptr1, CharPtr ptr2)
{
string result = "";
for (int i = 0; ptr1[i] != '\0'; i++)
result += ptr1[i];
for (int i = 0; ptr2[i] != '\0'; i++)
result += ptr2[i];
return new CharPtr(result);
}
public static int operator -(CharPtr ptr1, CharPtr ptr2) {
Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index - ptr2.index; }
public static bool operator <(CharPtr ptr1, CharPtr ptr2) {
Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index < ptr2.index; }
public static bool operator <=(CharPtr ptr1, CharPtr ptr2) {
Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index <= ptr2.index; }
public static bool operator >(CharPtr ptr1, CharPtr ptr2) {
Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index > ptr2.index; }
public static bool operator >=(CharPtr ptr1, CharPtr ptr2) {
Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index >= ptr2.index; }
public static bool operator ==(CharPtr ptr1, CharPtr ptr2) {
object o1 = ptr1 as CharPtr;
object o2 = ptr2 as CharPtr;
if ((o1 == null) && (o2 == null)) return true;
if (o1 == null) return false;
if (o2 == null) return false;
return (ptr1.chars == ptr2.chars) && (ptr1.index == ptr2.index); }
public static bool operator !=(CharPtr ptr1, CharPtr ptr2) {return !(ptr1 == ptr2); }
public override bool Equals(object o)
{
return this == (o as CharPtr);
}
public override int GetHashCode()
{
return 0;
}
public override string ToString()
{
string result = "";
for (int i = index; (i<chars.Length) && (chars[i] != '\0'); i++)
result += chars[i];
return result;
}
}
public static int memcmp(CharPtr ptr1, CharPtr ptr2, uint size) { return memcmp(ptr1, ptr2, (int)size); }
public static int memcmp(CharPtr ptr1, CharPtr ptr2, int size)
{
for (int i=0; i<size; i++)
if (ptr1[i]!=ptr2[i])
{
if (ptr1[i]<ptr2[i])
return -1;
else
return 1;
}
return 0;
}
public static CharPtr memchr(CharPtr ptr, char c, uint count)
{
for (uint i = 0; i < count; i++)
if (ptr[i] == c)
return new CharPtr(ptr.chars, (int)(ptr.index + i));
return null;
}
public static CharPtr strpbrk(CharPtr str, CharPtr charset)
{
for (int i=0; str[i] != '\0'; i++)
for (int j = 0; charset[j] != '\0'; j++)
if (str[i] == charset[j])
return new CharPtr(str.chars, str.index + i);
return null;
}
// find c in str
public static CharPtr strchr(CharPtr str, char c)
{
for (int index = str.index; str.chars[index] != 0; index++)
if (str.chars[index] == c)
return new CharPtr(str.chars, index);
return null;
}
public static CharPtr strcpy(CharPtr dst, CharPtr src)
{
int i;
for (i = 0; src[i] != '\0'; i++)
dst[i] = src[i];
dst[i] = '\0';
return dst;
}
public static CharPtr strcat(CharPtr dst, CharPtr src)
{
int dst_index = 0;
while (dst[dst_index] != '\0')
dst_index++;
int src_index = 0;
while (src[src_index] != '\0')
dst[dst_index++] = src[src_index++];
dst[dst_index++] = '\0';
return dst;
}
public static CharPtr strncat(CharPtr dst, CharPtr src, int count)
{
int dst_index = 0;
while (dst[dst_index] != '\0')
dst_index++;
int src_index = 0;
while ((src[src_index] != '\0') && (count-- > 0))
dst[dst_index++] = src[src_index++];
return dst;
}
public static uint strcspn(CharPtr str, CharPtr charset)
{
int index = str.ToString().IndexOfAny(charset.ToString().ToCharArray());
if (index < 0)
index = str.ToString().Length;
return (uint)index;
}
public static CharPtr strncpy(CharPtr dst, CharPtr src, int length)
{
int index = 0;
while ((src[index] != '\0') && (index<length))
{
dst[index] = src[index];
index++;
}
while (index < length)
dst[index++] = '\0';
return dst;
}
public static int strlen(CharPtr str)
{
int index = 0;
while (str[index] != '\0')
index++;
return index;
}
public static lua_Number fmod(lua_Number a, lua_Number b)
{
float quotient = (int)Math.Floor(a / b);
return a - quotient * b;
}
public static lua_Number modf(lua_Number a, out lua_Number b)
{
b = Math.Floor(a);
return a - Math.Floor(a);
}
public static long lmod(lua_Number a, lua_Number b)
{
return (long)a % (long)b;
}
public static int getc(Stream f)
{
return f.ReadByte();
}
public static void ungetc(int c, Stream f)
{
if (f.Position > 0)
f.Seek(-1, SeekOrigin.Current);
}
#if XBOX || SILVERLIGHT
public static Stream stdout;
public static Stream stdin;
public static Stream stderr;
#else
public static Stream stdout = Console.OpenStandardOutput();
public static Stream stdin = Console.OpenStandardInput();
public static Stream stderr = Console.OpenStandardError();
#endif
public static int EOF = -1;
public static void fputs(CharPtr str, Stream stream)
{
Console.Write(str.ToString());
}
public static int feof(Stream s)
{
return (s.Position >= s.Length) ? 1 : 0;
}
public static int fread(CharPtr ptr, int size, int num, Stream stream)
{
int num_bytes = num * size;
byte[] bytes = new byte[num_bytes];
try
{
int result = stream.Read(bytes, 0, num_bytes);
for (int i = 0; i < result; i++)
ptr[i] = (char)bytes[i];
return result/size;
}
catch
{
return 0;
}
}
public static int fwrite(CharPtr ptr, int size, int num, Stream stream)
{
int num_bytes = num * size;
byte[] bytes = new byte[num_bytes];
for (int i = 0; i < num_bytes; i++)
bytes[i] = (byte)ptr[i];
try
{
stream.Write(bytes, 0, num_bytes);
}
catch
{
return 0;
}
return num;
}
public static int strcmp(CharPtr s1, CharPtr s2)
{
if (s1 == s2)
return 0;
if (s1 == null)
return -1;
if (s2 == null)
return 1;
for (int i = 0; ; i++)
{
if (s1[i] != s2[i])
{
if (s1[i] < s2[i])
return -1;
else
return 1;
}
if (s1[i] == '\0')
return 0;
}
}
public static CharPtr fgets(CharPtr str, Stream stream)
{
int index = 0;
try
{
while (true)
{
str[index] = (char)stream.ReadByte();
if (str[index] == '\n')
break;
if (index >= str.chars.Length)
break;
index++;
}
}
catch
{
}
return str;
}
public static double frexp(double x, out int expptr)
{
#if XBOX
expptr = (int)(Math.Log(x) / Math.Log(2)) + 1;
#else
expptr = (int)Math.Log(x, 2) + 1;
#endif
double s = x / Math.Pow(2, expptr);
return s;
}
public static double ldexp(double x, int expptr)
{
return x * Math.Pow(2, expptr);
}
public static CharPtr strstr(CharPtr str, CharPtr substr)
{
int index = str.ToString().IndexOf(substr.ToString());
if (index < 0)
return null;
return new CharPtr(str + index);
}
public static CharPtr strrchr(CharPtr str, char ch)
{
int index = str.ToString().LastIndexOf(ch);
if (index < 0)
return null;
return str + index;
}
public static Stream fopen(CharPtr filename, CharPtr mode)
{
string str = filename.ToString();
FileMode filemode = FileMode.Open;
FileAccess fileaccess = (FileAccess)0;
for (int i=0; mode[i] != '\0'; i++)
switch (mode[i])
{
case 'r':
fileaccess = fileaccess | FileAccess.Read;
if (!File.Exists(str))
return null;
break;
case 'w':
filemode = FileMode.Create;
fileaccess = fileaccess | FileAccess.Write;
break;
}
try
{
return new FileStream(str, filemode, fileaccess);
}
catch
{
return null;
}
}
public static Stream freopen(CharPtr filename, CharPtr mode, Stream stream)
{
try
{
stream.Flush();
stream.Close();
}
catch { }
return fopen(filename, mode);
}
public static void fflush(Stream stream)
{
stream.Flush();
}
public static int ferror(Stream stream)
{
return 0; // todo: fix this - mjf
}
public static int fclose(Stream stream)
{
stream.Close();
return 0;
}
#if !XBOX
public static Stream tmpfile()
{
return new FileStream(Path.GetTempFileName(), FileMode.Create, FileAccess.ReadWrite);
}
#endif
public static int fscanf(Stream f, CharPtr format, params object[] argp)
{
string str = Console.ReadLine();
return parse_scanf(str, format, argp);
}
public static int fseek(Stream f, long offset, int origin)
{
try
{
f.Seek(offset, (SeekOrigin)origin);
return 0;
}
catch
{
return 1;
}
}
public static int ftell(Stream f)
{
return (int)f.Position;
}
public static int clearerr(Stream f)
{
//Debug.Assert(false, "clearerr not implemented yet - mjf");
return 0;
}
public static int setvbuf(Stream stream, CharPtr buffer, int mode, uint size)
{
Debug.Assert(false, "setvbuf not implemented yet - mjf");
return 0;
}
public static void memcpy<T>(T[] dst, T[] src, int length)
{
for (int i = 0; i < length; i++)
dst[i] = src[i];
}
public static void memcpy<T>(T[] dst, int offset, T[] src, int length)
{
for (int i=0; i<length; i++)
dst[offset+i] = src[i];
}
public static void memcpy<T>(T[] dst, T[] src, int srcofs, int length)
{
for (int i = 0; i < length; i++)
dst[i] = src[srcofs+i];
}
public static void memcpy(CharPtr ptr1, CharPtr ptr2, uint size) { memcpy(ptr1, ptr2, (int)size); }
public static void memcpy(CharPtr ptr1, CharPtr ptr2, int size)
{
for (int i = 0; i < size; i++)
ptr1[i] = ptr2[i];
}
public static object VOID(object f) { return f; }
public const double HUGE_VAL = System.Double.MaxValue;
public const uint SHRT_MAX = System.UInt16.MaxValue;
public const int _IONBF = 0;
public const int _IOFBF = 1;
public const int _IOLBF = 2;
public const int SEEK_SET = 0;
public const int SEEK_CUR = 1;
public const int SEEK_END = 2;
// one of the primary objectives of this port is to match the C version of Lua as closely as
// possible. a key part of this is also matching the behaviour of the garbage collector, as
// that affects the operation of things such as weak tables. in order for this to occur the
// size of structures that are allocated must be reported as identical to their C++ equivelents.
// that this means that variables such as global_State.totalbytes no longer indicate the true
// amount of memory allocated.
public static int GetUnmanagedSize(Type t)
{
if (t == typeof(global_State))
return 228;
else if (t == typeof(LG))
return 376;
else if (t == typeof(CallInfo))
return 24;
else if (t == typeof(lua_TValue))
return 16;
else if (t == typeof(Table))
return 32;
else if (t == typeof(Node))
return 32;
else if (t == typeof(GCObject))
return 120;
else if (t == typeof(GCObjectRef))
return 4;
else if (t == typeof(ArrayRef))
return 4;
else if (t == typeof(Closure))
return 0; // handle this one manually in the code
else if (t == typeof(Proto))
return 76;
else if (t == typeof(luaL_Reg))
return 8;
else if (t == typeof(luaL_Buffer))
return 524;
else if (t == typeof(lua_State))
return 120;
else if (t == typeof(lua_Debug))
return 100;
else if (t == typeof(CallS))
return 8;
else if (t == typeof(LoadF))
return 520;
else if (t == typeof(LoadS))
return 8;
else if (t == typeof(lua_longjmp))
return 72;
else if (t == typeof(SParser))
return 20;
else if (t == typeof(Token))
return 16;
else if (t == typeof(LexState))
return 52;
else if (t == typeof(FuncState))
return 572;
else if (t == typeof(GCheader))
return 8;
else if (t == typeof(lua_TValue))
return 16;
else if (t == typeof(TString))
return 16;
else if (t == typeof(LocVar))
return 12;
else if (t == typeof(UpVal))
return 32;
else if (t == typeof(CClosure))
return 40;
else if (t == typeof(LClosure))
return 24;
else if (t == typeof(TKey))
return 16;
else if (t == typeof(ConsControl))
return 40;
else if (t == typeof(LHS_assign))
return 32;
else if (t == typeof(expdesc))
return 24;
else if (t == typeof(upvaldesc))
return 2;
else if (t == typeof(BlockCnt))
return 12;
else if (t == typeof(Zio))
return 20;
else if (t == typeof(Mbuffer))
return 12;
else if (t == typeof(LoadState))
return 16;
else if (t == typeof(MatchState))
return 272;
else if (t == typeof(stringtable))
return 12;
else if (t == typeof(FilePtr))
return 4;
else if (t == typeof(Udata))
return 24;
else if (t == typeof(Char))
return 1;
else if (t == typeof(UInt16))
return 2;
else if (t == typeof(Int16))
return 2;
else if (t == typeof(UInt32))
return 4;
else if (t == typeof(Int32))
return 4;
else if (t == typeof(Single))
return 4;
Debug.Assert(false, "Trying to get unknown sized of unmanaged type " + t.ToString());
return 0;
}
}
}
/*
** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace KopiLua
{
public partial class Lua
{
/* Key to file-handle type */
public const string LUA_FILEHANDLE = "FILE*";
public const string LUA_COLIBNAME = "coroutine";
public const string LUA_TABLIBNAME = "table";
public const string LUA_IOLIBNAME = "io";
public const string LUA_OSLIBNAME = "os";
public const string LUA_STRLIBNAME = "string";
public const string LUA_MATHLIBNAME = "math";
public const string LUA_DBLIBNAME = "debug";
public const string LUA_LOADLIBNAME = "package";
}
}
/*
** $Id: lundump.c,v 2.7.1.4 2008/04/04 19:51:41 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
namespace KopiLua
{
using TValue = Lua.lua_TValue;
using lua_Number = System.Double;
using lu_byte = System.Byte;
using StkId = Lua.lua_TValue;
using Instruction = System.UInt32;
using ZIO = Lua.Zio;
public partial class Lua
{
/* for header of binary files -- this is Lua 5.1 */
public const int LUAC_VERSION = 0x51;
/* for header of binary files -- this is the official format */
public const int LUAC_FORMAT = 0;
/* size of header of binary files */
public const int LUAC_HEADERSIZE = 12;
public class LoadState{
public lua_State L;
public ZIO Z;
public Mbuffer b;
public CharPtr name;
};
//#ifdef LUAC_TRUST_BINARIES
//#define IF(c,s)
//#define error(S,s)
//#else
//#define IF(c,s) if (c) error(S,s)
public static void IF(int c, string s) { }
public static void IF(bool c, string s) { }
static void error(LoadState S, CharPtr why)
{
luaO_pushfstring(S.L,"%s: %s in precompiled chunk",S.name,why);
luaD_throw(S.L,LUA_ERRSYNTAX);
}
//#endif
public static object LoadMem(LoadState S, Type t)
{
int size = Marshal.SizeOf(t);
CharPtr str = new char[size];
LoadBlock(S, str, size);
byte[] bytes = new byte[str.chars.Length];
for (int i = 0; i < str.chars.Length; i++)
bytes[i] = (byte)str.chars[i];
GCHandle pinnedPacket = GCHandle.Alloc(bytes, GCHandleType.Pinned);
object b = Marshal.PtrToStructure(pinnedPacket.AddrOfPinnedObject(), t);
pinnedPacket.Free();
return b;
}
public static object LoadMem(LoadState S, Type t, int n)
{
#if SILVERLIGHT
List<object> array = new List<object>();
for (int i = 0; i < n; i++)
array.Add(LoadMem(S, t));
return array.ToArray();
#else
ArrayList array = new ArrayList();
for (int i=0; i<n; i++)
array.Add(LoadMem(S, t));
return array.ToArray(t);
#endif
}
public static lu_byte LoadByte(LoadState S) {return (lu_byte)LoadChar(S);}
public static object LoadVar(LoadState S, Type t) { return LoadMem(S, t); }
public static object LoadVector(LoadState S, Type t, int n) {return LoadMem(S, t, n);}
private static void LoadBlock(LoadState S, CharPtr b, int size)
{
uint r=luaZ_read(S.Z, b, (uint)size);
IF (r!=0, "unexpected end");
}
private static int LoadChar(LoadState S)
{
return (char)LoadVar(S, typeof(char));
}
private static int LoadInt(LoadState S)
{
int x = (int)LoadVar(S, typeof(int));
IF (x<0, "bad integer");
return x;
}
private static lua_Number LoadNumber(LoadState S)
{
return (lua_Number)LoadVar(S, typeof(lua_Number));
}
private static TString LoadString(LoadState S)
{
uint size = (uint)LoadVar(S, typeof(uint));
if (size==0)
return null;
else
{
CharPtr s=luaZ_openspace(S.L,S.b,size);
LoadBlock(S, s, (int)size);
return luaS_newlstr(S.L,s,size-1); /* remove trailing '\0' */
}
}
private static void LoadCode(LoadState S, Proto f)
{
int n=LoadInt(S);
f.code = luaM_newvector<Instruction>(S.L, n);
f.sizecode=n;
f.code = (Instruction[])LoadVector(S, typeof(Instruction), n);
}
private static void LoadConstants(LoadState S, Proto f)
{
int i,n;
n=LoadInt(S);
f.k = luaM_newvector<TValue>(S.L, n);
f.sizek=n;
for (i=0; i<n; i++) setnilvalue(f.k[i]);
for (i=0; i<n; i++)
{
TValue o=f.k[i];
int t=LoadChar(S);
switch (t)
{
case LUA_TNIL:
setnilvalue(o);
break;
case LUA_TBOOLEAN:
setbvalue(o, LoadChar(S));
break;
case LUA_TNUMBER:
setnvalue(o, LoadNumber(S));
break;
case LUA_TSTRING:
setsvalue2n(S.L, o, LoadString(S));
break;
default:
error(S,"bad constant");
break;
}
}
n=LoadInt(S);
f.p=luaM_newvector<Proto>(S.L,n);
f.sizep=n;
for (i=0; i<n; i++) f.p[i]=null;
for (i=0; i<n; i++) f.p[i]=LoadFunction(S,f.source);
}
private static void LoadDebug(LoadState S, Proto f)
{
int i,n;
n=LoadInt(S);
f.lineinfo=luaM_newvector<int>(S.L,n);
f.sizelineinfo=n;
f.lineinfo = (int[])LoadVector(S, typeof(int), n);
n=LoadInt(S);
f.locvars=luaM_newvector<LocVar>(S.L,n);
f.sizelocvars=n;
for (i=0; i<n; i++) f.locvars[i].varname=null;
for (i=0; i<n; i++)
{
f.locvars[i].varname=LoadString(S);
f.locvars[i].startpc=LoadInt(S);
f.locvars[i].endpc=LoadInt(S);
}
n=LoadInt(S);
f.upvalues=luaM_newvector<TString>(S.L, n);
f.sizeupvalues=n;
for (i=0; i<n; i++) f.upvalues[i]=null;
for (i=0; i<n; i++) f.upvalues[i]=LoadString(S);
}
private static Proto LoadFunction(LoadState S, TString p)
{
Proto f;
if (++S.L.nCcalls > LUAI_MAXCCALLS) error(S,"code too deep");
f=luaF_newproto(S.L);
setptvalue2s(S.L,S.L.top,f); incr_top(S.L);
f.source=LoadString(S); if (f.source==null) f.source=p;
f.linedefined=LoadInt(S);
f.lastlinedefined=LoadInt(S);
f.nups=LoadByte(S);
f.numparams=LoadByte(S);
f.is_vararg=LoadByte(S);
f.maxstacksize=LoadByte(S);
LoadCode(S,f);
LoadConstants(S,f);
LoadDebug(S,f);
IF (luaG_checkcode(f)==0 ? 1 : 0, "bad code");
StkId.dec(ref S.L.top);
S.L.nCcalls--;
return f;
}
private static void LoadHeader(LoadState S)
{
CharPtr h = new char[LUAC_HEADERSIZE];
CharPtr s = new char[LUAC_HEADERSIZE];
luaU_header(h);
LoadBlock(S, s, LUAC_HEADERSIZE);
IF (memcmp(h, s, LUAC_HEADERSIZE)!=0, "bad header");
}
/*
** load precompiled chunk
*/
public static Proto luaU_undump (lua_State L, ZIO Z, Mbuffer buff, CharPtr name)
{
LoadState S = new LoadState();
if (name[0] == '@' || name[0] == '=')
S.name = name+1;
else if (name[0]==LUA_SIGNATURE[0])
S.name="binary string";
else
S.name=name;
S.L=L;
S.Z=Z;
S.b=buff;
LoadHeader(S);
return LoadFunction(S,luaS_newliteral(L,"=?"));
}
/*
* make header
*/
public static void luaU_header(CharPtr h)
{
h = new CharPtr(h);
int x=1;
memcpy(h, LUA_SIGNATURE, LUA_SIGNATURE.Length);
h = h.add(LUA_SIGNATURE.Length);
h[0] = (char)LUAC_VERSION;
h.inc();
h[0] = (char)LUAC_FORMAT;
h.inc();
//*h++=(char)*(char*)&x; /* endianness */
h[0] = (char)x; /* endianness */
h.inc();
h[0] = (char)sizeof(int);
h.inc();
h[0] = (char)sizeof(uint);
h.inc();
h[0] = (char)sizeof(Instruction);
h.inc();
h[0] = (char)sizeof(lua_Number);
h.inc();
//(h++)[0] = ((lua_Number)0.5 == 0) ? 0 : 1; /* is lua_Number integral? */
h[0] = (char)0; // always 0 on this build
}
}
}
/*
** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace KopiLua
{
using TValue = Lua.lua_TValue;
using StkId = Lua.lua_TValue;
using lua_Number = System.Double;
using lu_byte = System.Byte;
using ptrdiff_t = System.Int32;
using Instruction = System.UInt32;
public partial class Lua
{
public static int tostring(lua_State L, StkId o) {
return ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o) != 0)) ? 1 : 0;
}
public static int tonumber(ref StkId o, TValue n) {
return ((ttype(o) == LUA_TNUMBER || (((o) = luaV_tonumber(o, n)) != null))) ? 1 : 0;
}
public static int equalobj(lua_State L, TValue o1, TValue o2) {
return ((ttype(o1) == ttype(o2)) && (luaV_equalval(L, o1, o2) != 0)) ? 1 : 0;
}
/* limit for table tag-method chains (to avoid loops) */
public const int MAXTAGLOOP = 100;
public static TValue luaV_tonumber (TValue obj, TValue n) {
lua_Number num;
if (ttisnumber(obj)) return obj;
if (ttisstring(obj) && (luaO_str2d(svalue(obj), out num)!=0)) {
setnvalue(n, num);
return n;
}
else
return null;
}
public static int luaV_tostring (lua_State L, StkId obj) {
if (!ttisnumber(obj))
return 0;
else {
lua_Number n = nvalue(obj);
CharPtr s = lua_number2str(n);
setsvalue2s(L, obj, luaS_new(L, s));
return 1;
}
}
private static void traceexec (lua_State L, InstructionPtr pc) {
lu_byte mask = L.hookmask;
InstructionPtr oldpc = InstructionPtr.Assign(L.savedpc);
L.savedpc = InstructionPtr.Assign(pc);
if (((mask & LUA_MASKCOUNT) != 0) && (L.hookcount == 0)) {
resethookcount(L);
luaD_callhook(L, LUA_HOOKCOUNT, -1);
}
if ((mask & LUA_MASKLINE) != 0) {
Proto p = ci_func(L.ci).l.p;
int npc = pcRel(pc, p);
int newline = getline(p, npc);
/* call linehook when enter a new function, when jump back (loop),
or when enter a new line */
if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p)))
luaD_callhook(L, LUA_HOOKLINE, newline);
}
}
private static void callTMres (lua_State L, StkId res, TValue f,
TValue p1, TValue p2) {
ptrdiff_t result = savestack(L, res);
setobj2s(L, L.top, f); /* push function */
setobj2s(L, L.top+1, p1); /* 1st argument */
setobj2s(L, L.top+2, p2); /* 2nd argument */
luaD_checkstack(L, 3);
L.top += 3;
luaD_call(L, L.top-3, 1);
res = restorestack(L, result);
StkId.dec(ref L.top);
setobjs2s(L, res, L.top);
}
private static void callTM (lua_State L, TValue f, TValue p1,
TValue p2, TValue p3) {
setobj2s(L, L.top, f); /* push function */
setobj2s(L, L.top + 1, p1); /* 1st argument */
setobj2s(L, L.top + 2, p2); /* 2nd argument */
setobj2s(L, L.top + 3, p3); /* 3th argument */
luaD_checkstack(L, 4);
L.top += 4;
luaD_call(L, L.top - 4, 0);
}
public static void luaV_gettable (lua_State L, TValue t, TValue key, StkId val) {
int loop;
for (loop = 0; loop < MAXTAGLOOP; loop++) {
TValue tm;
if (ttistable(t)) { /* `t' is a table? */
Table h = hvalue(t);
TValue res = luaH_get(h, key); /* do a primitive get */
if (!ttisnil(res) || /* result is no nil? */
(tm = fasttm(L, h.metatable, TMS.TM_INDEX)) == null) { /* or no TM? */
setobj2s(L, val, res);
return;
}
/* else will try the tag method */
}
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TMS.TM_INDEX)))
luaG_typeerror(L, t, "index");
if (ttisfunction(tm)) {
callTMres(L, val, tm, t, key);
return;
}
t = tm; /* else repeat with `tm' */
}
luaG_runerror(L, "loop in gettable");
}
public static void luaV_settable (lua_State L, TValue t, TValue key, StkId val) {
int loop;
for (loop = 0; loop < MAXTAGLOOP; loop++) {
TValue tm;
if (ttistable(t)) { /* `t' is a table? */
Table h = hvalue(t);
TValue oldval = luaH_set(L, h, key); /* do a primitive set */
if (!ttisnil(oldval) || /* result is no nil? */
(tm = fasttm(L, h.metatable, TMS.TM_NEWINDEX)) == null) { /* or no TM? */
setobj2t(L, oldval, val);
luaC_barriert(L, h, val);
return;
}
/* else will try the tag method */
}
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TMS.TM_NEWINDEX)))
luaG_typeerror(L, t, "index");
if (ttisfunction(tm)) {
callTM(L, tm, t, key, val);
return;
}
t = tm; /* else repeat with `tm' */
}
luaG_runerror(L, "loop in settable");
}
private static int call_binTM (lua_State L, TValue p1, TValue p2,
StkId res, TMS event_) {
TValue tm = luaT_gettmbyobj(L, p1, event_); /* try first operand */
if (ttisnil(tm))
tm = luaT_gettmbyobj(L, p2, event_); /* try second operand */
if (ttisnil(tm)) return 0;
callTMres(L, res, tm, p1, p2);
return 1;
}
private static TValue get_compTM (lua_State L, Table mt1, Table mt2,
TMS event_) {
TValue tm1 = fasttm(L, mt1, event_);
TValue tm2;
if (tm1 == null) return null; /* no metamethod */
if (mt1 == mt2) return tm1; /* same metatables => same metamethods */
tm2 = fasttm(L, mt2, event_);
if (tm2 == null) return null; /* no metamethod */
if (luaO_rawequalObj(tm1, tm2) != 0) /* same metamethods? */
return tm1;
return null;
}
private static int call_orderTM (lua_State L, TValue p1, TValue p2,
TMS event_) {
TValue tm1 = luaT_gettmbyobj(L, p1, event_);
TValue tm2;
if (ttisnil(tm1)) return -1; /* no metamethod? */
tm2 = luaT_gettmbyobj(L, p2, event_);
if (luaO_rawequalObj(tm1, tm2)==0) /* different metamethods? */
return -1;
callTMres(L, L.top, tm1, p1, p2);
return l_isfalse(L.top) == 0 ? 1 : 0;
}
private static int l_strcmp (TString ls, TString rs) {
CharPtr l = getstr(ls);
uint ll = ls.tsv.len;
CharPtr r = getstr(rs);
uint lr = rs.tsv.len;
for (;;) {
//int temp = strcoll(l, r);
int temp = String.Compare(l.ToString(), r.ToString());
if (temp != 0) return temp;
else { /* strings are equal up to a `\0' */
uint len = (uint)l.ToString().Length; /* index of first `\0' in both strings */
if (len == lr) /* r is finished? */
return (len == ll) ? 0 : 1;
else if (len == ll) /* l is finished? */
return -1; /* l is smaller than r (because r is not finished) */
/* both strings longer than `len'; go on comparing (after the `\0') */
len++;
l += len; ll -= len; r += len; lr -= len;
}
}
}
public static int luaV_lessthan (lua_State L, TValue l, TValue r) {
int res;
if (ttype(l) != ttype(r))
return luaG_ordererror(L, l, r);
else if (ttisnumber(l))
return luai_numlt(nvalue(l), nvalue(r)) ? 1 : 0;
else if (ttisstring(l))
return (l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0) ? 1 : 0;
else if ((res = call_orderTM(L, l, r, TMS.TM_LT)) != -1)
return res;
return luaG_ordererror(L, l, r);
}
private static int lessequal (lua_State L, TValue l, TValue r) {
int res;
if (ttype(l) != ttype(r))
return luaG_ordererror(L, l, r);
else if (ttisnumber(l))
return luai_numle(nvalue(l), nvalue(r)) ? 1 : 0;
else if (ttisstring(l))
return (l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0) ? 1 : 0;
else if ((res = call_orderTM(L, l, r, TMS.TM_LE)) != -1) /* first try `le' */
return res;
else if ((res = call_orderTM(L, r, l, TMS.TM_LT)) != -1) /* else try `lt' */
return (res == 0) ? 1 : 0;
return luaG_ordererror(L, l, r);
}
static CharPtr mybuff = null;
public static int luaV_equalval (lua_State L, TValue t1, TValue t2) {
TValue tm = null;
lua_assert(ttype(t1) == ttype(t2));
switch (ttype(t1)) {
case LUA_TNIL: return 1;
case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)) ? 1 : 0;
case LUA_TBOOLEAN: return (bvalue(t1) == bvalue(t2)) ? 1 : 0; /* true must be 1 !! */
case LUA_TLIGHTUSERDATA: return (pvalue(t1) == pvalue(t2)) ? 1 : 0;
case LUA_TUSERDATA: {
if (uvalue(t1) == uvalue(t2)) return 1;
tm = get_compTM(L, uvalue(t1).metatable, uvalue(t2).metatable,
TMS.TM_EQ);
break; /* will try TM */
}
case LUA_TTABLE: {
if (hvalue(t1) == hvalue(t2)) return 1;
tm = get_compTM(L, hvalue(t1).metatable, hvalue(t2).metatable, TMS.TM_EQ);
break; /* will try TM */
}
default: return (gcvalue(t1) == gcvalue(t2)) ? 1 : 0;
}
if (tm == null) return 0; /* no TM? */
callTMres(L, L.top, tm, t1, t2); /* call TM */
return l_isfalse(L.top) == 0 ? 1 : 0;
}
public static void luaV_concat (lua_State L, int total, int last) {
do {
StkId top = L.base_ + last + 1;
int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(top-2) || ttisnumber(top-2)) || (tostring(L, top-1)==0)) {
if (call_binTM(L, top-2, top-1, top-2, TMS.TM_CONCAT)==0)
luaG_concaterror(L, top-2, top-1);
} else if (tsvalue(top-1).len == 0) /* second op is empty? */
tostring(L, top - 2); /* result is first op (as string) */
else {
/* at least two string values; get as many as possible */
uint tl = tsvalue(top-1).len;
CharPtr buffer;
int i;
/* collect total length */
for (n = 1; n < total && (tostring(L, top-n-1)!=0); n++) {
uint l = tsvalue(top-n-1).len;
if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
tl += l;
}
buffer = luaZ_openspace(L, G(L).buff, tl);
if (mybuff == null)
mybuff = buffer;
tl = 0;
for (i=n; i>0; i--) { /* concat all strings */
uint l = tsvalue(top-i).len;
memcpy(buffer.chars, (int)tl, svalue(top-i).chars, (int)l);
tl += l;
}
setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
}
total -= n-1; /* got `n' strings to create 1 new */
last -= n-1;
} while (total > 1); /* repeat until only 1 result left */
}
public static void Arith (lua_State L, StkId ra, TValue rb,
TValue rc, TMS op) {
TValue tempb = new TValue(), tempc = new TValue();
TValue b, c;
if ((b = luaV_tonumber(rb, tempb)) != null &&
(c = luaV_tonumber(rc, tempc)) != null) {
lua_Number nb = nvalue(b), nc = nvalue(c);
switch (op) {
case TMS.TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
case TMS.TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
case TMS.TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
case TMS.TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break;
case TMS.TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break;
case TMS.TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
case TMS.TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
default: lua_assert(false); break;
}
}
else if (call_binTM(L, rb, rc, ra, op) == 0)
luaG_aritherror(L, rb, rc);
}
/*
** some macros for common tasks in `luaV_execute'
*/
public static void runtime_check(lua_State L, bool c) { Debug.Assert(c); }
//#define RA(i) (base+GETARG_A(i))
/* to be used after possible stack reallocation */
//#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgMask.OpArgR, base+GETARG_B(i))
//#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgMask.OpArgR, base+GETARG_C(i))
//#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgMask.OpArgK, \
//ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
//#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgMask.OpArgK, \
// ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
//#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgMask.OpArgK, k+GETARG_Bx(i))
// todo: implement proper checks, as above
internal static TValue RA(lua_State L, StkId base_, Instruction i) { return base_ + GETARG_A(i); }
internal static TValue RB(lua_State L, StkId base_, Instruction i) { return base_ + GETARG_B(i); }
internal static TValue RC(lua_State L, StkId base_, Instruction i) { return base_ + GETARG_C(i); }
internal static TValue RKB(lua_State L, StkId base_, Instruction i, TValue[] k) { return ISK(GETARG_B(i)) != 0 ? k[INDEXK(GETARG_B(i))] : base_ + GETARG_B(i); }
internal static TValue RKC(lua_State L, StkId base_, Instruction i, TValue[] k) { return ISK(GETARG_C(i)) != 0 ? k[INDEXK(GETARG_C(i))] : base_ + GETARG_C(i); }
internal static TValue KBx(lua_State L, Instruction i, TValue[] k) { return k[GETARG_Bx(i)]; }
public static void dojump(lua_State L, InstructionPtr pc, int i) { pc.pc += i; luai_threadyield(L); }
//#define Protect(x) { L.savedpc = pc; {x;}; base = L.base_; }
public static void arith_op(lua_State L, op_delegate op, TMS tm, StkId base_, Instruction i, TValue[] k, StkId ra, InstructionPtr pc) {
TValue rb = RKB(L, base_, i, k);
TValue rc = RKC(L, base_, i, k);
if (ttisnumber(rb) && ttisnumber(rc))
{
lua_Number nb = nvalue(rb), nc = nvalue(rc);
setnvalue(ra, op(nb, nc));
}
else
{
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
Arith(L, ra, rb, rc, tm);
base_ = L.base_;
//);
}
}
internal static void Dump(int pc, Instruction i)
{
int A = GETARG_A(i);
int B = GETARG_B(i);
int C = GETARG_C(i);
int Bx = GETARG_Bx(i);
int sBx = GETARG_sBx(i);
if ((sBx & 0x100) != 0)
sBx = - (sBx & 0xff);
Console.Write("{0,5} ({1,10}): ", pc, i);
Console.Write("{0,-10}\t", luaP_opnames[(int)GET_OPCODE(i)]);
switch (GET_OPCODE(i))
{
case OpCode.OP_CLOSE:
Console.Write("{0}", A);
break;
case OpCode.OP_MOVE:
case OpCode.OP_LOADNIL:
case OpCode.OP_GETUPVAL:
case OpCode.OP_SETUPVAL:
case OpCode.OP_UNM:
case OpCode.OP_NOT:
case OpCode.OP_RETURN:
Console.Write("{0}, {1}", A, B);
break;
case OpCode.OP_LOADBOOL:
case OpCode.OP_GETTABLE:
case OpCode.OP_SETTABLE:
case OpCode.OP_NEWTABLE:
case OpCode.OP_SELF:
case OpCode.OP_ADD:
case OpCode.OP_SUB:
case OpCode.OP_MUL:
case OpCode.OP_DIV:
case OpCode.OP_POW:
case OpCode.OP_CONCAT:
case OpCode.OP_EQ:
case OpCode.OP_LT:
case OpCode.OP_LE:
case OpCode.OP_TEST:
case OpCode.OP_CALL:
case OpCode.OP_TAILCALL:
Console.Write("{0}, {1}, {2}", A, B, C);
break;
case OpCode.OP_LOADK:
Console.Write("{0}, {1}", A, Bx);
break;
case OpCode.OP_GETGLOBAL:
case OpCode.OP_SETGLOBAL:
case OpCode.OP_SETLIST:
case OpCode.OP_CLOSURE:
Console.Write("{0}, {1}", A, Bx);
break;
case OpCode.OP_TFORLOOP:
Console.Write("{0}, {1}", A, C);
break;
case OpCode.OP_JMP:
case OpCode.OP_FORLOOP:
case OpCode.OP_FORPREP:
Console.Write("{0}, {1}", A, sBx);
break;
}
Console.WriteLine();
}
public static void luaV_execute (lua_State L, int nexeccalls) {
LClosure cl;
StkId base_;
TValue[] k;
/*const*/ InstructionPtr pc;
reentry: /* entry point */
lua_assert(isLua(L.ci));
pc = InstructionPtr.Assign(L.savedpc);
cl = clvalue(L.ci.func).l;
base_ = L.base_;
k = cl.p.k;
/* main loop of interpreter */
for (;;) {
/*const*/ Instruction i = InstructionPtr.inc(ref pc)[0];
StkId ra;
if ( ((L.hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) != 0) &&
(((--L.hookcount) == 0) || ((L.hookmask & LUA_MASKLINE) != 0))) {
traceexec(L, pc);
if (L.status == LUA_YIELD) { /* did hook yield? */
L.savedpc = new InstructionPtr(pc.codes, pc.pc - 1);
return;
}
base_ = L.base_;
}
/* warning!! several calls may realloc the stack and invalidate `ra' */
ra = RA(L, base_, i);
lua_assert(base_ == L.base_ && L.base_ == L.ci.base_);
lua_assert(base_ <= L.top && ((L.top - L.stack) <= L.stacksize));
lua_assert(L.top == L.ci.top || (luaG_checkopenop(i)!=0));
//Dump(pc.pc, i);
switch (GET_OPCODE(i)) {
case OpCode.OP_MOVE: {
setobjs2s(L, ra, RB(L, base_, i));
continue;
}
case OpCode.OP_LOADK: {
setobj2s(L, ra, KBx(L, i, k));
continue;
}
case OpCode.OP_LOADBOOL: {
setbvalue(ra, GETARG_B(i));
if (GETARG_C(i) != 0) InstructionPtr.inc(ref pc); /* skip next instruction (if C) */
continue;
}
case OpCode.OP_LOADNIL: {
TValue rb = RB(L, base_, i);
do {
setnilvalue(StkId.dec(ref rb));
} while (rb >= ra);
continue;
}
case OpCode.OP_GETUPVAL: {
int b = GETARG_B(i);
setobj2s(L, ra, cl.upvals[b].v);
continue;
}
case OpCode.OP_GETGLOBAL: {
TValue g = new TValue();
TValue rb = KBx(L, i, k);
sethvalue(L, g, cl.env);
lua_assert(ttisstring(rb));
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
luaV_gettable(L, g, rb, ra);
base_ = L.base_;
//);
L.savedpc = InstructionPtr.Assign(pc);
continue;
}
case OpCode.OP_GETTABLE: {
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
luaV_gettable(L, RB(L, base_, i), RKC(L, base_, i, k), ra);
base_ = L.base_;
//);
L.savedpc = InstructionPtr.Assign(pc);
continue;
}
case OpCode.OP_SETGLOBAL: {
TValue g = new TValue();
sethvalue(L, g, cl.env);
lua_assert(ttisstring(KBx(L, i, k)));
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
luaV_settable(L, g, KBx(L, i, k), ra);
base_ = L.base_;
//);
L.savedpc = InstructionPtr.Assign(pc);
continue;
}
case OpCode.OP_SETUPVAL: {
UpVal uv = cl.upvals[GETARG_B(i)];
setobj(L, uv.v, ra);
luaC_barrier(L, uv, ra);
continue;
}
case OpCode.OP_SETTABLE: {
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
luaV_settable(L, ra, RKB(L, base_, i, k), RKC(L, base_, i, k));
base_ = L.base_;
//);
L.savedpc = InstructionPtr.Assign(pc);
continue;
}
case OpCode.OP_NEWTABLE: {
int b = GETARG_B(i);
int c = GETARG_C(i);
sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
luaC_checkGC(L);
base_ = L.base_;
//);
L.savedpc = InstructionPtr.Assign(pc);
continue;
}
case OpCode.OP_SELF: {
StkId rb = RB(L, base_, i);
setobjs2s(L, ra + 1, rb);
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
luaV_gettable(L, rb, RKC(L, base_, i, k), ra);
base_ = L.base_;
//);
L.savedpc = InstructionPtr.Assign(pc);
continue;
}
case OpCode.OP_ADD: {
arith_op(L, luai_numadd, TMS.TM_ADD, base_, i, k, ra, pc);
continue;
}
case OpCode.OP_SUB: {
arith_op(L, luai_numsub, TMS.TM_SUB, base_, i, k, ra, pc);
continue;
}
case OpCode.OP_MUL: {
arith_op(L, luai_nummul, TMS.TM_MUL, base_, i, k, ra, pc);
continue;
}
case OpCode.OP_DIV: {
arith_op(L, luai_numdiv, TMS.TM_DIV, base_, i, k, ra, pc);
continue;
}
case OpCode.OP_MOD: {
arith_op(L, luai_nummod, TMS.TM_MOD, base_, i, k, ra, pc);
continue;
}
case OpCode.OP_POW: {
arith_op(L, luai_numpow, TMS.TM_POW, base_, i, k, ra, pc);
continue;
}
case OpCode.OP_UNM: {
TValue rb = RB(L, base_, i);
if (ttisnumber(rb)) {
lua_Number nb = nvalue(rb);
setnvalue(ra, luai_numunm(nb));
}
else {
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
Arith(L, ra, rb, rb, TMS.TM_UNM);
base_ = L.base_;
//);
L.savedpc = InstructionPtr.Assign(pc);
}
continue;
}
case OpCode.OP_NOT: {
int res = l_isfalse(RB(L, base_, i)) == 0 ? 0 : 1; /* next assignment may change this value */
setbvalue(ra, res);
continue;
}
case OpCode.OP_LEN: {
TValue rb = RB(L, base_, i);
switch (ttype(rb)) {
case LUA_TTABLE: {
setnvalue(ra, (lua_Number)luaH_getn(hvalue(rb)));
break;
}
case LUA_TSTRING: {
setnvalue(ra, (lua_Number)tsvalue(rb).len);
break;
}
default: { /* try metamethod */
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
if (call_binTM(L, rb, luaO_nilobject, ra, TMS.TM_LEN) == 0)
luaG_typeerror(L, rb, "get length of");
base_ = L.base_;
//)
break;
}
}
continue;
}
case OpCode.OP_CONCAT: {
int b = GETARG_B(i);
int c = GETARG_C(i);
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
luaV_concat(L, c-b+1, c); luaC_checkGC(L);
base_ = L.base_;
//);
setobjs2s(L, RA(L, base_, i), base_ + b);
continue;
}
case OpCode.OP_JMP: {
dojump(L, pc, GETARG_sBx(i));
continue;
}
case OpCode.OP_EQ: {
TValue rb = RKB(L, base_, i, k);
TValue rc = RKC(L, base_, i, k);
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
if (equalobj(L, rb, rc) == GETARG_A(i))
dojump(L, pc, GETARG_sBx(pc[0]));
base_ = L.base_;
//);
InstructionPtr.inc(ref pc);
continue;
}
case OpCode.OP_LT: {
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
if (luaV_lessthan(L, RKB(L, base_, i, k), RKC(L, base_, i, k)) == GETARG_A(i))
dojump(L, pc, GETARG_sBx(pc[0]));
base_ = L.base_;
//);
InstructionPtr.inc(ref pc);
continue;
}
case OpCode.OP_LE: {
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
if (lessequal(L, RKB(L, base_, i, k), RKC(L, base_, i, k)) == GETARG_A(i))
dojump(L, pc, GETARG_sBx(pc[0]));
base_ = L.base_;
//);
InstructionPtr.inc(ref pc);
continue;
}
case OpCode.OP_TEST: {
if (l_isfalse(ra) != GETARG_C(i))
dojump(L, pc, GETARG_sBx(pc[0]));
InstructionPtr.inc(ref pc);
continue;
}
case OpCode.OP_TESTSET: {
TValue rb = RB(L, base_, i);
if (l_isfalse(rb) != GETARG_C(i)) {
setobjs2s(L, ra, rb);
dojump(L, pc, GETARG_sBx(pc[0]));
}
InstructionPtr.inc(ref pc);
continue;
}
case OpCode.OP_CALL: {
int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1;
if (b != 0) L.top = ra + b; /* else previous instruction set top */
L.savedpc = InstructionPtr.Assign(pc);
switch (luaD_precall(L, ra, nresults)) {
case PCRLUA: {
nexeccalls++;
goto reentry; /* restart luaV_execute over new Lua function */
}
case PCRC: {
/* it was a C function (`precall' called it); adjust results */
if (nresults >= 0) L.top = L.ci.top;
base_ = L.base_;
continue;
}
default: {
return; /* yield */
}
}
}
case OpCode.OP_TAILCALL: {
int b = GETARG_B(i);
if (b != 0) L.top = ra + b; /* else previous instruction set top */
L.savedpc = InstructionPtr.Assign(pc);
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
switch (luaD_precall(L, ra, LUA_MULTRET)) {
case PCRLUA: {
/* tail call: put new frame in place of previous one */
CallInfo ci = L.ci - 1; /* previous frame */
int aux;
StkId func = ci.func;
StkId pfunc = (ci+1).func; /* previous function index */
if (L.openupval != null) luaF_close(L, ci.base_);
L.base_ = ci.base_ = ci.func + (ci[1].base_ - pfunc);
for (aux = 0; pfunc+aux < L.top; aux++) /* move frame down */
setobjs2s(L, func+aux, pfunc+aux);
ci.top = L.top = func+aux; /* correct top */
lua_assert(L.top == L.base_ + clvalue(func).l.p.maxstacksize);
ci.savedpc = InstructionPtr.Assign(L.savedpc);
ci.tailcalls++; /* one more call lost */
CallInfo.dec(ref L.ci); /* remove new frame */
goto reentry;
}
case PCRC: { /* it was a C function (`precall' called it) */
base_ = L.base_;
continue;
}
default: {
return; /* yield */
}
}
}
case OpCode.OP_RETURN: {
int b = GETARG_B(i);
if (b != 0) L.top = ra+b-1;
if (L.openupval != null) luaF_close(L, base_);
L.savedpc = InstructionPtr.Assign(pc);
b = luaD_poscall(L, ra);
if (--nexeccalls == 0) /* was previous function running `here'? */
return; /* no: return */
else { /* yes: continue its execution */
if (b != 0) L.top = L.ci.top;
lua_assert(isLua(L.ci));
lua_assert(GET_OPCODE(L.ci.savedpc[-1]) == OpCode.OP_CALL);
goto reentry;
}
}
case OpCode.OP_FORLOOP: {
lua_Number step = nvalue(ra+2);
lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
lua_Number limit = nvalue(ra+1);
if (luai_numlt(0, step) ? luai_numle(idx, limit)
: luai_numle(limit, idx)) {
dojump(L, pc, GETARG_sBx(i)); /* jump back */
setnvalue(ra, idx); /* update internal index... */
setnvalue(ra+3, idx); /* ...and external index */
}
continue;
}
case OpCode.OP_FORPREP: {
TValue init = ra;
TValue plimit = ra+1;
TValue pstep = ra+2;
L.savedpc = InstructionPtr.Assign(pc); /* next steps may throw errors */
if (tonumber(ref init, ra) == 0)
luaG_runerror(L, LUA_QL("for") + " initial value must be a number");
else if (tonumber(ref plimit, ra+1) == 0)
luaG_runerror(L, LUA_QL("for") + " limit must be a number");
else if (tonumber(ref pstep, ra+2) == 0)
luaG_runerror(L, LUA_QL("for") + " step must be a number");
setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
dojump(L, pc, GETARG_sBx(i));
continue;
}
case OpCode.OP_TFORLOOP: {
StkId cb = ra + 3; /* call base */
setobjs2s(L, cb+2, ra+2);
setobjs2s(L, cb+1, ra+1);
setobjs2s(L, cb, ra);
L.top = cb+3; /* func. + 2 args (state and index) */
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
luaD_call(L, cb, GETARG_C(i));
base_ = L.base_;
//);
L.top = L.ci.top;
cb = RA(L, base_, i) + 3; /* previous call may change the stack */
if (!ttisnil(cb)) { /* continue loop? */
setobjs2s(L, cb-1, cb); /* save control variable */
dojump(L, pc, GETARG_sBx(pc[0])); /* jump back */
}
InstructionPtr.inc(ref pc);
continue;
}
case OpCode.OP_SETLIST: {
int n = GETARG_B(i);
int c = GETARG_C(i);
int last;
Table h;
if (n == 0) {
n = cast_int(L.top - ra) - 1;
L.top = L.ci.top;
}
if (c == 0)
{
c = cast_int(pc[0]);
InstructionPtr.inc(ref pc);
}
runtime_check(L, ttistable(ra));
h = hvalue(ra);
last = ((c-1)*LFIELDS_PER_FLUSH) + n;
if (last > h.sizearray) /* needs more space? */
luaH_resizearray(L, h, last); /* pre-alloc it at once */
for (; n > 0; n--) {
TValue val = ra+n;
setobj2t(L, luaH_setnum(L, h, last--), val);
luaC_barriert(L, h, val);
}
continue;
}
case OpCode.OP_CLOSE: {
luaF_close(L, ra);
continue;
}
case OpCode.OP_CLOSURE: {
Proto p;
Closure ncl;
int nup, j;
p = cl.p.p[GETARG_Bx(i)];
nup = p.nups;
ncl = luaF_newLclosure(L, nup, cl.env);
ncl.l.p = p;
for (j=0; j<nup; j++, InstructionPtr.inc(ref pc)) {
if (GET_OPCODE(pc[0]) == OpCode.OP_GETUPVAL)
ncl.l.upvals[j] = cl.upvals[GETARG_B(pc[0])];
else {
lua_assert(GET_OPCODE(pc[0]) == OpCode.OP_MOVE);
ncl.l.upvals[j] = luaF_findupval(L, base_ + GETARG_B(pc[0]));
}
}
setclvalue(L, ra, ncl);
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
luaC_checkGC(L);
base_ = L.base_;
//);
continue;
}
case OpCode.OP_VARARG: {
int b = GETARG_B(i) - 1;
int j;
CallInfo ci = L.ci;
int n = cast_int(ci.base_ - ci.func) - cl.p.numparams - 1;
if (b == LUA_MULTRET) {
//Protect(
L.savedpc = InstructionPtr.Assign(pc);
luaD_checkstack(L, n);
base_ = L.base_;
//);
ra = RA(L, base_, i); /* previous call may change the stack */
b = n;
L.top = ra + n;
}
for (j = 0; j < b; j++) {
if (j < n) {
setobjs2s(L, ra + j, ci.base_ - n + j);
}
else {
setnilvalue(ra + j);
}
}
continue;
}
}
}
}
}
}
/*
** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
** a generic input stream interface
** See Copyright Notice in lua.h
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace KopiLua
{
using ZIO = Lua.Zio;
public partial class Lua
{
public const int EOZ = -1; /* end of stream */
//public class ZIO : Zio { };
public static int char2int(char c) { return (int)c; }
public static int zgetc(ZIO z)
{
if (z.n-- > 0)
{
int ch = char2int(z.p[0]);
z.p.inc();
return ch;
}
else
return luaZ_fill(z);
}
public class Mbuffer {
public CharPtr buffer = new CharPtr();
public uint n;
public uint buffsize;
};
public static void luaZ_initbuffer(lua_State L, Mbuffer buff)
{
buff.buffer = null;
}
public static CharPtr luaZ_buffer(Mbuffer buff) {return buff.buffer;}
public static uint luaZ_sizebuffer(Mbuffer buff) { return buff.buffsize; }
public static uint luaZ_bufflen(Mbuffer buff) {return buff.n;}
public static void luaZ_resetbuffer(Mbuffer buff) {buff.n = 0;}
public static void luaZ_resizebuffer(lua_State L, Mbuffer buff, int size)
{
if (buff.buffer == null)
buff.buffer = new CharPtr();
luaM_reallocvector(L, ref buff.buffer.chars, (int)buff.buffsize, size);
buff.buffsize = (uint)buff.buffer.chars.Length;
}
public static void luaZ_freebuffer(lua_State L, Mbuffer buff) {luaZ_resizebuffer(L, buff, 0);}
/* --------- Private Part ------------------ */
public class Zio {
public uint n; /* bytes still unread */
public CharPtr p; /* current position in buffer */
public lua_Reader reader;
public object data; /* additional data */
public lua_State L; /* Lua state (for reader) */
};
public static int luaZ_fill (ZIO z) {
uint size;
lua_State L = z.L;
CharPtr buff;
lua_unlock(L);
buff = z.reader(L, z.data, out size);
lua_lock(L);
if (buff == null || size == 0) return EOZ;
z.n = size - 1;
z.p = new CharPtr(buff);
int result = char2int(z.p[0]);
z.p.inc();
return result;
}
public static int luaZ_lookahead (ZIO z) {
if (z.n == 0) {
if (luaZ_fill(z) == EOZ)
return EOZ;
else {
z.n++; /* luaZ_fill removed first byte; put back it */
z.p.dec();
}
}
return char2int(z.p[0]);
}
public static void luaZ_init(lua_State L, ZIO z, lua_Reader reader, object data)
{
z.L = L;
z.reader = reader;
z.data = data;
z.n = 0;
z.p = null;
}
/* --------------------------------------------------------------- read --- */
public static uint luaZ_read (ZIO z, CharPtr b, uint n) {
b = new CharPtr(b);
while (n != 0) {
uint m;
if (luaZ_lookahead(z) == EOZ)
return n; // return number of missing bytes
m = (n <= z.n) ? n : z.n; // min. between n and z.n
memcpy(b, z.p, m);
z.n -= m;
z.p += m;
b = b + m;
n -= m;
}
return 0;
}
/* ------------------------------------------------------------------------ */
public static CharPtr luaZ_openspace (lua_State L, Mbuffer buff, uint n) {
if (n > buff.buffsize) {
if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
luaZ_resizebuffer(L, buff, (int)n);
}
return buff.buffer;
}
}
}
/*
** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $
** print bytecodes
** See Copyright Notice in lua.h
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace KopiLua
{
using TValue = Lua.lua_TValue;
using Instruction = System.UInt32;
public partial class Lua
{
public static void luaU_print(Proto f, int full) {PrintFunction(f, full);}
//#define Sizeof(x) ((int)sizeof(x))
//#define VOID(p) ((const void*)(p))
public static void PrintString(TString ts)
{
CharPtr s=getstr(ts);
uint i,n=ts.tsv.len;
putchar('"');
for (i=0; i<n; i++)
{
int c=s[i];
switch (c)
{
case '"': printf("\\\""); break;
case '\\': printf("\\\\"); break;
case '\a': printf("\\a"); break;
case '\b': printf("\\b"); break;
case '\f': printf("\\f"); break;
case '\n': printf("\\n"); break;
case '\r': printf("\\r"); break;
case '\t': printf("\\t"); break;
case '\v': printf("\\v"); break;
default: if (isprint((byte)c))
putchar(c);
else
printf("\\%03u",(byte)c);
break;
}
}
putchar('"');
}
private static void PrintConstant(Proto f, int i)
{
/*const*/ TValue o=f.k[i];
switch (ttype(o))
{
case LUA_TNIL:
printf("nil");
break;
case LUA_TBOOLEAN:
printf(bvalue(o) != 0 ? "true" : "false");
break;
case LUA_TNUMBER:
printf(LUA_NUMBER_FMT,nvalue(o));
break;
case LUA_TSTRING:
PrintString(rawtsvalue(o));
break;
default: /* cannot happen */
printf("? type=%d",ttype(o));
break;
}
}
private static void PrintCode( Proto f)
{
Instruction[] code = f.code;
int pc,n=f.sizecode;
for (pc=0; pc<n; pc++)
{
Instruction i = f.code[pc];
OpCode o=GET_OPCODE(i);
int a=GETARG_A(i);
int b=GETARG_B(i);
int c=GETARG_C(i);
int bx=GETARG_Bx(i);
int sbx=GETARG_sBx(i);
int line=getline(f,pc);
printf("\t%d\t",pc+1);
if (line>0) printf("[%d]\t",line); else printf("[-]\t");
printf("%-9s\t",luaP_opnames[(int)o]);
switch (getOpMode(o))
{
case OpMode.iABC:
printf("%d",a);
if (getBMode(o) != OpArgMask.OpArgN) printf(" %d", (ISK(b) != 0) ? (-1 - INDEXK(b)) : b);
if (getCMode(o) != OpArgMask.OpArgN) printf(" %d", (ISK(c) != 0) ? (-1 - INDEXK(c)) : c);
break;
case OpMode.iABx:
if (getBMode(o)==OpArgMask.OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx);
break;
case OpMode.iAsBx:
if (o==OpCode.OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx);
break;
}
switch (o)
{
case OpCode.OP_LOADK:
printf("\t; "); PrintConstant(f,bx);
break;
case OpCode.OP_GETUPVAL:
case OpCode.OP_SETUPVAL:
printf("\t; %s", (f.sizeupvalues>0) ? getstr(f.upvalues[b]) : "-");
break;
case OpCode.OP_GETGLOBAL:
case OpCode.OP_SETGLOBAL:
printf("\t; %s",svalue(f.k[bx]));
break;
case OpCode.OP_GETTABLE:
case OpCode.OP_SELF:
if (ISK(c) != 0) { printf("\t; "); PrintConstant(f,INDEXK(c)); }
break;
case OpCode.OP_SETTABLE:
case OpCode.OP_ADD:
case OpCode.OP_SUB:
case OpCode.OP_MUL:
case OpCode.OP_DIV:
case OpCode.OP_POW:
case OpCode.OP_EQ:
case OpCode.OP_LT:
case OpCode.OP_LE:
if (ISK(b)!=0 || ISK(c)!=0)
{
printf("\t; ");
if (ISK(b) != 0) PrintConstant(f,INDEXK(b)); else printf("-");
printf(" ");
if (ISK(c) != 0) PrintConstant(f,INDEXK(c)); else printf("-");
}
break;
case OpCode.OP_JMP:
case OpCode.OP_FORLOOP:
case OpCode.OP_FORPREP:
printf("\t; to %d",sbx+pc+2);
break;
case OpCode.OP_CLOSURE:
printf("\t; %p",VOID(f.p[bx]));
break;
case OpCode.OP_SETLIST:
if (c==0) printf("\t; %d",(int)code[++pc]);
else printf("\t; %d",c);
break;
default:
break;
}
printf("\n");
}
}
public static string SS(int x) { return (x == 1) ? "" : "s"; }
//#define S(x) x,SS(x)
private static void PrintHeader(Proto f)
{
CharPtr s=getstr(f.source);
if (s[0]=='@' || s[0]=='=')
s = s.next();
else if (s[0]==LUA_SIGNATURE[0])
s="(bstring)";
else
s="(string)";
printf("\n%s <%s:%d,%d> (%d Instruction%s, %d bytes at %p)\n",
(f.linedefined==0)?"main":"function",s,
f.linedefined,f.lastlinedefined,
f.sizecode, SS(f.sizecode), f.sizecode * GetUnmanagedSize(typeof(Instruction)), VOID(f));
printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
f.numparams,(f.is_vararg != 0) ? "+" : "", SS(f.numparams),
f.maxstacksize, SS(f.maxstacksize), f.nups, SS(f.nups));
printf("%d local%s, %d constant%s, %d function%s\n",
f.sizelocvars, SS(f.sizelocvars), f.sizek, SS(f.sizek), f.sizep, SS(f.sizep));
}
private static void PrintConstants(Proto f)
{
int i,n=f.sizek;
printf("constants (%d) for %p:\n",n,VOID(f));
for (i=0; i<n; i++)
{
printf("\t%d\t",i+1);
PrintConstant(f,i);
printf("\n");
}
}
private static void PrintLocals(Proto f)
{
int i,n=f.sizelocvars;
printf("locals (%d) for %p:\n",n,VOID(f));
for (i=0; i<n; i++)
{
printf("\t%d\t%s\t%d\t%d\n",
i,getstr(f.locvars[i].varname),f.locvars[i].startpc+1,f.locvars[i].endpc+1);
}
}
private static void PrintUpvalues(Proto f)
{
int i,n=f.sizeupvalues;
printf("upvalues (%d) for %p:\n",n,VOID(f));
if (f.upvalues==null) return;
for (i=0; i<n; i++)
{
printf("\t%d\t%s\n",i,getstr(f.upvalues[i]));
}
}
public static void PrintFunction(Proto f, int full)
{
int i,n=f.sizep;
PrintHeader(f);
PrintCode(f);
if (full != 0)
{
PrintConstants(f);
PrintLocals(f);
PrintUpvalues(f);
}
for (i=0; i<n; i++) PrintFunction(f.p[i],full);
}
}
}
#region Usings
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
#endregion
namespace AT.MIN
{
public static class Tools
{
#region Public Methods
#region IsNumericType
/// <summary>
/// Determines whether the specified value is of numeric type.
/// </summary>
/// <param name="o">The object to check.</param>
/// <returns>
/// <c>true</c> if o is a numeric type; otherwise, <c>false</c>.
/// </returns>
public static bool IsNumericType( object o )
{
return ( o is byte ||
o is sbyte ||
o is short ||
o is ushort ||
o is int ||
o is uint ||
o is long ||
o is ulong ||
o is float ||
o is double ||
o is decimal );
}
#endregion
#region IsPositive
/// <summary>
/// Determines whether the specified value is positive.
/// </summary>
/// <param name="Value">The value.</param>
/// <param name="ZeroIsPositive">if set to <c>true</c> treats 0 as positive.</param>
/// <returns>
/// <c>true</c> if the specified value is positive; otherwise, <c>false</c>.
/// </returns>
public static bool IsPositive( object Value, bool ZeroIsPositive )
{
switch ( Type.GetTypeCode( Value.GetType() ) )
{
case TypeCode.SByte:
return ( ZeroIsPositive ? (sbyte)Value >= 0 : (sbyte)Value > 0 );
case TypeCode.Int16:
return ( ZeroIsPositive ? (short)Value >= 0 : (short)Value > 0 );
case TypeCode.Int32:
return ( ZeroIsPositive ? (int)Value >= 0 : (int)Value > 0 );
case TypeCode.Int64:
return ( ZeroIsPositive ? (long)Value >= 0 : (long)Value > 0 );
case TypeCode.Single:
return ( ZeroIsPositive ? (float)Value >= 0 : (float)Value > 0 );
case TypeCode.Double:
return ( ZeroIsPositive ? (double)Value >= 0 : (double)Value > 0 );
case TypeCode.Decimal:
return ( ZeroIsPositive ? (decimal)Value >= 0 : (decimal)Value > 0 );
case TypeCode.Byte:
return ( ZeroIsPositive ? true : (byte)Value > 0 );
case TypeCode.UInt16:
return ( ZeroIsPositive ? true : (ushort)Value > 0 );
case TypeCode.UInt32:
return ( ZeroIsPositive ? true : (uint)Value > 0 );
case TypeCode.UInt64:
return ( ZeroIsPositive ? true : (ulong)Value > 0 );
case TypeCode.Char:
return ( ZeroIsPositive ? true : (char)Value != '\0' );
default:
return false;
}
}
#endregion
#region ToUnsigned
/// <summary>
/// Converts the specified values boxed type to its correpsonding unsigned
/// type.
/// </summary>
/// <param name="Value">The value.</param>
/// <returns>A boxed numeric object whos type is unsigned.</returns>
public static object ToUnsigned( object Value )
{
switch ( Type.GetTypeCode( Value.GetType() ) )
{
case TypeCode.SByte:
return (byte)( (sbyte)Value );
case TypeCode.Int16:
return (ushort)( (short)Value );
case TypeCode.Int32:
return (uint)( (int)Value );
case TypeCode.Int64:
return (ulong)( (long)Value );
case TypeCode.Byte:
return Value;
case TypeCode.UInt16:
return Value;
case TypeCode.UInt32:
return Value;
case TypeCode.UInt64:
return Value;
case TypeCode.Single:
return (UInt32)( (float)Value );
case TypeCode.Double:
return (ulong)( (double)Value );
case TypeCode.Decimal:
return (ulong)( (decimal)Value );
default:
return null;
}
}
#endregion
#region ToInteger
/// <summary>
/// Converts the specified values boxed type to its correpsonding integer
/// type.
/// </summary>
/// <param name="Value">The value.</param>
/// <returns>A boxed numeric object whos type is an integer type.</returns>
public static object ToInteger( object Value, bool Round )
{
switch ( Type.GetTypeCode( Value.GetType() ) )
{
case TypeCode.SByte:
return Value;
case TypeCode.Int16:
return Value;
case TypeCode.Int32:
return Value;
case TypeCode.Int64:
return Value;
case TypeCode.Byte:
return Value;
case TypeCode.UInt16:
return Value;
case TypeCode.UInt32:
return Value;
case TypeCode.UInt64:
return Value;
case TypeCode.Single:
return ( Round ? (int)Math.Round( (float)Value ) : (int)( (float)Value ) );
case TypeCode.Double:
return ( Round ? (long)Math.Round( (double)Value ) : (long)( (double)Value ) );
case TypeCode.Decimal:
return ( Round ? Math.Round( (decimal)Value ) : (decimal)Value );
default:
return null;
}
}
#endregion
#region UnboxToLong
public static long UnboxToLong( object Value, bool Round )
{
switch ( Type.GetTypeCode( Value.GetType() ) )
{
case TypeCode.SByte:
return (long)( (sbyte)Value );
case TypeCode.Int16:
return (long)( (short)Value );
case TypeCode.Int32:
return (long)( (int)Value );
case TypeCode.Int64:
return (long)Value;
case TypeCode.Byte:
return (long)( (byte)Value );
case TypeCode.UInt16:
return (long)( (ushort)Value );
case TypeCode.UInt32:
return (long)( (uint)Value );
case TypeCode.UInt64:
return (long)( (ulong)Value );
case TypeCode.Single:
return ( Round ? (long)Math.Round( (float)Value ) : (long)( (float)Value ) );
case TypeCode.Double:
return ( Round ? (long)Math.Round( (double)Value ) : (long)( (double)Value ) );
case TypeCode.Decimal:
return ( Round ? (long)Math.Round( (decimal)Value ) : (long)( (decimal)Value ) );
default:
return 0;
}
}
#endregion
#region ReplaceMetaChars
/// <summary>
/// Replaces the string representations of meta chars with their corresponding
/// character values.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A string with all string meta chars are replaced</returns>
public static string ReplaceMetaChars( string input )
{
return Regex.Replace( input, @"(\\)(\d{3}|[^\d])?", new MatchEvaluator( ReplaceMetaCharsMatch ) );
}
private static string ReplaceMetaCharsMatch( Match m )
{
// convert octal quotes (like \040)
if ( m.Groups[2].Length == 3 )
return Convert.ToChar( Convert.ToByte( m.Groups[2].Value, 8 ) ).ToString();
else
{
// convert all other special meta characters
//TODO: \xhhh hex and possible dec !!
switch ( m.Groups[2].Value )
{
case "0": // null
return "\0";
case "a": // alert (beep)
return "\a";
case "b": // BS
return "\b";
case "f": // FF
return "\f";
case "v": // vertical tab
return "\v";
case "r": // CR
return "\r";
case "n": // LF
return "\n";
case "t": // Tab
return "\t";
default:
// if neither an octal quote nor a special meta character
// so just remove the backslash
return m.Groups[2].Value;
}
}
}
#endregion
#region printf
public static void printf( string Format, params object[] Parameters )
{
Console.Write( Tools.sprintf( Format, Parameters ) );
}
#endregion
#region fprintf
public static void fprintf( TextWriter Destination, string Format, params object[] Parameters )
{
Destination.Write( Tools.sprintf( Format, Parameters ) );
}
internal static Regex r = new Regex(@"\%(\d*\$)?([\'\#\-\+ ]*)(\d*)(?:\.(\d+))?([hl])?([dioxXucsfeEgGpn%])");
#endregion
#region sprintf
public static string sprintf( string Format, params object[] Parameters )
{
#region Variables
StringBuilder f = new StringBuilder();
//Regex r = new Regex( @"\%(\d*\$)?([\'\#\-\+ ]*)(\d*)(?:\.(\d+))?([hl])?([dioxXucsfeEgGpn%])" );
//"%[parameter][flags][width][.precision][length]type"
Match m = null;
string w = String.Empty;
int defaultParamIx = 0;
int paramIx;
object o = null;
bool flagLeft2Right = false;
bool flagAlternate = false;
bool flagPositiveSign = false;
bool flagPositiveSpace = false;
bool flagZeroPadding = false;
bool flagGroupThousands = false;
int fieldLength = 0;
int fieldPrecision = 0;
char shortLongIndicator = '\0';
char formatSpecifier = '\0';
char paddingCharacter = ' ';
#endregion
// find all format parameters in format string
f.Append( Format );
m = r.Match( f.ToString() );
while ( m.Success )
{
#region parameter index
paramIx = defaultParamIx;
if ( m.Groups[1] != null && m.Groups[1].Value.Length > 0 )
{
string val = m.Groups[1].Value.Substring( 0, m.Groups[1].Value.Length - 1 );
paramIx = Convert.ToInt32( val ) - 1;
};
#endregion
#region format flags
// extract format flags
flagAlternate = false;
flagLeft2Right = false;
flagPositiveSign = false;
flagPositiveSpace = false;
flagZeroPadding = false;
flagGroupThousands = false;
if ( m.Groups[2] != null && m.Groups[2].Value.Length > 0 )
{
string flags = m.Groups[2].Value;
flagAlternate = ( flags.IndexOf( '#' ) >= 0 );
flagLeft2Right = ( flags.IndexOf( '-' ) >= 0 );
flagPositiveSign = ( flags.IndexOf( '+' ) >= 0 );
flagPositiveSpace = ( flags.IndexOf( ' ' ) >= 0 );
flagGroupThousands = ( flags.IndexOf( '\'' ) >= 0 );
// positive + indicator overrides a
// positive space character
if ( flagPositiveSign && flagPositiveSpace )
flagPositiveSpace = false;
}
#endregion
#region field length
// extract field length and
// pading character
paddingCharacter = ' ';
fieldLength = int.MinValue;
if ( m.Groups[3] != null && m.Groups[3].Value.Length > 0 )
{
fieldLength = Convert.ToInt32( m.Groups[3].Value );
flagZeroPadding = ( m.Groups[3].Value[0] == '0' );
}
#endregion
if ( flagZeroPadding )
paddingCharacter = '0';
// left2right allignment overrides zero padding
if ( flagLeft2Right && flagZeroPadding )
{
flagZeroPadding = false;
paddingCharacter = ' ';
}
#region field precision
// extract field precision
fieldPrecision = int.MinValue;
if ( m.Groups[4] != null && m.Groups[4].Value.Length > 0 )
fieldPrecision = Convert.ToInt32( m.Groups[4].Value );
#endregion
#region short / long indicator
// extract short / long indicator
shortLongIndicator = Char.MinValue;
if ( m.Groups[5] != null && m.Groups[5].Value.Length > 0 )
shortLongIndicator = m.Groups[5].Value[0];
#endregion
#region format specifier
// extract format
formatSpecifier = Char.MinValue;
if ( m.Groups[6] != null && m.Groups[6].Value.Length > 0 )
formatSpecifier = m.Groups[6].Value[0];
#endregion
// default precision is 6 digits if none is specified except
if ( fieldPrecision == int.MinValue &&
formatSpecifier != 's' &&
formatSpecifier != 'c' &&
Char.ToUpper( formatSpecifier ) != 'X' &&
formatSpecifier != 'o' )
fieldPrecision = 6;
#region get next value parameter
// get next value parameter and convert value parameter depending on short / long indicator
if ( Parameters == null || paramIx >= Parameters.Length )
o = null;
else
{
o = Parameters[paramIx];
if ( shortLongIndicator == 'h' )
{
if ( o is int )
o = (short)( (int)o );
else if ( o is long )
o = (short)( (long)o );
else if ( o is uint )
o = (ushort)( (uint)o );
else if ( o is ulong )
o = (ushort)( (ulong)o );
}
else if ( shortLongIndicator == 'l' )
{
if ( o is short )
o = (long)( (short)o );
else if ( o is int )
o = (long)( (int)o );
else if ( o is ushort )
o = (ulong)( (ushort)o );
else if ( o is uint )
o = (ulong)( (uint)o );
}
}
#endregion
// convert value parameters to a string depending on the formatSpecifier
w = String.Empty;
switch ( formatSpecifier )
{
#region % - character
case '%': // % character
w = "%";
break;
#endregion
#region d - integer
case 'd': // integer
w = FormatNumber( ( flagGroupThousands ? "n" : "d" ), flagAlternate,
fieldLength, int.MinValue, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o );
defaultParamIx++;
break;
#endregion
#region i - integer
case 'i': // integer
goto case 'd';
#endregion
#region o - octal integer
case 'o': // octal integer - no leading zero
w = FormatOct( "o", flagAlternate,
fieldLength, int.MinValue, flagLeft2Right,
paddingCharacter, o );
defaultParamIx++;
break;
#endregion
#region x - hex integer
case 'x': // hex integer - no leading zero
w = FormatHex( "x", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
paddingCharacter, o );
defaultParamIx++;
break;
#endregion
#region X - hex integer
case 'X': // same as x but with capital hex characters
w = FormatHex( "X", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
paddingCharacter, o );
defaultParamIx++;
break;
#endregion
#region u - unsigned integer
case 'u': // unsigned integer
w = FormatNumber( ( flagGroupThousands ? "n" : "d" ), flagAlternate,
fieldLength, int.MinValue, flagLeft2Right,
false, false,
paddingCharacter, ToUnsigned( o ) );
defaultParamIx++;
break;
#endregion
#region c - character
case 'c': // character
if ( IsNumericType( o ) )
w = Convert.ToChar( o ).ToString();
else if ( o is char )
w = ( (char)o ).ToString();
else if ( o is string && ( (string)o ).Length > 0 )
w = ( (string)o )[0].ToString();
defaultParamIx++;
break;
#endregion
#region s - string
case 's': // string
string t = "{0" + ( fieldLength != int.MinValue ? "," + ( flagLeft2Right ? "-" : String.Empty ) + fieldLength.ToString() : String.Empty ) + ":s}";
w = o.ToString();
if ( fieldPrecision >= 0 )
w = w.Substring( 0, fieldPrecision );
if ( fieldLength != int.MinValue )
if ( flagLeft2Right )
w = w.PadRight( fieldLength, paddingCharacter );
else
w = w.PadLeft( fieldLength, paddingCharacter );
defaultParamIx++;
break;
#endregion
#region f - double number
case 'f': // double
w = FormatNumber( ( flagGroupThousands ? "n" : "f" ), flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o );
defaultParamIx++;
break;
#endregion
#region e - exponent number
case 'e': // double / exponent
w = FormatNumber( "e", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o );
defaultParamIx++;
break;
#endregion
#region E - exponent number
case 'E': // double / exponent
w = FormatNumber( "E", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o );
defaultParamIx++;
break;
#endregion
#region g - general number
case 'g': // double / exponent
w = FormatNumber( "g", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o );
defaultParamIx++;
break;
#endregion
#region G - general number
case 'G': // double / exponent
w = FormatNumber( "G", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o );
defaultParamIx++;
break;
#endregion
#region p - pointer
case 'p': // pointer
if ( o is IntPtr )
#if XBOX || SILVERLIGHT
w = ( (IntPtr)o ).ToString();
#else
w = "0x" + ( (IntPtr)o ).ToString( "x" );
#endif
defaultParamIx++;
break;
#endregion
#region n - number of processed chars so far
case 'n': // number of characters so far
w = FormatNumber( "d", flagAlternate,
fieldLength, int.MinValue, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, m.Index );
break;
#endregion
default:
w = String.Empty;
defaultParamIx++;
break;
}
// replace format parameter with parameter value
// and start searching for the next format parameter
// AFTER the position of the current inserted value
// to prohibit recursive matches if the value also
// includes a format specifier
f.Remove( m.Index, m.Length );
f.Insert( m.Index, w );
m = r.Match( f.ToString(), m.Index + w.Length );
}
return f.ToString();
}
#endregion
#endregion
#region Private Methods
#region FormatOCT
private static string FormatOct( string NativeFormat, bool Alternate,
int FieldLength, int FieldPrecision,
bool Left2Right,
char Padding, object Value )
{
string w = String.Empty;
string lengthFormat = "{0" + ( FieldLength != int.MinValue ?
"," + ( Left2Right ?
"-" :
String.Empty ) + FieldLength.ToString() :
String.Empty ) + "}";
if ( IsNumericType( Value ) )
{
w = Convert.ToString( UnboxToLong( Value, true ), 8 );
if ( Left2Right || Padding == ' ' )
{
if ( Alternate && w != "0" )
w = "0" + w;
w = String.Format( lengthFormat, w );
}
else
{
if ( FieldLength != int.MinValue )
w = w.PadLeft( FieldLength - ( Alternate && w != "0" ? 1 : 0 ), Padding );
if ( Alternate && w != "0" )
w = "0" + w;
}
}
return w;
}
#endregion
#region FormatHEX
private static string FormatHex( string NativeFormat, bool Alternate,
int FieldLength, int FieldPrecision,
bool Left2Right,
char Padding, object Value )
{
string w = String.Empty;
string lengthFormat = "{0" + ( FieldLength != int.MinValue ?
"," + ( Left2Right ?
"-" :
String.Empty ) + FieldLength.ToString() :
String.Empty ) + "}";
string numberFormat = "{0:" + NativeFormat + ( FieldPrecision != int.MinValue ?
FieldPrecision.ToString() :
String.Empty ) + "}";
if ( IsNumericType( Value ) )
{
w = String.Format( numberFormat, Value );
if ( Left2Right || Padding == ' ' )
{
if ( Alternate )
w = ( NativeFormat == "x" ? "0x" : "0X" ) + w;
w = String.Format( lengthFormat, w );
}
else
{
if ( FieldLength != int.MinValue )
w = w.PadLeft( FieldLength - ( Alternate ? 2 : 0 ), Padding );
if ( Alternate )
w = ( NativeFormat == "x" ? "0x" : "0X" ) + w;
}
}
return w;
}
#endregion
#region FormatNumber
private static string FormatNumber( string NativeFormat, bool Alternate,
int FieldLength, int FieldPrecision,
bool Left2Right,
bool PositiveSign, bool PositiveSpace,
char Padding, object Value )
{
string w = String.Empty;
string lengthFormat = "{0" + ( FieldLength != int.MinValue ?
"," + ( Left2Right ?
"-" :
String.Empty ) + FieldLength.ToString() :
String.Empty ) + "}";
string numberFormat = "{0:" + NativeFormat + ( FieldPrecision != int.MinValue ?
FieldPrecision.ToString() :
"0" ) + "}";
if ( IsNumericType( Value ) )
{
w = String.Format( numberFormat, Value );
if ( Left2Right || Padding == ' ' )
{
if ( IsPositive( Value, true ) )
w = ( PositiveSign ?
"+" : ( PositiveSpace ? " " : String.Empty ) ) + w;
w = String.Format( lengthFormat, w );
}
else
{
if ( w.StartsWith( "-" ) )
w = w.Substring( 1 );
if ( FieldLength != int.MinValue )
w = w.PadLeft( FieldLength - 1, Padding );
if ( IsPositive( Value, true ) )
w = ( PositiveSign ?
"+" : ( PositiveSpace ?
" " : ( FieldLength != int.MinValue ?
Padding.ToString() : String.Empty ) ) ) + w;
else
w = "-" + w;
}
}
return w;
}
#endregion
#endregion
}
}
......@@ -3,12 +3,18 @@ Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaInterface", "LuaInterface\LuaInterface.csproj", "{F55CABBB-4108-4A39-94E1-581FD46DC021}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KopiLua", "KopiLua\KopiLua.csproj", "{E8DDBC21-EF74-4ABA-9C49-BFC702BE25D8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E8DDBC21-EF74-4ABA-9C49-BFC702BE25D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E8DDBC21-EF74-4ABA-9C49-BFC702BE25D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8DDBC21-EF74-4ABA-9C49-BFC702BE25D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8DDBC21-EF74-4ABA-9C49-BFC702BE25D8}.Release|Any CPU.Build.0 = Release|Any CPU
{F55CABBB-4108-4A39-94E1-581FD46DC021}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F55CABBB-4108-4A39-94E1-581FD46DC021}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F55CABBB-4108-4A39-94E1-581FD46DC021}.Release|Any CPU.ActiveCfg = Release|Any CPU
......
......@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Reflection;
using LuaWrap;
namespace Mono.LuaInterface
namespace LuaInterface
{
/*
* Type checking and conversion functions.
......@@ -20,130 +20,130 @@ namespace Mono.LuaInterface
public CheckType(ObjectTranslator translator)
{
this.translator = translator;
this.translator = translator;
extractValues.Add(typeof(object).TypeHandle.Value.ToInt64(), new ExtractValue(getAsObject));
extractValues.Add(typeof(sbyte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsSbyte));
extractValues.Add(typeof(byte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsByte));
extractValues.Add(typeof(short).TypeHandle.Value.ToInt64(), new ExtractValue(getAsShort));
extractValues.Add(typeof(ushort).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUshort));
extractValues.Add(typeof(int).TypeHandle.Value.ToInt64(), new ExtractValue(getAsInt));
extractValues.Add(typeof(uint).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUint));
extractValues.Add(typeof(long).TypeHandle.Value.ToInt64(), new ExtractValue(getAsLong));
extractValues.Add(typeof(ulong).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUlong));
extractValues.Add(typeof(double).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDouble));
extractValues.Add(typeof(char).TypeHandle.Value.ToInt64(), new ExtractValue(getAsChar));
extractValues.Add(typeof(float).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFloat));
extractValues.Add(typeof(decimal).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDecimal));
extractValues.Add(typeof(bool).TypeHandle.Value.ToInt64(), new ExtractValue(getAsBoolean));
extractValues.Add(typeof(string).TypeHandle.Value.ToInt64(), new ExtractValue(getAsString));
extractValues.Add(typeof(LuaFunction).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFunction));
extractValues.Add(typeof(LuaTable).TypeHandle.Value.ToInt64(), new ExtractValue(getAsTable));
extractValues.Add(typeof(LuaUserData).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUserdata));
extractValues.Add(typeof(object).TypeHandle.Value.ToInt64(), new ExtractValue(getAsObject));
extractValues.Add(typeof(sbyte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsSbyte));
extractValues.Add(typeof(byte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsByte));
extractValues.Add(typeof(short).TypeHandle.Value.ToInt64(), new ExtractValue(getAsShort));
extractValues.Add(typeof(ushort).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUshort));
extractValues.Add(typeof(int).TypeHandle.Value.ToInt64(), new ExtractValue(getAsInt));
extractValues.Add(typeof(uint).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUint));
extractValues.Add(typeof(long).TypeHandle.Value.ToInt64(), new ExtractValue(getAsLong));
extractValues.Add(typeof(ulong).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUlong));
extractValues.Add(typeof(double).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDouble));
extractValues.Add(typeof(char).TypeHandle.Value.ToInt64(), new ExtractValue(getAsChar));
extractValues.Add(typeof(float).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFloat));
extractValues.Add(typeof(decimal).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDecimal));
extractValues.Add(typeof(bool).TypeHandle.Value.ToInt64(), new ExtractValue(getAsBoolean));
extractValues.Add(typeof(string).TypeHandle.Value.ToInt64(), new ExtractValue(getAsString));
extractValues.Add(typeof(LuaFunction).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFunction));
extractValues.Add(typeof(LuaTable).TypeHandle.Value.ToInt64(), new ExtractValue(getAsTable));
extractValues.Add(typeof(LuaUserData).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUserdata));
extractNetObject = new ExtractValue(getAsNetObject);
extractNetObject = new ExtractValue(getAsNetObject);
}
/*
* Checks if the value at Lua stack index stackPos matches paramType,
* returning a conversion function if it does and null otherwise.
*/
internal ExtractValue getExtractor(IReflect paramType)
{
return getExtractor(paramType.UnderlyingSystemType);
}
internal ExtractValue getExtractor(IReflect paramType)
{
return getExtractor(paramType.UnderlyingSystemType);
}
internal ExtractValue getExtractor(Type paramType)
{
if(paramType.IsByRef) paramType=paramType.GetElementType();
long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64();
if(extractValues.ContainsKey(runtimeHandleValue))
return extractValues[runtimeHandleValue];
else
if(extractValues.ContainsKey(runtimeHandleValue))
return extractValues[runtimeHandleValue];
else
return extractNetObject;
}
internal ExtractValue checkType(IntPtr luaState,int stackPos,Type paramType)
internal ExtractValue checkType(KopiLua.Lua.lua_State luaState,int stackPos,Type paramType)
{
LuaType luatype = LuaLib.lua_type(luaState, stackPos);
LuaType luatype = KopiLua.Lua.lua_type(luaState, stackPos).ToLuaType();
if(paramType.IsByRef) paramType=paramType.GetElementType();
Type underlyingType = Nullable.GetUnderlyingType(paramType);
if (underlyingType != null)
{
paramType = underlyingType; // Silently convert nullable types to their non null requics
}
Type underlyingType = Nullable.GetUnderlyingType(paramType);
if (underlyingType != null)
{
paramType = underlyingType; // Silently convert nullable types to their non null requics
}
long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64();
if (paramType.Equals(typeof(object)))
return extractValues[runtimeHandleValue];
if (LuaLib.lua_isnumber(luaState, stackPos))
if (KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return extractValues[runtimeHandleValue];
if (paramType == typeof(bool))
{
if (LuaLib.lua_isboolean(luaState, stackPos))
if (paramType == typeof(bool))
{
if (KopiLua.Lua.lua_isboolean(luaState, stackPos))
return extractValues[runtimeHandleValue];
}
else if (paramType == typeof(string))
{
if (LuaLib.lua_isstring(luaState, stackPos))
}
else if (paramType == typeof(string))
{
if (KopiLua.Lua.lua_isstring(luaState, stackPos).ToBoolean())
return extractValues[runtimeHandleValue];
else if (luatype == LuaType.Nil)
else if (luatype == LuaType.Nil)
return extractNetObject; // kevinh - silently convert nil to a null string pointer
}
else if (paramType == typeof(LuaTable))
{
if (luatype == LuaType.Table)
}
else if (paramType == typeof(LuaTable))
{
if (luatype == LuaType.Table)
return extractValues[runtimeHandleValue];
}
else if (paramType == typeof(LuaUserData))
{
if (luatype == LuaType.UserData)
}
else if (paramType == typeof(LuaUserData))
{
if (luatype == LuaType.UserData)
return extractValues[runtimeHandleValue];
}
else if (paramType == typeof(LuaFunction))
{
if (luatype == LuaType.Function)
}
else if (paramType == typeof(LuaFunction))
{
if (luatype == LuaType.Function)
return extractValues[runtimeHandleValue];
}
else if (typeof(Delegate).IsAssignableFrom(paramType) && luatype == LuaType.Function)
{
return new ExtractValue(new DelegateGenerator(translator, paramType).extractGenerated);
}
else if (paramType.IsInterface && luatype == LuaType.Table)
{
return new ExtractValue(new ClassGenerator(translator, paramType).extractGenerated);
}
else if ((paramType.IsInterface || paramType.IsClass) && luatype == LuaType.Nil)
{
// kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found
return extractNetObject;
}
else if (LuaLib.lua_type(luaState, stackPos) == LuaType.Table)
{
if (LuaLib.luaL_getmetafield(luaState, stackPos, "__index"))
{
object obj = translator.getNetObject(luaState, -1);
LuaLib.lua_settop(luaState, -2);
if (obj != null && paramType.IsAssignableFrom(obj.GetType()))
}
else if (typeof(Delegate).IsAssignableFrom(paramType) && luatype == LuaType.Function)
{
return new ExtractValue(new DelegateGenerator(translator, paramType).extractGenerated);
}
else if (paramType.IsInterface && luatype == LuaType.Table)
{
return new ExtractValue(new ClassGenerator(translator, paramType).extractGenerated);
}
else if ((paramType.IsInterface || paramType.IsClass) && luatype == LuaType.Nil)
{
// kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found
return extractNetObject;
}
else if (KopiLua.Lua.lua_type(luaState, stackPos).ToLuaType() == LuaType.Table)
{
if (KopiLua.Lua.luaL_getmetafield(luaState, stackPos, "__index").ToBoolean())
{
object obj = translator.getNetObject(luaState, -1);
KopiLua.Lua.lua_settop(luaState, -2);
if (obj != null && paramType.IsAssignableFrom(obj.GetType()))
return extractNetObject;
}
else
}
else
return null;
}
else
{
object obj = translator.getNetObject(luaState, stackPos);
if (obj != null && paramType.IsAssignableFrom(obj.GetType()))
}
else
{
object obj = translator.getNetObject(luaState, stackPos);
if (obj != null && paramType.IsAssignableFrom(obj.GetType()))
return extractNetObject;
}
}
return null;
return null;
}
/*
......@@ -151,136 +151,136 @@ namespace Mono.LuaInterface
* index stackPos as the desired type if it can, or null
* otherwise.
*/
private object getAsSbyte(IntPtr luaState,int stackPos)
private object getAsSbyte(KopiLua.Lua.lua_State luaState,int stackPos)
{
sbyte retVal=(sbyte)LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
sbyte retVal=(sbyte)KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsByte(IntPtr luaState,int stackPos)
private object getAsByte(KopiLua.Lua.lua_State luaState,int stackPos)
{
byte retVal=(byte)LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
byte retVal=(byte)KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsShort(IntPtr luaState,int stackPos)
private object getAsShort(KopiLua.Lua.lua_State luaState,int stackPos)
{
short retVal=(short)LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
short retVal=(short)KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsUshort(IntPtr luaState,int stackPos)
private object getAsUshort(KopiLua.Lua.lua_State luaState,int stackPos)
{
ushort retVal=(ushort)LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
ushort retVal=(ushort)KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsInt(IntPtr luaState,int stackPos)
private object getAsInt(KopiLua.Lua.lua_State luaState,int stackPos)
{
int retVal=(int)LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
int retVal=(int)KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsUint(IntPtr luaState,int stackPos)
private object getAsUint(KopiLua.Lua.lua_State luaState,int stackPos)
{
uint retVal=(uint)LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
uint retVal=(uint)KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsLong(IntPtr luaState,int stackPos)
private object getAsLong(KopiLua.Lua.lua_State luaState,int stackPos)
{
long retVal=(long)LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
long retVal=(long)KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsUlong(IntPtr luaState,int stackPos)
private object getAsUlong(KopiLua.Lua.lua_State luaState,int stackPos)
{
ulong retVal=(ulong)LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
ulong retVal=(ulong)KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsDouble(IntPtr luaState,int stackPos)
private object getAsDouble(KopiLua.Lua.lua_State luaState,int stackPos)
{
double retVal=LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
double retVal=KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsChar(IntPtr luaState,int stackPos)
private object getAsChar(KopiLua.Lua.lua_State luaState,int stackPos)
{
char retVal=(char)LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
char retVal=(char)KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsFloat(IntPtr luaState,int stackPos)
private object getAsFloat(KopiLua.Lua.lua_State luaState,int stackPos)
{
float retVal=(float)LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
float retVal=(float)KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsDecimal(IntPtr luaState,int stackPos)
private object getAsDecimal(KopiLua.Lua.lua_State luaState,int stackPos)
{
decimal retVal=(decimal)LuaLib.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaLib.lua_isnumber(luaState,stackPos)) return null;
decimal retVal=(decimal)KopiLua.Lua.lua_tonumber(luaState,stackPos);
if(retVal==0 && !KopiLua.Lua.lua_isnumber(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsBoolean(IntPtr luaState,int stackPos)
private object getAsBoolean(KopiLua.Lua.lua_State luaState,int stackPos)
{
return LuaLib.lua_toboolean(luaState,stackPos);
return KopiLua.Lua.lua_toboolean(luaState,stackPos);
}
private object getAsString(IntPtr luaState,int stackPos)
private object getAsString(KopiLua.Lua.lua_State luaState,int stackPos)
{
string retVal=LuaLib.lua_tostring(luaState,stackPos);
if(retVal=="" && !LuaLib.lua_isstring(luaState,stackPos)) return null;
string retVal=KopiLua.Lua.lua_tostring(luaState,stackPos).ToString();
if(retVal==string.Empty && !KopiLua.Lua.lua_isstring(luaState,stackPos).ToBoolean()) return null;
return retVal;
}
private object getAsTable(IntPtr luaState,int stackPos)
private object getAsTable(KopiLua.Lua.lua_State luaState,int stackPos)
{
return translator.getTable(luaState,stackPos);
}
private object getAsFunction(IntPtr luaState,int stackPos)
private object getAsFunction(KopiLua.Lua.lua_State luaState,int stackPos)
{
return translator.getFunction(luaState,stackPos);
}
private object getAsUserdata(IntPtr luaState,int stackPos)
private object getAsUserdata(KopiLua.Lua.lua_State luaState,int stackPos)
{
return translator.getUserData(luaState,stackPos);
}
public object getAsObject(IntPtr luaState,int stackPos)
public object getAsObject(KopiLua.Lua.lua_State luaState,int stackPos)
{
if(LuaLib.lua_type(luaState,stackPos)==LuaType.Table)
if(KopiLua.Lua.lua_type(luaState,stackPos).ToLuaType()==LuaType.Table)
{
if(LuaLib.luaL_getmetafield(luaState,stackPos,"__index"))
if(KopiLua.Lua.luaL_getmetafield(luaState,stackPos,"__index").ToBoolean())
{
if(LuaLib.luaL_checkmetatable(luaState,-1))
{
LuaLib.lua_insert(luaState,stackPos);
LuaLib.lua_remove(luaState,stackPos+1);
KopiLua.Lua.lua_insert(luaState,stackPos);
KopiLua.Lua.lua_remove(luaState,stackPos+1);
}
else
{
LuaLib.lua_settop(luaState,-2);
KopiLua.Lua.lua_settop(luaState,-2);
}
}
}
object obj=translator.getObject(luaState,stackPos);
return obj;
}
public object getAsNetObject(IntPtr luaState,int stackPos)
public object getAsNetObject(KopiLua.Lua.lua_State luaState,int stackPos)
{
object obj=translator.getNetObject(luaState,stackPos);
if(obj==null && LuaLib.lua_type(luaState,stackPos)==LuaType.Table)
if(obj==null && KopiLua.Lua.lua_type(luaState,stackPos).ToLuaType()==LuaType.Table)
{
if(LuaLib.luaL_getmetafield(luaState,stackPos,"__index"))
if(KopiLua.Lua.luaL_getmetafield(luaState,stackPos,"__index").ToBoolean())
{
if(LuaLib.luaL_checkmetatable(luaState,-1))
{
LuaLib.lua_insert(luaState,stackPos);
LuaLib.lua_remove(luaState,stackPos+1);
KopiLua.Lua.lua_insert(luaState,stackPos);
KopiLua.Lua.lua_remove(luaState,stackPos+1);
obj=translator.getNetObject(luaState,stackPos);
}
else
{
LuaLib.lua_settop(luaState,-2);
KopiLua.Lua.lua_settop(luaState,-2);
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment