Commit b969a882 authored by Megax's avatar Megax
Browse files

* Project fajlok at lettek alakitva. Igy most mindegyik normalisan hasznalhato...

* Project fajlok at lettek alakitva. Igy most mindegyik normalisan hasznalhato forditasnal. Nincsenek hibak. KopiLua-ba kerult egy fix. Nem ertem mitol jott elo az a hiba ami elojott de most van a kodban (vagy is volt mert fixaltam).
parent d7bb0c93
/*
** $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: 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);
}
}
}
/*
** $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
}
}
#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
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Reflection;
using System.Collections.Generic;
using LuaInterface.Method;
using LuaInterface.Extensions;
namespace LuaInterface
{
using LuaCore = KopiLua.Lua;
/*
* Type checking and conversion functions.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class CheckType
{
private Dictionary<long, ExtractValue> extractValues = new Dictionary<long, ExtractValue>();
private ExtractValue extractNetObject;
private ObjectTranslator translator;
public CheckType(ObjectTranslator 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));
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(Type paramType)
{
if(paramType.IsByRef)
paramType = paramType.GetElementType();
long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64();
return extractValues.ContainsKey(runtimeHandleValue) ? extractValues[runtimeHandleValue] : extractNetObject;
}
internal ExtractValue checkType(LuaCore.lua_State luaState, int stackPos, Type paramType)
{
var luatype = LuaCore.lua_type(luaState, stackPos).ToLuaTypes();
if(paramType.IsByRef)
paramType = paramType.GetElementType();
var underlyingType = Nullable.GetUnderlyingType(paramType);
if(!underlyingType.IsNull())
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];
//CP: Added support for generic parameters
if(paramType.IsGenericParameter)
{
if(luatype == LuaTypes.Boolean)
return extractValues[typeof(bool).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.String)
return extractValues[typeof(string).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.Table)
return extractValues[typeof(LuaTable).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.UserData)
return extractValues[typeof(object).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.Function)
return extractValues[typeof(LuaFunction).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.Number)
return extractValues[typeof(double).TypeHandle.Value.ToInt64()];
//else
//;//an unsupported type was encountered
}
if(LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return extractValues[runtimeHandleValue];
if(paramType == typeof(bool))
{
if(LuaCore.lua_isboolean(luaState, stackPos))
return extractValues[runtimeHandleValue];
}
else if(paramType == typeof(string))
{
if(LuaCore.lua_isstring(luaState, stackPos).ToBoolean())
return extractValues[runtimeHandleValue];
else if(luatype == LuaTypes.Nil)
return extractNetObject; // kevinh - silently convert nil to a null string pointer
}
else if(paramType == typeof(LuaTable))
{
if(luatype == LuaTypes.Table)
return extractValues[runtimeHandleValue];
}
else if(paramType == typeof(LuaUserData))
{
if(luatype == LuaTypes.UserData)
return extractValues[runtimeHandleValue];
}
else if(paramType == typeof(LuaFunction))
{
if(luatype == LuaTypes.Function)
return extractValues[runtimeHandleValue];
}
else if(typeof(Delegate).IsAssignableFrom(paramType) && luatype == LuaTypes.Function)
return new ExtractValue(new DelegateGenerator(translator, paramType).extractGenerated);
else if(paramType.IsInterface && luatype == LuaTypes.Table)
return new ExtractValue(new ClassGenerator(translator, paramType).extractGenerated);
else if((paramType.IsInterface || paramType.IsClass) && luatype == LuaTypes.Nil)
{
// kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found
return extractNetObject;
}
else if(LuaCore.lua_type(luaState, stackPos).ToLuaTypes() == LuaTypes.Table)
{
if(LuaCore.luaL_getmetafield(luaState, stackPos, "__index").ToBoolean())
{
object obj = translator.getNetObject(luaState, -1);
LuaCore.lua_settop(luaState, -2);
if(!obj.IsNull() && paramType.IsAssignableFrom(obj.GetType()))
return extractNetObject;
}
else
return null;
}
else
{
object obj = translator.getNetObject(luaState, stackPos);
if(!obj.IsNull() && paramType.IsAssignableFrom(obj.GetType()))
return extractNetObject;
}
return null;
}
/*
* The following functions return the value in the Lua stack
* index stackPos as the desired type if it can, or null
* otherwise.
*/
private object getAsSbyte(LuaCore.lua_State luaState, int stackPos)
{
sbyte retVal = (sbyte)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsByte(LuaCore.lua_State luaState, int stackPos)
{
byte retVal = (byte)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsShort(LuaCore.lua_State luaState, int stackPos)
{
short retVal = (short)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsUshort(LuaCore.lua_State luaState, int stackPos)
{
ushort retVal = (ushort)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsInt(LuaCore.lua_State luaState, int stackPos)
{
int retVal = (int)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsUint(LuaCore.lua_State luaState, int stackPos)
{
uint retVal = (uint)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsLong(LuaCore.lua_State luaState, int stackPos)
{
long retVal = (long)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsUlong(LuaCore.lua_State luaState, int stackPos)
{
ulong retVal = (ulong)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsDouble(LuaCore.lua_State luaState, int stackPos)
{
double retVal = LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsChar(LuaCore.lua_State luaState, int stackPos)
{
char retVal = (char)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsFloat(LuaCore.lua_State luaState, int stackPos)
{
float retVal = (float)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsDecimal(LuaCore.lua_State luaState, int stackPos)
{
decimal retVal = (decimal)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsBoolean(LuaCore.lua_State luaState, int stackPos)
{
return LuaCore.lua_toboolean(luaState, stackPos);
}
private object getAsString(LuaCore.lua_State luaState, int stackPos)
{
string retVal = LuaCore.lua_tostring(luaState, stackPos).ToString();
if(retVal == string.Empty && !LuaCore.lua_isstring(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsTable(LuaCore.lua_State luaState, int stackPos)
{
return translator.getTable(luaState, stackPos);
}
private object getAsFunction(LuaCore.lua_State luaState, int stackPos)
{
return translator.getFunction(luaState, stackPos);
}
private object getAsUserdata(LuaCore.lua_State luaState, int stackPos)
{
return translator.getUserData(luaState, stackPos);
}
public object getAsObject(LuaCore.lua_State luaState, int stackPos)
{
if(LuaCore.lua_type(luaState, stackPos).ToLuaTypes() == LuaTypes.Table)
{
if(LuaCore.luaL_getmetafield(luaState, stackPos, "__index").ToBoolean())
{
if(LuaLib.luaL_checkmetatable(luaState, -1))
{
LuaCore.lua_insert(luaState, stackPos);
LuaCore.lua_remove(luaState, stackPos+1);
}
else
LuaCore.lua_settop(luaState, -2);
}
}
object obj = translator.getObject(luaState, stackPos);
return obj;
}
public object getAsNetObject(LuaCore.lua_State luaState, int stackPos)
{
object obj = translator.getNetObject(luaState, stackPos);
if(obj.IsNull() && LuaCore.lua_type(luaState, stackPos).ToLuaTypes() == LuaTypes.Table)
{
if(LuaCore.luaL_getmetafield(luaState, stackPos, "__index").ToBoolean())
{
if(LuaLib.luaL_checkmetatable(luaState, -1))
{
LuaCore.lua_insert(luaState, stackPos);
LuaCore.lua_remove(luaState, stackPos+1);
obj = translator.getNetObject(luaState, stackPos);
}
else
LuaCore.lua_settop(luaState, -2);
}
}
return obj;
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Reflection;
using System.Collections.Generic;
using LuaInterface.Method;
using LuaInterface.Extensions;
namespace LuaInterface
{
using LuaCore = KopiLua.Lua;
/*
* Type checking and conversion functions.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class CheckType
{
private Dictionary<long, ExtractValue> extractValues = new Dictionary<long, ExtractValue>();
private ExtractValue extractNetObject;
private ObjectTranslator translator;
public CheckType(ObjectTranslator 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));
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(Type paramType)
{
if(paramType.IsByRef)
paramType = paramType.GetElementType();
long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64();
return extractValues.ContainsKey(runtimeHandleValue) ? extractValues[runtimeHandleValue] : extractNetObject;
}
internal ExtractValue checkType(LuaCore.lua_State luaState, int stackPos, Type paramType)
{
var luatype = LuaCore.lua_type(luaState, stackPos).ToLuaTypes();
if(paramType.IsByRef)
paramType = paramType.GetElementType();
var underlyingType = Nullable.GetUnderlyingType(paramType);
if(!underlyingType.IsNull())
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];
//CP: Added support for generic parameters
if(paramType.IsGenericParameter)
{
if(luatype == LuaTypes.Boolean)
return extractValues[typeof(bool).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.String)
return extractValues[typeof(string).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.Table)
return extractValues[typeof(LuaTable).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.UserData)
return extractValues[typeof(object).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.Function)
return extractValues[typeof(LuaFunction).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.Number)
return extractValues[typeof(double).TypeHandle.Value.ToInt64()];
//else
//;//an unsupported type was encountered
}
if(LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return extractValues[runtimeHandleValue];
if(paramType == typeof(bool))
{
if(LuaCore.lua_isboolean(luaState, stackPos))
return extractValues[runtimeHandleValue];
}
else if(paramType == typeof(string))
{
if(LuaCore.lua_isstring(luaState, stackPos).ToBoolean())
return extractValues[runtimeHandleValue];
else if(luatype == LuaTypes.Nil)
return extractNetObject; // kevinh - silently convert nil to a null string pointer
}
else if(paramType == typeof(LuaTable))
{
if(luatype == LuaTypes.Table)
return extractValues[runtimeHandleValue];
}
else if(paramType == typeof(LuaUserData))
{
if(luatype == LuaTypes.UserData)
return extractValues[runtimeHandleValue];
}
else if(paramType == typeof(LuaFunction))
{
if(luatype == LuaTypes.Function)
return extractValues[runtimeHandleValue];
}
else if(typeof(Delegate).IsAssignableFrom(paramType) && luatype == LuaTypes.Function)
return new ExtractValue(new DelegateGenerator(translator, paramType).extractGenerated);
else if(paramType.IsInterface && luatype == LuaTypes.Table)
return new ExtractValue(new ClassGenerator(translator, paramType).extractGenerated);
else if((paramType.IsInterface || paramType.IsClass) && luatype == LuaTypes.Nil)
{
// kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found
return extractNetObject;
}
else if(LuaCore.lua_type(luaState, stackPos).ToLuaTypes() == LuaTypes.Table)
{
if(LuaCore.luaL_getmetafield(luaState, stackPos, "__index").ToBoolean())
{
object obj = translator.getNetObject(luaState, -1);
LuaCore.lua_settop(luaState, -2);
if(!obj.IsNull() && paramType.IsAssignableFrom(obj.GetType()))
return extractNetObject;
}
else
return null;
}
else
{
object obj = translator.getNetObject(luaState, stackPos);
if(!obj.IsNull() && paramType.IsAssignableFrom(obj.GetType()))
return extractNetObject;
}
return null;
}
/*
* The following functions return the value in the Lua stack
* index stackPos as the desired type if it can, or null
* otherwise.
*/
private object getAsSbyte(LuaCore.lua_State luaState, int stackPos)
{
sbyte retVal = (sbyte)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsByte(LuaCore.lua_State luaState, int stackPos)
{
byte retVal = (byte)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsShort(LuaCore.lua_State luaState, int stackPos)
{
short retVal = (short)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsUshort(LuaCore.lua_State luaState, int stackPos)
{
ushort retVal = (ushort)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsInt(LuaCore.lua_State luaState, int stackPos)
{
int retVal = (int)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsUint(LuaCore.lua_State luaState, int stackPos)
{
uint retVal = (uint)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsLong(LuaCore.lua_State luaState, int stackPos)
{
long retVal = (long)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsUlong(LuaCore.lua_State luaState, int stackPos)
{
ulong retVal = (ulong)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsDouble(LuaCore.lua_State luaState, int stackPos)
{
double retVal = LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsChar(LuaCore.lua_State luaState, int stackPos)
{
char retVal = (char)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsFloat(LuaCore.lua_State luaState, int stackPos)
{
float retVal = (float)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsDecimal(LuaCore.lua_State luaState, int stackPos)
{
decimal retVal = (decimal)LuaCore.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !LuaCore.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsBoolean(LuaCore.lua_State luaState, int stackPos)
{
return LuaCore.lua_toboolean(luaState, stackPos);
}
private object getAsString(LuaCore.lua_State luaState, int stackPos)
{
string retVal = LuaCore.lua_tostring(luaState, stackPos).ToString();
if(retVal == string.Empty && !LuaCore.lua_isstring(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsTable(LuaCore.lua_State luaState, int stackPos)
{
return translator.getTable(luaState, stackPos);
}
private object getAsFunction(LuaCore.lua_State luaState, int stackPos)
{
return translator.getFunction(luaState, stackPos);
}
private object getAsUserdata(LuaCore.lua_State luaState, int stackPos)
{
return translator.getUserData(luaState, stackPos);
}
public object getAsObject(LuaCore.lua_State luaState, int stackPos)
{
if(LuaCore.lua_type(luaState, stackPos).ToLuaTypes() == LuaTypes.Table)
{
if(LuaCore.luaL_getmetafield(luaState, stackPos, "__index").ToBoolean())
{
if(LuaLib.luaL_checkmetatable(luaState, -1))
{
LuaCore.lua_insert(luaState, stackPos);
LuaCore.lua_remove(luaState, stackPos+1);
}
else
LuaCore.lua_settop(luaState, -2);
}
}
object obj = translator.getObject(luaState, stackPos);
return obj;
}
public object getAsNetObject(LuaCore.lua_State luaState, int stackPos)
{
object obj = translator.getNetObject(luaState, stackPos);
if(obj.IsNull() && LuaCore.lua_type(luaState, stackPos).ToLuaTypes() == LuaTypes.Table)
{
if(LuaCore.luaL_getmetafield(luaState, stackPos, "__index").ToBoolean())
{
if(LuaLib.luaL_checkmetatable(luaState, -1))
{
LuaCore.lua_insert(luaState, stackPos);
LuaCore.lua_remove(luaState, stackPos+1);
obj = translator.getNetObject(luaState, stackPos);
}
else
LuaCore.lua_settop(luaState, -2);
}
}
return obj;
}
}
}
\ No newline at end of file
......@@ -15,10 +15,10 @@
* 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,
* 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,
* 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.
*/
......
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Event
{
/// <summary>
/// Event codes for lua hook function
/// </summary>
/// <remarks>
/// Do not change any of the values because they must match the lua values
/// </remarks>
/// <author>Reinhard Ostermeier</author>
public enum EventCodes
{
LUA_HOOKCALL = 0,
LUA_HOOKRET = 1,
LUA_HOOKLINE = 2,
LUA_HOOKCOUNT = 3,
LUA_HOOKTAILRET = 4
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Event
{
/// <summary>
/// Event codes for lua hook function
/// </summary>
/// <remarks>
/// Do not change any of the values because they must match the lua values
/// </remarks>
/// <author>Reinhard Ostermeier</author>
public enum EventCodes
{
LUA_HOOKCALL = 0,
LUA_HOOKRET = 1,
LUA_HOOKLINE = 2,
LUA_HOOKCOUNT = 3,
LUA_HOOKTAILRET = 4
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Event
{
/// <summary>
/// Event masks for lua hook callback
/// </summary>
/// <remarks>
/// Do not change any of the values because they must match the lua values
/// </remarks>
/// <author>Reinhard Ostermeier</author>
[Flags]
public enum EventMasks
{
LUA_MASKCALL = (1 << EventCodes.LUA_HOOKCALL),
LUA_MASKRET = (1 << EventCodes.LUA_HOOKRET),
LUA_MASKLINE = (1 << EventCodes.LUA_HOOKLINE),
LUA_MASKCOUNT = (1 << EventCodes.LUA_HOOKCOUNT),
LUA_MASKALL = Int32.MaxValue
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Event
{
/// <summary>
/// Event masks for lua hook callback
/// </summary>
/// <remarks>
/// Do not change any of the values because they must match the lua values
/// </remarks>
/// <author>Reinhard Ostermeier</author>
[Flags]
public enum EventMasks
{
LUA_MASKCALL = (1 << EventCodes.LUA_HOOKCALL),
LUA_MASKRET = (1 << EventCodes.LUA_HOOKRET),
LUA_MASKLINE = (1 << EventCodes.LUA_HOOKLINE),
LUA_MASKCOUNT = (1 << EventCodes.LUA_HOOKCOUNT),
LUA_MASKALL = Int32.MaxValue
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Event
{
public class HookExceptionEventArgs : EventArgs
{
private readonly Exception m_Exception;
public Exception Exception
{
get { return m_Exception; }
}
public HookExceptionEventArgs(Exception ex)
{
m_Exception = ex;
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Event
{
public class HookExceptionEventArgs : EventArgs
{
private readonly Exception m_Exception;
public Exception Exception
{
get { return m_Exception; }
}
public HookExceptionEventArgs(Exception ex)
{
m_Exception = ex;
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Event
{
/// <summary>
/// Structure for lua debug information
/// </summary>
/// <remarks>
/// Do not change this struct because it must match the lua structure lua_debug
/// </remarks>
/// <author>Reinhard Ostermeier</author>
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct LuaDebug
{
public EventCodes eventCode;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string name;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string namewhat;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string what;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string source;
public int currentline;
public int nups;
public int linedefined;
public int lastlinedefined;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 60/*LUA_IDSIZE*/)]
public string shortsrc;
public int i_ci;
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Event
{
/// <summary>
/// Structure for lua debug information
/// </summary>
/// <remarks>
/// Do not change this struct because it must match the lua structure lua_debug
/// </remarks>
/// <author>Reinhard Ostermeier</author>
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct LuaDebug
{
public EventCodes eventCode;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string name;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string namewhat;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string what;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string source;
public int currentline;
public int nups;
public int linedefined;
public int lastlinedefined;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 60/*LUA_IDSIZE*/)]
public string shortsrc;
public int i_ci;
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Runtime.Serialization;
namespace LuaInterface.Exceptions
{
/// <summary>
/// Exceptions thrown by the Lua runtime
/// </summary>
[Serializable]
public class LuaException : Exception
{
public LuaException()
{
}
public LuaException(string message) : base(message)
{
}
public LuaException(string message, Exception innerException) : base(message, innerException)
{
}
protected LuaException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Runtime.Serialization;
namespace LuaInterface.Exceptions
{
/// <summary>
/// Exceptions thrown by the Lua runtime
/// </summary>
[Serializable]
public class LuaException : Exception
{
public LuaException()
{
}
public LuaException(string message) : base(message)
{
}
public LuaException(string message, Exception innerException) : base(message, innerException)
{
}
protected LuaException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Exceptions
{
/// <summary>
/// Exceptions thrown by the Lua runtime because of errors in the script
/// </summary>
public class LuaScriptException : LuaException
{
/// <summary>
/// Returns true if the exception has occured as the result of a .NET exception in user code
/// </summary>
public bool IsNetException { get; private set; }
private readonly string source;
/// <summary>
/// The position in the script where the exception was triggered.
/// </summary>
public override string Source { get { return source; } }
/// <summary>
/// Creates a new Lua-only exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="source">The position in the script where the exception was triggered.</param>
public LuaScriptException(string message, string source) : base(message)
{
this.source = source;
}
/// <summary>
/// Creates a new .NET wrapping exception.
/// </summary>
/// <param name="innerException">The .NET exception triggered by user-code.</param>
/// <param name="source">The position in the script where the exception was triggered.</param>
public LuaScriptException(Exception innerException, string source)
: base("A .NET exception occured in user-code", innerException)
{
this.source = source;
this.IsNetException = true;
}
public override string ToString()
{
// Prepend the error source
return GetType().FullName + ": " + source + Message;
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Exceptions
{
/// <summary>
/// Exceptions thrown by the Lua runtime because of errors in the script
/// </summary>
public class LuaScriptException : LuaException
{
/// <summary>
/// Returns true if the exception has occured as the result of a .NET exception in user code
/// </summary>
public bool IsNetException { get; private set; }
private readonly string source;
/// <summary>
/// The position in the script where the exception was triggered.
/// </summary>
public override string Source { get { return source; } }
/// <summary>
/// Creates a new Lua-only exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="source">The position in the script where the exception was triggered.</param>
public LuaScriptException(string message, string source) : base(message)
{
this.source = source;
}
/// <summary>
/// Creates a new .NET wrapping exception.
/// </summary>
/// <param name="innerException">The .NET exception triggered by user-code.</param>
/// <param name="source">The position in the script where the exception was triggered.</param>
public LuaScriptException(Exception innerException, string source)
: base("A .NET exception occured in user-code", innerException)
{
this.source = source;
this.IsNetException = true;
}
public override string ToString()
{
// Prepend the error source
return GetType().FullName + ": " + source + Message;
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Extensions
{
/// <summary>
/// Some random extension stuff.
/// </summary>
static class GeneralExtensions
{
/// <summary>
/// Determines whether the specified obj is null.
/// </summary>
/// <param name="obj">The obj.</param>
/// <returns>
/// <c>true</c> if the specified obj is null; otherwise, <c>false</c>.
/// </returns>
public static bool IsNull(this object obj)
{
return (obj == null);
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Extensions
{
/// <summary>
/// Some random extension stuff.
/// </summary>
static class GeneralExtensions
{
/// <summary>
/// Determines whether the specified obj is null.
/// </summary>
/// <param name="obj">The obj.</param>
/// <returns>
/// <c>true</c> if the specified obj is null; otherwise, <c>false</c>.
/// </returns>
public static bool IsNull(this object obj)
{
return (obj == null);
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
/*
* Class used for generating delegates that get a table from the Lua
* stack as a an object of a specific type.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class ClassGenerator
{
private ObjectTranslator translator;
private Type klass;
public ClassGenerator(ObjectTranslator translator, Type klass)
{
this.translator = translator;
this.klass = klass;
}
public object extractGenerated(KopiLua.Lua.lua_State luaState, int stackPos)
{
return CodeGeneration.Instance.GetClassInstance(klass, translator.getTable(luaState, stackPos));
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
/*
* Class used for generating delegates that get a table from the Lua
* stack as a an object of a specific type.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class ClassGenerator
{
private ObjectTranslator translator;
private Type klass;
public ClassGenerator(ObjectTranslator translator, Type klass)
{
this.translator = translator;
this.klass = klass;
}
public object extractGenerated(KopiLua.Lua.lua_State luaState, int stackPos)
{
return CodeGeneration.Instance.GetClassInstance(klass, translator.getTable(luaState, stackPos));
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
using System.Collections.Generic;
using LuaInterface.Method;
namespace LuaInterface
{
/*
* Dynamically generates new types from existing types and
* Lua function and table values. Generated types are event handlers,
* delegates, interface implementations and subclasses.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class CodeGeneration
{
private Dictionary<Type, LuaClassType> classCollection = new Dictionary<Type, LuaClassType>();
private Dictionary<Type, Type> eventHandlerCollection = new Dictionary<Type, Type>();
private Dictionary<Type, Type> delegateCollection = new Dictionary<Type, Type>();
private static readonly CodeGeneration instance = new CodeGeneration();
private Type eventHandlerParent = typeof(LuaEventHandler);
private Type delegateParent = typeof(LuaDelegate);
private Type classHelper = typeof(LuaClassHelper);
private AssemblyName assemblyName;
private AssemblyBuilder newAssembly;
private ModuleBuilder newModule;
private int luaClassNumber = 1;
static CodeGeneration()
{
}
private CodeGeneration()
{
// Create an assembly name
assemblyName = new AssemblyName();
assemblyName.Name = "LuaInterface_generatedcode";
// Create a new assembly with one module.
newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
newModule = newAssembly.DefineDynamicModule("LuaInterface_generatedcode");
}
/*
* Singleton instance of the class
*/
public static CodeGeneration Instance
{
get { return instance; }
}
/*
* Generates an event handler that calls a Lua function
*/
private Type GenerateEvent(Type eventHandlerType)
{
string typeName;
lock(this)
{
typeName = "LuaGeneratedClass" + luaClassNumber;
luaClassNumber++;
}
// Define a public class in the assembly, called typeName
var myType = newModule.DefineType(typeName, TypeAttributes.Public, eventHandlerParent);
// Defines the handler method. Its signature is void(object, <subclassofEventArgs>)
var paramTypes = new Type[2];
paramTypes[0] = typeof(object);
paramTypes[1] = eventHandlerType;
var returnType = typeof(void);
var handleMethod = myType.DefineMethod("HandleEvent", MethodAttributes.Public | MethodAttributes.HideBySig, returnType, paramTypes);
// Emits the IL for the method. It loads the arguments
// and calls the handleEvent method of the base class
ILGenerator generator = handleMethod.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldarg_2);
var miGenericEventHandler = eventHandlerParent.GetMethod("handleEvent");
generator.Emit(OpCodes.Call, miGenericEventHandler);
// returns
generator.Emit(OpCodes.Ret);
// creates the new type
return myType.CreateType();
}
/*
* Generates a type that can be used for instantiating a delegate
* of the provided type, given a Lua function.
*/
private Type GenerateDelegate(Type delegateType)
{
string typeName;
lock(this)
{
typeName = "LuaGeneratedClass" + luaClassNumber;
luaClassNumber++;
}
// Define a public class in the assembly, called typeName
var myType = newModule.DefineType(typeName, TypeAttributes.Public, delegateParent);
// Defines the delegate method with the same signature as the
// Invoke method of delegateType
var invokeMethod = delegateType.GetMethod("Invoke");
var paramInfo = invokeMethod.GetParameters();
var paramTypes = new Type[paramInfo.Length];
var returnType = invokeMethod.ReturnType;
// Counts out and ref params, for use later
int nOutParams = 0; int nOutAndRefParams = 0;
for(int i = 0; i < paramTypes.Length; i++)
{
paramTypes[i] = paramInfo[i].ParameterType;
if((!paramInfo[i].IsIn) && paramInfo[i].IsOut)
nOutParams++;
if(paramTypes[i].IsByRef)
nOutAndRefParams++;
}
int[] refArgs = new int[nOutAndRefParams];
var delegateMethod = myType.DefineMethod("CallFunction", invokeMethod.Attributes, returnType, paramTypes);
// Generates the IL for the method
ILGenerator generator = delegateMethod.GetILGenerator( );
generator.DeclareLocal(typeof(object[])); // original arguments
generator.DeclareLocal(typeof(object[])); // with out-only arguments removed
generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments
if(!(returnType == typeof(void))) // return value
generator.DeclareLocal(returnType);
else
generator.DeclareLocal(typeof(object));
// Initializes local variables
generator.Emit(OpCodes.Ldc_I4, paramTypes.Length);
generator.Emit(OpCodes.Newarr, typeof(object));
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldc_I4, paramTypes.Length-nOutParams);
generator.Emit(OpCodes.Newarr, typeof(object));
generator.Emit(OpCodes.Stloc_1);
generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams);
generator.Emit(OpCodes.Newarr, typeof(int));
generator.Emit(OpCodes.Stloc_2);
// Stores the arguments in the local variables
for(int iArgs = 0, iInArgs = 0, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++)
{
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4, iArgs);
generator.Emit(OpCodes.Ldarg, iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType());
}
else
generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box, paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
if(paramTypes[iArgs].IsByRef)
{
generator.Emit(OpCodes.Ldloc_2);
generator.Emit(OpCodes.Ldc_I4, iOutArgs);
generator.Emit(OpCodes.Ldc_I4, iArgs);
generator.Emit(OpCodes.Stelem_I4);
refArgs[iOutArgs] = iArgs;
iOutArgs++;
}
if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut))
{
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldc_I4, iInArgs);
generator.Emit(OpCodes.Ldarg, iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType());
}
else
generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box, paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
iInArgs++;
}
}
// Calls the callFunction method of the base class
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldloc_2);
var miGenericEventHandler = delegateParent.GetMethod("callFunction");
generator.Emit(OpCodes.Call, miGenericEventHandler);
// Stores return value
if(returnType == typeof(void))
{
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ldnull);
}
else if(returnType.IsValueType)
{
generator.Emit(OpCodes.Unbox, returnType);
generator.Emit(OpCodes.Ldobj, returnType);
}
else
generator.Emit(OpCodes.Castclass, returnType);
generator.Emit(OpCodes.Stloc_3);
// Stores new value of out and ref params
for(int i = 0; i < refArgs.Length; i++)
{
generator.Emit(OpCodes.Ldarg, refArgs[i]+1);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4, refArgs[i]);
generator.Emit(OpCodes.Ldelem_Ref);
if(paramTypes[refArgs[i]].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType());
}
else
{
generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stind_Ref);
}
}
// Returns
if(!(returnType == typeof(void)))
generator.Emit(OpCodes.Ldloc_3);
generator.Emit(OpCodes.Ret);
return myType.CreateType(); // creates the new type
}
/*
* Generates an implementation of klass, if it is an interface, or
* a subclass of klass that delegates its virtual methods to a Lua table.
*/
public void GenerateClass(Type klass, out Type newType, out Type[][] returnTypes)
{
string typeName;
lock(this)
{
typeName = "LuaGeneratedClass" + luaClassNumber;
luaClassNumber++;
}
TypeBuilder myType;
// Define a public class in the assembly, called typeName
if(klass.IsInterface)
myType = newModule.DefineType(typeName, TypeAttributes.Public, typeof(object), new Type[] { klass, typeof(ILuaGeneratedType) });
else
myType = newModule.DefineType(typeName, TypeAttributes.Public, klass, new Type[] { typeof(ILuaGeneratedType) });
// Field that stores the Lua table
var luaTableField = myType.DefineField("__luaInterface_luaTable", typeof(LuaTable), FieldAttributes.Public);
// Field that stores the return types array
var returnTypesField = myType.DefineField("__luaInterface_returnTypes", typeof(Type[][]), FieldAttributes.Public);
// Generates the constructor for the new type, it takes a Lua table and an array
// of return types and stores them in the respective fields
var constructor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(LuaTable), typeof(Type[][]) });
ILGenerator generator = constructor.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
if(klass.IsInterface)
generator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
else
generator.Emit(OpCodes.Call, klass.GetConstructor(Type.EmptyTypes));
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, luaTableField);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_2);
generator.Emit(OpCodes.Stfld, returnTypesField);
generator.Emit(OpCodes.Ret);
// Generates overriden versions of the klass' public virtual methods
var classMethods = klass.GetMethods();
returnTypes = new Type[classMethods.Length][];
int i = 0;
foreach(var method in classMethods)
{
if(klass.IsInterface)
{
GenerateMethod(myType, method, MethodAttributes.HideBySig|MethodAttributes.Virtual|MethodAttributes.NewSlot,
i, luaTableField, returnTypesField, false, out returnTypes[i]);
i++;
}
else
{
if(!method.IsPrivate && !method.IsFinal && method.IsVirtual)
{
GenerateMethod(myType, method, (method.Attributes|MethodAttributes.NewSlot)^MethodAttributes.NewSlot, i,
luaTableField, returnTypesField, true, out returnTypes[i]);
i++;
}
}
}
// Generates an implementation of the __luaInterface_getLuaTable method
var returnTableMethod = myType.DefineMethod("__luaInterface_getLuaTable",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(LuaTable), new Type[0]);
myType.DefineMethodOverride(returnTableMethod, typeof(ILuaGeneratedType).GetMethod("__luaInterface_getLuaTable"));
generator = returnTableMethod.GetILGenerator();
generator.Emit(OpCodes.Ldfld, luaTableField);
generator.Emit(OpCodes.Ret);
newType = myType.CreateType(); // Creates the type
}
/*
* Generates an overriden implementation of method inside myType that delegates
* to a function in a Lua table with the same name, if the function exists. If it
* doesn't the method calls the base method (or does nothing, in case of interface
* implementations).
*/
private void GenerateMethod(TypeBuilder myType, MethodInfo method, MethodAttributes attributes, int methodIndex,
FieldInfo luaTableField, FieldInfo returnTypesField, bool generateBase, out Type[] returnTypes)
{
var paramInfo = method.GetParameters();
var paramTypes = new Type[paramInfo.Length];
var returnTypesList = new List<Type>();
// Counts out and ref parameters, for later use,
// and creates the list of return types
int nOutParams = 0;
int nOutAndRefParams = 0;
var returnType = method.ReturnType;
returnTypesList.Add(returnType);
for(int i = 0; i < paramTypes.Length; i++)
{
paramTypes[i] = paramInfo[i].ParameterType;
if((!paramInfo[i].IsIn) && paramInfo[i].IsOut)
nOutParams++;
if(paramTypes[i].IsByRef)
{
returnTypesList.Add(paramTypes[i].GetElementType());
nOutAndRefParams++;
}
}
int[] refArgs = new int[nOutAndRefParams];
returnTypes = returnTypesList.ToArray();
// Generates a version of the method that calls the base implementation
// directly, for use by the base field of the table
if(generateBase)
{
var baseMethod = myType.DefineMethod("__luaInterface_base_"+method.Name,
MethodAttributes.Private|MethodAttributes.NewSlot|MethodAttributes.HideBySig,
returnType, paramTypes);
ILGenerator generatorBase = baseMethod.GetILGenerator();
generatorBase.Emit(OpCodes.Ldarg_0);
for(int i = 0; i < paramTypes.Length; i++)
generatorBase.Emit(OpCodes.Ldarg, i+1);
generatorBase.Emit(OpCodes.Call, method);
if(returnType == typeof(void))
generatorBase.Emit(OpCodes.Pop);
generatorBase.Emit(OpCodes.Ret);
}
// Defines the method
var methodImpl = myType.DefineMethod(method.Name, attributes, returnType, paramTypes);
// If it's an implementation of an interface tells what method it
// is overriding
if(myType.BaseType.Equals(typeof(object)))
myType.DefineMethodOverride(methodImpl, method);
ILGenerator generator = methodImpl.GetILGenerator( );
generator.DeclareLocal(typeof(object[])); // original arguments
generator.DeclareLocal(typeof(object[])); // with out-only arguments removed
generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments
if(!(returnType == typeof(void))) // return value
generator.DeclareLocal(returnType);
else
generator.DeclareLocal(typeof(object));
// Initializes local variables
generator.Emit(OpCodes.Ldc_I4, paramTypes.Length);
generator.Emit(OpCodes.Newarr, typeof(object));
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldc_I4, paramTypes.Length-nOutParams+1);
generator.Emit(OpCodes.Newarr, typeof(object));
generator.Emit(OpCodes.Stloc_1);
generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams);
generator.Emit(OpCodes.Newarr, typeof(int));
generator.Emit(OpCodes.Stloc_2);
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldc_I4_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, luaTableField);
generator.Emit(OpCodes.Stelem_Ref);
// Stores the arguments into the local variables, as needed
for(int iArgs = 0, iInArgs = 1, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++)
{
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4, iArgs);
generator.Emit(OpCodes.Ldarg, iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType());
}
else
generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box, paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
if(paramTypes[iArgs].IsByRef)
{
generator.Emit(OpCodes.Ldloc_2);
generator.Emit(OpCodes.Ldc_I4, iOutArgs);
generator.Emit(OpCodes.Ldc_I4, iArgs);
generator.Emit(OpCodes.Stelem_I4);
refArgs[iOutArgs] = iArgs;
iOutArgs++;
}
if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut))
{
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldc_I4, iInArgs);
generator.Emit(OpCodes.Ldarg, iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType());
}
else
generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box, paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
iInArgs++;
}
}
// Gets the function the method will delegate to by calling
// the getTableFunction method of class LuaClassHelper
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, luaTableField);
generator.Emit(OpCodes.Ldstr, method.Name);
generator.Emit(OpCodes.Call, classHelper.GetMethod("getTableFunction"));
var lab1 = generator.DefineLabel();
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Brtrue_S, lab1);
// Function does not exist, call base method
generator.Emit(OpCodes.Pop);
if(!method.IsAbstract)
{
generator.Emit(OpCodes.Ldarg_0);
for(int i = 0; i < paramTypes.Length; i++)
generator.Emit(OpCodes.Ldarg, i+1);
generator.Emit(OpCodes.Call, method);
if(returnType == typeof(void))
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ret);
generator.Emit(OpCodes.Ldnull);
}
else
generator.Emit(OpCodes.Ldnull);
var lab2 = generator.DefineLabel();
generator.Emit(OpCodes.Br_S, lab2);
generator.MarkLabel(lab1);
// Function exists, call using method callFunction of LuaClassHelper
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, returnTypesField);
generator.Emit(OpCodes.Ldc_I4, methodIndex);
generator.Emit(OpCodes.Ldelem_Ref);
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldloc_2);
generator.Emit(OpCodes.Call, classHelper.GetMethod("callFunction"));
generator.MarkLabel(lab2);
// Stores the function return value
if(returnType == typeof(void))
{
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ldnull);
}
else if(returnType.IsValueType)
{
generator.Emit(OpCodes.Unbox, returnType);
generator.Emit(OpCodes.Ldobj, returnType);
}
else
generator.Emit(OpCodes.Castclass, returnType);
generator.Emit(OpCodes.Stloc_3);
// Sets return values of out and ref parameters
for(int i = 0; i < refArgs.Length; i++)
{
generator.Emit(OpCodes.Ldarg, refArgs[i]+1);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4, refArgs[i]);
generator.Emit(OpCodes.Ldelem_Ref);
if(paramTypes[refArgs[i]].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType());
}
else
{
generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stind_Ref);
}
}
// Returns
if(!(returnType == typeof(void)))
generator.Emit(OpCodes.Ldloc_3);
generator.Emit(OpCodes.Ret);
}
/*
* Gets an event handler for the event type that delegates to the eventHandler Lua function.
* Caches the generated type.
*/
public LuaEventHandler GetEvent(Type eventHandlerType, LuaFunction eventHandler)
{
Type eventConsumerType;
if(eventHandlerCollection.ContainsKey(eventHandlerType))
eventConsumerType = eventHandlerCollection[eventHandlerType];
else
{
eventConsumerType = GenerateEvent(eventHandlerType);
eventHandlerCollection[eventHandlerType] = eventConsumerType;
}
var luaEventHandler = (LuaEventHandler)Activator.CreateInstance(eventConsumerType);
luaEventHandler.handler = eventHandler;
return luaEventHandler;
}
/*
* Gets a delegate with delegateType that calls the luaFunc Lua function
* Caches the generated type.
*/
public Delegate GetDelegate(Type delegateType, LuaFunction luaFunc)
{
var returnTypes = new List<Type>();
Type luaDelegateType;
if(delegateCollection.ContainsKey(delegateType))
luaDelegateType = delegateCollection[delegateType];
else
{
luaDelegateType = GenerateDelegate(delegateType);
delegateCollection[delegateType] = luaDelegateType;
}
var methodInfo = delegateType.GetMethod("Invoke");
returnTypes.Add(methodInfo.ReturnType);
foreach(ParameterInfo paramInfo in methodInfo.GetParameters())
{
if(paramInfo.ParameterType.IsByRef)
returnTypes.Add(paramInfo.ParameterType);
}
var luaDelegate = (LuaDelegate)Activator.CreateInstance(luaDelegateType);
luaDelegate.function = luaFunc;
luaDelegate.returnTypes = returnTypes.ToArray();
return Delegate.CreateDelegate(delegateType, luaDelegate, "CallFunction");
}
/*
* Gets an instance of an implementation of the klass interface or
* subclass of klass that delegates public virtual methods to the
* luaTable table.
* Caches the generated type.
*/
public object GetClassInstance(Type klass, LuaTable luaTable)
{
LuaClassType luaClassType;
if(classCollection.ContainsKey(klass))
luaClassType = classCollection[klass];
else
{
luaClassType = new LuaClassType();
GenerateClass(klass, out luaClassType.klass, out luaClassType.returnTypes);
classCollection[klass] = luaClassType;
}
return Activator.CreateInstance(luaClassType.klass, new object[] {luaTable, luaClassType.returnTypes});
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
using System.Collections.Generic;
using LuaInterface.Method;
namespace LuaInterface
{
/*
* Dynamically generates new types from existing types and
* Lua function and table values. Generated types are event handlers,
* delegates, interface implementations and subclasses.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class CodeGeneration
{
private Dictionary<Type, LuaClassType> classCollection = new Dictionary<Type, LuaClassType>();
private Dictionary<Type, Type> eventHandlerCollection = new Dictionary<Type, Type>();
private Dictionary<Type, Type> delegateCollection = new Dictionary<Type, Type>();
private static readonly CodeGeneration instance = new CodeGeneration();
private Type eventHandlerParent = typeof(LuaEventHandler);
private Type delegateParent = typeof(LuaDelegate);
private Type classHelper = typeof(LuaClassHelper);
private AssemblyName assemblyName;
private AssemblyBuilder newAssembly;
private ModuleBuilder newModule;
private int luaClassNumber = 1;
static CodeGeneration()
{
}
private CodeGeneration()
{
// Create an assembly name
assemblyName = new AssemblyName();
assemblyName.Name = "LuaInterface_generatedcode";
// Create a new assembly with one module.
newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
newModule = newAssembly.DefineDynamicModule("LuaInterface_generatedcode");
}
/*
* Singleton instance of the class
*/
public static CodeGeneration Instance
{
get { return instance; }
}
/*
* Generates an event handler that calls a Lua function
*/
private Type GenerateEvent(Type eventHandlerType)
{
string typeName;
lock(this)
{
typeName = "LuaGeneratedClass" + luaClassNumber;
luaClassNumber++;
}
// Define a public class in the assembly, called typeName
var myType = newModule.DefineType(typeName, TypeAttributes.Public, eventHandlerParent);
// Defines the handler method. Its signature is void(object, <subclassofEventArgs>)
var paramTypes = new Type[2];
paramTypes[0] = typeof(object);
paramTypes[1] = eventHandlerType;
var returnType = typeof(void);
var handleMethod = myType.DefineMethod("HandleEvent", MethodAttributes.Public | MethodAttributes.HideBySig, returnType, paramTypes);
// Emits the IL for the method. It loads the arguments
// and calls the handleEvent method of the base class
ILGenerator generator = handleMethod.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldarg_2);
var miGenericEventHandler = eventHandlerParent.GetMethod("handleEvent");
generator.Emit(OpCodes.Call, miGenericEventHandler);
// returns
generator.Emit(OpCodes.Ret);
// creates the new type
return myType.CreateType();
}
/*
* Generates a type that can be used for instantiating a delegate
* of the provided type, given a Lua function.
*/
private Type GenerateDelegate(Type delegateType)
{
string typeName;
lock(this)
{
typeName = "LuaGeneratedClass" + luaClassNumber;
luaClassNumber++;
}
// Define a public class in the assembly, called typeName
var myType = newModule.DefineType(typeName, TypeAttributes.Public, delegateParent);
// Defines the delegate method with the same signature as the
// Invoke method of delegateType
var invokeMethod = delegateType.GetMethod("Invoke");
var paramInfo = invokeMethod.GetParameters();
var paramTypes = new Type[paramInfo.Length];
var returnType = invokeMethod.ReturnType;
// Counts out and ref params, for use later
int nOutParams = 0; int nOutAndRefParams = 0;
for(int i = 0; i < paramTypes.Length; i++)
{
paramTypes[i] = paramInfo[i].ParameterType;
if((!paramInfo[i].IsIn) && paramInfo[i].IsOut)
nOutParams++;
if(paramTypes[i].IsByRef)
nOutAndRefParams++;
}
int[] refArgs = new int[nOutAndRefParams];
var delegateMethod = myType.DefineMethod("CallFunction", invokeMethod.Attributes, returnType, paramTypes);
// Generates the IL for the method
ILGenerator generator = delegateMethod.GetILGenerator( );
generator.DeclareLocal(typeof(object[])); // original arguments
generator.DeclareLocal(typeof(object[])); // with out-only arguments removed
generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments
if(!(returnType == typeof(void))) // return value
generator.DeclareLocal(returnType);
else
generator.DeclareLocal(typeof(object));
// Initializes local variables
generator.Emit(OpCodes.Ldc_I4, paramTypes.Length);
generator.Emit(OpCodes.Newarr, typeof(object));
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldc_I4, paramTypes.Length-nOutParams);
generator.Emit(OpCodes.Newarr, typeof(object));
generator.Emit(OpCodes.Stloc_1);
generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams);
generator.Emit(OpCodes.Newarr, typeof(int));
generator.Emit(OpCodes.Stloc_2);
// Stores the arguments in the local variables
for(int iArgs = 0, iInArgs = 0, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++)
{
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4, iArgs);
generator.Emit(OpCodes.Ldarg, iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType());
}
else
generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box, paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
if(paramTypes[iArgs].IsByRef)
{
generator.Emit(OpCodes.Ldloc_2);
generator.Emit(OpCodes.Ldc_I4, iOutArgs);
generator.Emit(OpCodes.Ldc_I4, iArgs);
generator.Emit(OpCodes.Stelem_I4);
refArgs[iOutArgs] = iArgs;
iOutArgs++;
}
if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut))
{
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldc_I4, iInArgs);
generator.Emit(OpCodes.Ldarg, iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType());
}
else
generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box, paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
iInArgs++;
}
}
// Calls the callFunction method of the base class
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldloc_2);
var miGenericEventHandler = delegateParent.GetMethod("callFunction");
generator.Emit(OpCodes.Call, miGenericEventHandler);
// Stores return value
if(returnType == typeof(void))
{
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ldnull);
}
else if(returnType.IsValueType)
{
generator.Emit(OpCodes.Unbox, returnType);
generator.Emit(OpCodes.Ldobj, returnType);
}
else
generator.Emit(OpCodes.Castclass, returnType);
generator.Emit(OpCodes.Stloc_3);
// Stores new value of out and ref params
for(int i = 0; i < refArgs.Length; i++)
{
generator.Emit(OpCodes.Ldarg, refArgs[i]+1);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4, refArgs[i]);
generator.Emit(OpCodes.Ldelem_Ref);
if(paramTypes[refArgs[i]].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType());
}
else
{
generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stind_Ref);
}
}
// Returns
if(!(returnType == typeof(void)))
generator.Emit(OpCodes.Ldloc_3);
generator.Emit(OpCodes.Ret);
return myType.CreateType(); // creates the new type
}
/*
* Generates an implementation of klass, if it is an interface, or
* a subclass of klass that delegates its virtual methods to a Lua table.
*/
public void GenerateClass(Type klass, out Type newType, out Type[][] returnTypes)
{
string typeName;
lock(this)
{
typeName = "LuaGeneratedClass" + luaClassNumber;
luaClassNumber++;
}
TypeBuilder myType;
// Define a public class in the assembly, called typeName
if(klass.IsInterface)
myType = newModule.DefineType(typeName, TypeAttributes.Public, typeof(object), new Type[] { klass, typeof(ILuaGeneratedType) });
else
myType = newModule.DefineType(typeName, TypeAttributes.Public, klass, new Type[] { typeof(ILuaGeneratedType) });
// Field that stores the Lua table
var luaTableField = myType.DefineField("__luaInterface_luaTable", typeof(LuaTable), FieldAttributes.Public);
// Field that stores the return types array
var returnTypesField = myType.DefineField("__luaInterface_returnTypes", typeof(Type[][]), FieldAttributes.Public);
// Generates the constructor for the new type, it takes a Lua table and an array
// of return types and stores them in the respective fields
var constructor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(LuaTable), typeof(Type[][]) });
ILGenerator generator = constructor.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
if(klass.IsInterface)
generator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
else
generator.Emit(OpCodes.Call, klass.GetConstructor(Type.EmptyTypes));
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, luaTableField);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_2);
generator.Emit(OpCodes.Stfld, returnTypesField);
generator.Emit(OpCodes.Ret);
// Generates overriden versions of the klass' public virtual methods
var classMethods = klass.GetMethods();
returnTypes = new Type[classMethods.Length][];
int i = 0;
foreach(var method in classMethods)
{
if(klass.IsInterface)
{
GenerateMethod(myType, method, MethodAttributes.HideBySig|MethodAttributes.Virtual|MethodAttributes.NewSlot,
i, luaTableField, returnTypesField, false, out returnTypes[i]);
i++;
}
else
{
if(!method.IsPrivate && !method.IsFinal && method.IsVirtual)
{
GenerateMethod(myType, method, (method.Attributes|MethodAttributes.NewSlot)^MethodAttributes.NewSlot, i,
luaTableField, returnTypesField, true, out returnTypes[i]);
i++;
}
}
}
// Generates an implementation of the __luaInterface_getLuaTable method
var returnTableMethod = myType.DefineMethod("__luaInterface_getLuaTable",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(LuaTable), new Type[0]);
myType.DefineMethodOverride(returnTableMethod, typeof(ILuaGeneratedType).GetMethod("__luaInterface_getLuaTable"));
generator = returnTableMethod.GetILGenerator();
generator.Emit(OpCodes.Ldfld, luaTableField);
generator.Emit(OpCodes.Ret);
newType = myType.CreateType(); // Creates the type
}
/*
* Generates an overriden implementation of method inside myType that delegates
* to a function in a Lua table with the same name, if the function exists. If it
* doesn't the method calls the base method (or does nothing, in case of interface
* implementations).
*/
private void GenerateMethod(TypeBuilder myType, MethodInfo method, MethodAttributes attributes, int methodIndex,
FieldInfo luaTableField, FieldInfo returnTypesField, bool generateBase, out Type[] returnTypes)
{
var paramInfo = method.GetParameters();
var paramTypes = new Type[paramInfo.Length];
var returnTypesList = new List<Type>();
// Counts out and ref parameters, for later use,
// and creates the list of return types
int nOutParams = 0;
int nOutAndRefParams = 0;
var returnType = method.ReturnType;
returnTypesList.Add(returnType);
for(int i = 0; i < paramTypes.Length; i++)
{
paramTypes[i] = paramInfo[i].ParameterType;
if((!paramInfo[i].IsIn) && paramInfo[i].IsOut)
nOutParams++;
if(paramTypes[i].IsByRef)
{
returnTypesList.Add(paramTypes[i].GetElementType());
nOutAndRefParams++;
}
}
int[] refArgs = new int[nOutAndRefParams];
returnTypes = returnTypesList.ToArray();
// Generates a version of the method that calls the base implementation
// directly, for use by the base field of the table
if(generateBase)
{
var baseMethod = myType.DefineMethod("__luaInterface_base_"+method.Name,
MethodAttributes.Private|MethodAttributes.NewSlot|MethodAttributes.HideBySig,
returnType, paramTypes);
ILGenerator generatorBase = baseMethod.GetILGenerator();
generatorBase.Emit(OpCodes.Ldarg_0);
for(int i = 0; i < paramTypes.Length; i++)
generatorBase.Emit(OpCodes.Ldarg, i+1);
generatorBase.Emit(OpCodes.Call, method);
if(returnType == typeof(void))
generatorBase.Emit(OpCodes.Pop);
generatorBase.Emit(OpCodes.Ret);
}
// Defines the method
var methodImpl = myType.DefineMethod(method.Name, attributes, returnType, paramTypes);
// If it's an implementation of an interface tells what method it
// is overriding
if(myType.BaseType.Equals(typeof(object)))
myType.DefineMethodOverride(methodImpl, method);
ILGenerator generator = methodImpl.GetILGenerator( );
generator.DeclareLocal(typeof(object[])); // original arguments
generator.DeclareLocal(typeof(object[])); // with out-only arguments removed
generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments
if(!(returnType == typeof(void))) // return value
generator.DeclareLocal(returnType);
else
generator.DeclareLocal(typeof(object));
// Initializes local variables
generator.Emit(OpCodes.Ldc_I4, paramTypes.Length);
generator.Emit(OpCodes.Newarr, typeof(object));
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldc_I4, paramTypes.Length-nOutParams+1);
generator.Emit(OpCodes.Newarr, typeof(object));
generator.Emit(OpCodes.Stloc_1);
generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams);
generator.Emit(OpCodes.Newarr, typeof(int));
generator.Emit(OpCodes.Stloc_2);
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldc_I4_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, luaTableField);
generator.Emit(OpCodes.Stelem_Ref);
// Stores the arguments into the local variables, as needed
for(int iArgs = 0, iInArgs = 1, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++)
{
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4, iArgs);
generator.Emit(OpCodes.Ldarg, iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType());
}
else
generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box, paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
if(paramTypes[iArgs].IsByRef)
{
generator.Emit(OpCodes.Ldloc_2);
generator.Emit(OpCodes.Ldc_I4, iOutArgs);
generator.Emit(OpCodes.Ldc_I4, iArgs);
generator.Emit(OpCodes.Stelem_I4);
refArgs[iOutArgs] = iArgs;
iOutArgs++;
}
if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut))
{
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldc_I4, iInArgs);
generator.Emit(OpCodes.Ldarg, iArgs+1);
if(paramTypes[iArgs].IsByRef)
{
if(paramTypes[iArgs].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType());
generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType());
}
else
generator.Emit(OpCodes.Ldind_Ref);
}
else
{
if(paramTypes[iArgs].IsValueType)
generator.Emit(OpCodes.Box, paramTypes[iArgs]);
}
generator.Emit(OpCodes.Stelem_Ref);
iInArgs++;
}
}
// Gets the function the method will delegate to by calling
// the getTableFunction method of class LuaClassHelper
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, luaTableField);
generator.Emit(OpCodes.Ldstr, method.Name);
generator.Emit(OpCodes.Call, classHelper.GetMethod("getTableFunction"));
var lab1 = generator.DefineLabel();
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Brtrue_S, lab1);
// Function does not exist, call base method
generator.Emit(OpCodes.Pop);
if(!method.IsAbstract)
{
generator.Emit(OpCodes.Ldarg_0);
for(int i = 0; i < paramTypes.Length; i++)
generator.Emit(OpCodes.Ldarg, i+1);
generator.Emit(OpCodes.Call, method);
if(returnType == typeof(void))
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ret);
generator.Emit(OpCodes.Ldnull);
}
else
generator.Emit(OpCodes.Ldnull);
var lab2 = generator.DefineLabel();
generator.Emit(OpCodes.Br_S, lab2);
generator.MarkLabel(lab1);
// Function exists, call using method callFunction of LuaClassHelper
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, returnTypesField);
generator.Emit(OpCodes.Ldc_I4, methodIndex);
generator.Emit(OpCodes.Ldelem_Ref);
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ldloc_2);
generator.Emit(OpCodes.Call, classHelper.GetMethod("callFunction"));
generator.MarkLabel(lab2);
// Stores the function return value
if(returnType == typeof(void))
{
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ldnull);
}
else if(returnType.IsValueType)
{
generator.Emit(OpCodes.Unbox, returnType);
generator.Emit(OpCodes.Ldobj, returnType);
}
else
generator.Emit(OpCodes.Castclass, returnType);
generator.Emit(OpCodes.Stloc_3);
// Sets return values of out and ref parameters
for(int i = 0; i < refArgs.Length; i++)
{
generator.Emit(OpCodes.Ldarg, refArgs[i]+1);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldc_I4, refArgs[i]);
generator.Emit(OpCodes.Ldelem_Ref);
if(paramTypes[refArgs[i]].GetElementType().IsValueType)
{
generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType());
}
else
{
generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType());
generator.Emit(OpCodes.Stind_Ref);
}
}
// Returns
if(!(returnType == typeof(void)))
generator.Emit(OpCodes.Ldloc_3);
generator.Emit(OpCodes.Ret);
}
/*
* Gets an event handler for the event type that delegates to the eventHandler Lua function.
* Caches the generated type.
*/
public LuaEventHandler GetEvent(Type eventHandlerType, LuaFunction eventHandler)
{
Type eventConsumerType;
if(eventHandlerCollection.ContainsKey(eventHandlerType))
eventConsumerType = eventHandlerCollection[eventHandlerType];
else
{
eventConsumerType = GenerateEvent(eventHandlerType);
eventHandlerCollection[eventHandlerType] = eventConsumerType;
}
var luaEventHandler = (LuaEventHandler)Activator.CreateInstance(eventConsumerType);
luaEventHandler.handler = eventHandler;
return luaEventHandler;
}
/*
* Gets a delegate with delegateType that calls the luaFunc Lua function
* Caches the generated type.
*/
public Delegate GetDelegate(Type delegateType, LuaFunction luaFunc)
{
var returnTypes = new List<Type>();
Type luaDelegateType;
if(delegateCollection.ContainsKey(delegateType))
luaDelegateType = delegateCollection[delegateType];
else
{
luaDelegateType = GenerateDelegate(delegateType);
delegateCollection[delegateType] = luaDelegateType;
}
var methodInfo = delegateType.GetMethod("Invoke");
returnTypes.Add(methodInfo.ReturnType);
foreach(ParameterInfo paramInfo in methodInfo.GetParameters())
{
if(paramInfo.ParameterType.IsByRef)
returnTypes.Add(paramInfo.ParameterType);
}
var luaDelegate = (LuaDelegate)Activator.CreateInstance(luaDelegateType);
luaDelegate.function = luaFunc;
luaDelegate.returnTypes = returnTypes.ToArray();
return Delegate.CreateDelegate(delegateType, luaDelegate, "CallFunction");
}
/*
* Gets an instance of an implementation of the klass interface or
* subclass of klass that delegates public virtual methods to the
* luaTable table.
* Caches the generated type.
*/
public object GetClassInstance(Type klass, LuaTable luaTable)
{
LuaClassType luaClassType;
if(classCollection.ContainsKey(klass))
luaClassType = classCollection[klass];
else
{
luaClassType = new LuaClassType();
GenerateClass(klass, out luaClassType.klass, out luaClassType.returnTypes);
classCollection[klass] = luaClassType;
}
return Activator.CreateInstance(luaClassType.klass, new object[] {luaTable, luaClassType.returnTypes});
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
/*
* Class used for generating delegates that get a function from the Lua
* stack as a delegate of a specific type.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class DelegateGenerator
{
private ObjectTranslator translator;
private Type delegateType;
public DelegateGenerator(ObjectTranslator translator, Type delegateType)
{
this.translator = translator;
this.delegateType = delegateType;
}
public object extractGenerated(KopiLua.Lua.lua_State luaState, int stackPos)
{
return CodeGeneration.Instance.GetDelegate(delegateType, translator.getFunction(luaState, stackPos));
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
/*
* Class used for generating delegates that get a function from the Lua
* stack as a delegate of a specific type.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class DelegateGenerator
{
private ObjectTranslator translator;
private Type delegateType;
public DelegateGenerator(ObjectTranslator translator, Type delegateType)
{
this.translator = translator;
this.delegateType = delegateType;
}
public object extractGenerated(KopiLua.Lua.lua_State luaState, int stackPos)
{
return CodeGeneration.Instance.GetDelegate(delegateType, translator.getFunction(luaState, stackPos));
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
/*
* Common interface for types generated from tables. The method
* returns the table that overrides some or all of the type's methods.
*/
public interface ILuaGeneratedType
{
LuaTable __luaInterface_getLuaTable();
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
/*
* Common interface for types generated from tables. The method
* returns the table that overrides some or all of the type's methods.
*/
public interface ILuaGeneratedType
{
LuaTable __luaInterface_getLuaTable();
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
/*
* Structure to store a type and the return types of
* its methods (the type of the returned value and out/ref
* parameters).
*/
struct LuaClassType
{
public Type klass;
public Type[][] returnTypes;
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
/*
* Structure to store a type and the return types of
* its methods (the type of the returned value and out/ref
* parameters).
*/
struct LuaClassType
{
public Type klass;
public Type[][] returnTypes;
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using LuaInterface.Event;
using LuaInterface.Method;
using LuaInterface.Exceptions;
using LuaInterface.Extensions;
namespace LuaInterface
{
using LuaCore = KopiLua.Lua;
/*
* Main class of LuaInterface
* Object-oriented wrapper to Lua API
*
* Author: Fabio Mascarenhas
* Version: 1.0
*
* // steffenj: important changes in Lua class:
* - removed all Open*Lib() functions
* - all libs automatically open in the Lua class constructor (just assign nil to unwanted libs)
* */
[CLSCompliant(true)]
public class Lua : IDisposable
{
#region lua debug functions
/// <summary>
/// Event that is raised when an exception occures during a hook call.
/// </summary>
/// <author>Reinhard Ostermeier</author>
public event EventHandler<HookExceptionEventArgs> HookException;
/// <summary>
/// Event when lua hook callback is called
/// </summary>
/// <remarks>
/// Is only raised if SetDebugHook is called before.
/// </remarks>
/// <author>Reinhard Ostermeier</author>
public event EventHandler<DebugHookEventArgs> DebugHook;
/// <summary>
/// lua hook calback delegate
/// </summary>
/// <author>Reinhard Ostermeier</author>
private LuaCore.lua_Hook hookCallback = null;
#endregion
#region Globals auto-complete
private readonly List<string> globals = new List<string>();
private bool globalsSorted;
#endregion
private /*readonly */ LuaCore.lua_State luaState;
/// <summary>
/// True while a script is being executed
/// </summary>
public bool IsExecuting { get { return executing; } }
private LuaCore.lua_CFunction panicCallback;
private ObjectTranslator translator;
/// <summary>
/// Used to ensure multiple .net threads all get serialized by this single lock for access to the lua stack/objects
/// </summary>
private object luaLock = new object();
private bool _StatePassed;
private bool executing;
static string init_luanet =
"local metatable = {} \n" +
"local import_type = luanet.import_type \n" +
"local load_assembly = luanet.load_assembly \n" +
" \n" +
"-- Lookup a .NET identifier component. \n" +
"function metatable:__index(key) -- key is e.g. \"Form\" \n" +
" -- Get the fully-qualified name, e.g. \"System.Windows.Forms.Form\" \n" +
" local fqn = ((rawget(self, \".fqn\") and rawget(self, \".fqn\") .. \n" +
" \".\") or \"\") .. key \n" +
" \n" +
" -- Try to find either a luanet function or a CLR type \n" +
" local obj = rawget(luanet, key) or import_type(fqn) \n" +
" \n" +
" -- If key is neither a luanet function or a CLR type, then it is simply \n" +
" -- an identifier component. \n" +
" if obj == nil then \n" +
" -- It might be an assembly, so we load it too. \n" +
" load_assembly(fqn) \n" +
" obj = { [\".fqn\"] = fqn } \n" +
" setmetatable(obj, metatable) \n" +
" end \n" +
" \n" +
" -- Cache this lookup \n" +
" rawset(self, key, obj) \n" +
" return obj \n" +
"end \n" +
" \n" +
"-- A non-type has been called; e.g. foo = System.Foo() \n" +
"function metatable:__call(...) \n" +
" error(\"No such type: \" .. rawget(self, \".fqn\"), 2) \n" +
"end \n" +
" \n" +
"-- This is the root of the .NET namespace \n" +
"luanet[\".fqn\"] = false \n" +
"setmetatable(luanet, metatable) \n" +
" \n" +
"-- Preload the mscorlib assembly \n" +
"luanet.load_assembly(\"mscorlib\") \n";
#region Globals auto-complete
/// <summary>
/// An alphabetically sorted list of all globals (objects, methods, etc.) externally added to this Lua instance
/// </summary>
/// <remarks>Members of globals are also listed. The formatting is optimized for text input auto-completion.</remarks>
public IEnumerable<string> Globals
{
get
{
// Only sort list when necessary
if(!globalsSorted)
{
globals.Sort();
globalsSorted = true;
}
return globals;
}
}
#endregion
public Lua()
{
luaState = LuaCore.luaL_newstate(); // steffenj: Lua 5.1.1 API change (lua_open is gone)
//LuaCore.luaopen_base(luaState); // steffenj: luaopen_* no longer used
LuaCore.luaL_openlibs(luaState); // steffenj: Lua 5.1.1 API change (luaopen_base is gone, just open all libs right here)
LuaCore.lua_pushstring(luaState, "LUAINTERFACE LOADED");
LuaCore.lua_pushboolean(luaState, 1);
LuaCore.lua_settable(luaState, (int)PseudoIndex.Registry);
LuaCore.lua_newtable(luaState);
LuaCore.lua_setglobal(luaState, "luanet");
LuaCore.lua_pushvalue(luaState, (int)PseudoIndex.Globals);
LuaCore.lua_getglobal(luaState, "luanet");
LuaCore.lua_pushstring(luaState, "getmetatable");
LuaCore.lua_getglobal(luaState, "getmetatable");
LuaCore.lua_settable(luaState, -3);
LuaCore.lua_replace(luaState, (int)PseudoIndex.Globals);
translator = new ObjectTranslator(this, luaState);
LuaCore.lua_replace(luaState, (int)PseudoIndex.Globals);
LuaLib.luaL_dostring(luaState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring
// We need to keep this in a managed reference so the delegate doesn't get garbage collected
panicCallback = new LuaCore.lua_CFunction(PanicCallback);
LuaCore.lua_atpanic(luaState, panicCallback);
//LuaCore.lua_atlock(luaState, lockCallback = new LuaCore.lua_CFunction(LockCallback));
//LuaCore.lua_atunlock(luaState, unlockCallback = new LuaCore.lua_CFunction(UnlockCallback));
}
/*
* CAUTION: LuaInterface.Lua instances can't share the same lua state!
*/
public Lua(LuaCore.lua_State luaState)
{
LuaCore.lua_State lState = luaState;
LuaCore.lua_pushstring(lState, "LUAINTERFACE LOADED");
LuaCore.lua_gettable(lState, (int)PseudoIndex.Registry);
if(LuaCore.lua_toboolean(lState, -1).ToBoolean())
{
LuaCore.lua_settop(lState, -2);
throw new LuaException("There is already a LuaInterface.Lua instance associated with this Lua state");
}
else
{
LuaCore.lua_settop(lState, -2);
LuaCore.lua_pushstring(lState, "LUAINTERFACE LOADED");
LuaCore.lua_pushboolean(lState, 1);
LuaCore.lua_settable(lState, (int)PseudoIndex.Registry);
this.luaState = lState;
LuaCore.lua_pushvalue(lState, (int)PseudoIndex.Globals);
LuaCore.lua_getglobal(lState, "luanet");
LuaCore.lua_pushstring(lState, "getmetatable");
LuaCore.lua_getglobal(lState, "getmetatable");
LuaCore.lua_settable(lState, -3);
LuaCore.lua_replace(lState, (int)PseudoIndex.Globals);
translator = new ObjectTranslator(this, this.luaState);
LuaCore.lua_replace(lState, (int)PseudoIndex.Globals);
LuaLib.luaL_dostring(lState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring
}
_StatePassed = true;
}
/// <summary>
/// Called for each lua_lock call
/// </summary>
/// <param name = "luaState"></param>
/// Not yet used
/*int LockCallback(LuaCore.lua_State luaState)
{
// Monitor.Enter(luaLock);
return 0;
}*/
/// <summary>
/// Called for each lua_unlock call
/// </summary>
/// <param name = "luaState"></param>
/// Not yet used
/*int UnlockCallback(LuaCore.lua_State luaState)
{
// Monitor.Exit(luaLock);
return 0;
}*/
public void Close()
{
if(_StatePassed)
return;
////// if(luaState != LuaCore.lua_State.Zero)
if(!luaState.IsNull())
LuaCore.lua_close(luaState);
//luaState = LuaCore.lua_State.Zero; <- suggested by Christopher Cebulski http://luaforge.net/forum/forum.php?thread_id = 44593&forum_id = 146
}
static int PanicCallback(LuaCore.lua_State luaState)
{
// string desc = LuaCore.lua_tostring(luaState, 1);
string reason = string.Format("unprotected error in call to Lua API ({0})", LuaCore.lua_tostring(luaState, -1));
// lua_tostring(L, -1);
throw new LuaException(reason);
}
/// <summary>
/// Assuming we have a Lua error string sitting on the stack, throw a C# exception out to the user's app
/// </summary>
/// <exception cref = "LuaScriptException">Thrown if the script caused an exception</exception>
private void ThrowExceptionFromError(int oldTop)
{
object err = translator.getObject(luaState, -1);
LuaCore.lua_settop(luaState, oldTop);
// A pre-wrapped exception - just rethrow it (stack trace of InnerException will be preserved)
var luaEx = err as LuaScriptException;
if(!luaEx.IsNull())
throw luaEx;
// A non-wrapped Lua error (best interpreted as a string) - wrap it and throw it
if(err.IsNull())
err = "Unknown Lua Error";
throw new LuaScriptException(err.ToString(), string.Empty);
}
/// <summary>
/// Convert C# exceptions into Lua errors
/// </summary>
/// <returns>num of things on stack</returns>
/// <param name = "e">null for no pending exception</param>
internal int SetPendingException(Exception e)
{
var caughtExcept = e;
if(!caughtExcept.IsNull())
{
translator.throwError(luaState, caughtExcept);
LuaCore.lua_pushnil(luaState);
return 1;
}
else
return 0;
}
/// <summary>
///
/// </summary>
/// <param name = "chunk"></param>
/// <param name = "name"></param>
/// <returns></returns>
public LuaFunction LoadString(string chunk, string name)
{
int oldTop = LuaCore.lua_gettop(luaState);
executing = true;
try
{
if(LuaLib.luaL_loadbuffer(luaState, chunk, name) != 0)
ThrowExceptionFromError(oldTop);
}
finally
{
executing = false;
}
var result = translator.getFunction(luaState, -1);
translator.popValues(luaState, oldTop);
return result;
}
/// <summary>
///
/// </summary>
/// <param name = "fileName"></param>
/// <returns></returns>
public LuaFunction LoadFile(string fileName)
{
int oldTop = LuaCore.lua_gettop(luaState);
if(LuaCore.luaL_loadfile(luaState, fileName) != 0)
ThrowExceptionFromError(oldTop);
var result = translator.getFunction(luaState, -1);
translator.popValues(luaState, oldTop);
return result;
}
/*
* Excutes a Lua chunk and returns all the chunk's return
* values in an array
*/
public object[] DoString(string chunk)
{
int oldTop = LuaCore.lua_gettop(luaState);
if(LuaLib.luaL_loadbuffer(luaState, chunk, "chunk") == 0)
{
executing = true;
try
{
if(LuaCore.lua_pcall(luaState, 0, -1, 0) == 0)
return translator.popValues(luaState, oldTop);
else
ThrowExceptionFromError(oldTop);
}
finally
{
executing = false;
}
}
else
ThrowExceptionFromError(oldTop);
return null; // Never reached - keeps compiler happy
}
/// <summary>
/// Executes a Lua chnk and returns all the chunk's return values in an array.
/// </summary>
/// <param name = "chunk">Chunk to execute</param>
/// <param name = "chunkName">Name to associate with the chunk</param>
/// <returns></returns>
public object[] DoString(string chunk, string chunkName)
{
int oldTop = LuaCore.lua_gettop(luaState);
executing = true;
if(LuaLib.luaL_loadbuffer(luaState, chunk, chunkName) == 0)
{
try
{
if(LuaCore.lua_pcall(luaState, 0, -1, 0) == 0)
return translator.popValues(luaState, oldTop);
else
ThrowExceptionFromError(oldTop);
}
finally
{
executing = false;
}
}
else
ThrowExceptionFromError(oldTop);
return null; // Never reached - keeps compiler happy
}
/*
* Excutes a Lua file and returns all the chunk's return
* values in an array
*/
public object[] DoFile(string fileName)
{
int oldTop = LuaCore.lua_gettop(luaState);
if(LuaCore.luaL_loadfile(luaState, fileName) == 0)
{
executing = true;
try
{
if(LuaCore.lua_pcall(luaState, 0, -1, 0) == 0)
return translator.popValues(luaState, oldTop);
else
ThrowExceptionFromError(oldTop);
}
finally
{
executing = false;
}
}
else
ThrowExceptionFromError(oldTop);
return null; // Never reached - keeps compiler happy
}
/*
* Indexer for global variables from the LuaInterpreter
* Supports navigation of tables by using . operator
*/
public object this[string fullPath]
{
get
{
object returnValue = null;
int oldTop = LuaCore.lua_gettop(luaState);
string[] path = fullPath.Split(new char[] { '.' });
LuaCore.lua_getglobal(luaState, path[0]);
returnValue = translator.getObject(luaState, -1);
if(path.Length>1)
{
string[] remainingPath = new string[path.Length-1];
Array.Copy(path, 1, remainingPath, 0, path.Length-1);
returnValue = getObject(remainingPath);
}
LuaCore.lua_settop(luaState, oldTop);
return returnValue;
}
set
{
int oldTop = LuaCore.lua_gettop(luaState);
string[] path = fullPath.Split(new char[] { '.' });
if(path.Length == 1)
{
translator.push(luaState, value);
LuaCore.lua_setglobal(luaState, fullPath);
}
else
{
LuaCore.lua_getglobal(luaState, path[0]);
string[] remainingPath = new string[path.Length-1];
Array.Copy(path, 1, remainingPath, 0, path.Length-1);
setObject(remainingPath, value);
}
LuaCore.lua_settop(luaState, oldTop);
// Globals auto-complete
if(value.IsNull())
{
// Remove now obsolete entries
globals.Remove(fullPath);
}
else
{
// Add new entries
if(!globals.Contains(fullPath))
registerGlobal(fullPath, value.GetType(), 0);
}
}
}
#region Globals auto-complete
/// <summary>
/// Adds an entry to <see cref = "globals"/> (recursivley handles 2 levels of members)
/// </summary>
/// <param name = "path">The index accessor path ot the entry</param>
/// <param name = "type">The type of the entry</param>
/// <param name = "recursionCounter">How deep have we gone with recursion?</param>
private void registerGlobal(string path, Type type, int recursionCounter)
{
// If the type is a global method, list it directly
if(type == typeof(LuaCore.lua_CFunction))
{
// Format for easy method invocation
globals.Add(path + "(");
}
// If the type is a class or an interface and recursion hasn't been running too long, list the members
else if((type.IsClass || type.IsInterface) && type != typeof(string) && recursionCounter < 2)
{
#region Methods
foreach(var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance))
{
if(
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(method.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) &&
(method.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0) &&
// Exclude some generic .NET methods that wouldn't be very usefull in Lua
method.Name != "GetType" && method.Name != "GetHashCode" && method.Name != "Equals" &&
method.Name != "ToString" && method.Name != "Clone" && method.Name != "Dispose" &&
method.Name != "GetEnumerator" && method.Name != "CopyTo" &&
!method.Name.StartsWith("get_", StringComparison.Ordinal) &&
!method.Name.StartsWith("set_", StringComparison.Ordinal) &&
!method.Name.StartsWith("add_", StringComparison.Ordinal) &&
!method.Name.StartsWith("remove_", StringComparison.Ordinal))
{
// Format for easy method invocation
string command = path + ":" + method.Name + "(";
if(method.GetParameters().Length == 0) command += ")";
globals.Add(command);
}
}
#endregion
#region Fields
foreach(var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance))
{
if(
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(field.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) &&
(field.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0))
{
// Go into recursion for members
registerGlobal(path + "." + field.Name, field.FieldType, recursionCounter + 1);
}
}
#endregion
#region Properties
foreach(var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if(
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(property.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) &&
(property.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0)
// Exclude some generic .NET properties that wouldn't be very usefull in Lua
&& property.Name != "Item")
{
// Go into recursion for members
registerGlobal(path + "." + property.Name, property.PropertyType, recursionCounter + 1);
}
}
#endregion
}
else
globals.Add(path); // Otherwise simply add the element to the list
// List will need to be sorted on next access
globalsSorted = false;
}
#endregion
/*
* Navigates a table in the top of the stack, returning
* the value of the specified field
*/
internal object getObject(string[] remainingPath)
{
object returnValue = null;
for(int i = 0; i < remainingPath.Length; i++)
{
LuaCore.lua_pushstring(luaState, remainingPath[i]);
LuaCore.lua_gettable(luaState, -2);
returnValue = translator.getObject(luaState, -1);
if(returnValue.IsNull())
break;
}
return returnValue;
}
/*
* Gets a numeric global variable
*/
public double GetNumber(string fullPath)
{
return (double)this[fullPath];
}
/*
* Gets a string global variable
*/
public string GetString(string fullPath)
{
return (string)this[fullPath];
}
/*
* Gets a table global variable
*/
public LuaTable GetTable(string fullPath)
{
return (LuaTable)this[fullPath];
}
/*
* Gets a table global variable as an object implementing
* the interfaceType interface
*/
public object GetTable(Type interfaceType, string fullPath)
{
return CodeGeneration.Instance.GetClassInstance(interfaceType, GetTable(fullPath));
}
/*
* Gets a function global variable
*/
public LuaFunction GetFunction(string fullPath)
{
object obj = this[fullPath];
return (obj is LuaCore.lua_CFunction ? new LuaFunction((LuaCore.lua_CFunction)obj, this) : (LuaFunction)obj);
//return (obj is LuaCore.lua_CFunction ? new LuaFunction((LuaCore.lua_CFunction)obj, this) : /*(LuaFunction)*/new LuaFunction(obj.GetHashCode(), this));
}
/*
* Gets a function global variable as a delegate of
* type delegateType
*/
public Delegate GetFunction(Type delegateType, string fullPath)
{
return CodeGeneration.Instance.GetDelegate(delegateType, GetFunction(fullPath));
}
/*
* Calls the object as a function with the provided arguments,
* returning the function's returned values inside an array
*/
internal object[] callFunction(object function, object[] args)
{
return callFunction(function, args, null);
}
/*
* Calls the object as a function with the provided arguments and
* casting returned values to the types in returnTypes before returning
* them in an array
*/
internal object[] callFunction(object function, object[] args, Type[] returnTypes)
{
int nArgs = 0;
int oldTop = LuaCore.lua_gettop(luaState);
if(!LuaCore.lua_checkstack(luaState, args.Length+6).ToBoolean())
throw new LuaException("Lua stack overflow");
translator.push(luaState, function);
if(!args.IsNull())
{
nArgs = args.Length;
for(int i = 0; i < args.Length; i++)
translator.push(luaState, args[i]);
}
executing = true;
try
{
int error = LuaCore.lua_pcall(luaState, nArgs, -1, 0);
if(error != 0)
ThrowExceptionFromError(oldTop);
}
finally
{
executing = false;
}
return !returnTypes.IsNull() ? translator.popValues(luaState, oldTop, returnTypes) : translator.popValues(luaState, oldTop);
}
/*
* Navigates a table to set the value of one of its fields
*/
internal void setObject(string[] remainingPath, object val)
{
for(int i = 0; i < remainingPath.Length-1; i++)
{
LuaCore.lua_pushstring(luaState, remainingPath[i]);
LuaCore.lua_gettable(luaState, -2);
}
LuaCore.lua_pushstring(luaState, remainingPath[remainingPath.Length-1]);
translator.push(luaState, val);
LuaCore.lua_settable(luaState, -3);
}
/*
* Creates a new table as a global variable or as a field
* inside an existing table
*/
public void NewTable(string fullPath)
{
string[] path = fullPath.Split(new char[] { '.' });
int oldTop = LuaCore.lua_gettop(luaState);
if(path.Length == 1)
{
LuaCore.lua_newtable(luaState);
LuaCore.lua_setglobal(luaState, fullPath);
}
else
{
LuaCore.lua_getglobal(luaState, path[0]);
for(int i = 1; i < path.Length-1; i++)
{
LuaCore.lua_pushstring(luaState, path[i]);
LuaCore.lua_gettable(luaState, -2);
}
LuaCore.lua_pushstring(luaState, path[path.Length-1]);
LuaCore.lua_newtable(luaState);
LuaCore.lua_settable(luaState, -3);
}
LuaCore.lua_settop(luaState, oldTop);
}
public ListDictionary GetTableDict(LuaTable table)
{
var dict = new ListDictionary();
int oldTop = LuaCore.lua_gettop(luaState);
translator.push(luaState, table);
LuaCore.lua_pushnil(luaState);
while(LuaCore.lua_next(luaState, -2) != 0)
{
dict[translator.getObject(luaState, -2)] = translator.getObject(luaState, -1);
LuaCore.lua_settop(luaState, -2);
}
LuaCore.lua_settop(luaState, oldTop);
return dict;
}
/*
* Lets go of a previously allocated reference to a table, function
* or userdata
*/
#region lua debug functions
/// <summary>
/// Activates the debug hook
/// </summary>
/// <param name = "mask">Mask</param>
/// <param name = "count">Count</param>
/// <returns>see lua docs. -1 if hook is already set</returns>
/// <author>Reinhard Ostermeier</author>
/*public int SetDebugHook(EventMasks mask, int count)
{
if(hookCallback.IsNull())
{
hookCallback = new LuaCore.lua_Hook(DebugHookCallback);
return LuaCore.lua_sethook(luaState, hookCallback, (int)mask, count);
}
return -1;
}*/
/// <summary>
/// Removes the debug hook
/// </summary>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public int RemoveDebugHook()
{
hookCallback = null;
return LuaCore.lua_sethook(luaState, null, 0, 0);
}
/// <summary>
/// Gets the hook mask.
/// </summary>
/// <returns>hook mask</returns>
/// <author>Reinhard Ostermeier</author>
public EventMasks GetHookMask()
{
return (EventMasks)LuaCore.lua_gethookmask(luaState);
}
/// <summary>
/// Gets the hook count
/// </summary>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public int GetHookCount()
{
return LuaCore.lua_gethookcount(luaState);
}
/// <summary>
/// Gets the stack entry on a given level
/// </summary>
/// <param name = "level">level</param>
/// <param name = "luaDebug">lua debug structure</param>
/// <returns>Returns true if level was allowed, false if level was invalid.</returns>
/// <author>Reinhard Ostermeier</author>
/*public bool GetStack(int level, out LuaDebug luaDebug)
{
luaDebug = new LuaDebug();
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaCore.lua_getstack(luaState, level, ld) != 0;
}
finally
{
luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug));
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Gets info (see lua docs)
/// </summary>
/// <param name = "what">what (see lua docs)</param>
/// <param name = "luaDebug">lua debug structure</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
/*public int GetInfo(String what, ref LuaDebug luaDebug)
{
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaCore.lua_getinfo(luaState, what, ld);
}
finally
{
luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug));
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Gets local (see lua docs)
/// </summary>
/// <param name = "luaDebug">lua debug structure</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
/*public String GetLocal(LuaDebug luaDebug, int n)
{
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaCore.lua_getlocal(luaState, ld, n);
}
finally
{
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Sets local (see lua docs)
/// </summary>
/// <param name = "luaDebug">lua debug structure</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
/*public String SetLocal(LuaDebug luaDebug, int n)
{
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaCore.lua_setlocal(luaState, ld, n);
}
finally
{
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Gets up value (see lua docs)
/// </summary>
/// <param name = "funcindex">see lua docs</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string GetUpValue(int funcindex, int n)
{
return LuaCore.lua_getupvalue(luaState, funcindex, n).ToString();
}
/// <summary>
/// Sets up value (see lua docs)
/// </summary>
/// <param name = "funcindex">see lua docs</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string SetUpValue(int funcindex, int n)
{
return LuaCore.lua_setupvalue(luaState, funcindex, n).ToString();
}
/// <summary>
/// Delegate that is called on lua hook callback
/// </summary>
/// <param name = "luaState">lua state</param>
/// <param name = "luaDebug">Pointer to LuaDebug (lua_debug) structure</param>
/// <author>Reinhard Ostermeier</author>
/*private void DebugHookCallback(LuaCore.lua_State luaState, LuaCore.lua_Debug luaDebug)
{
try
{
LuaDebug ld = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(luaDebug, typeof(LuaDebug));
EventHandler<DebugHookEventArgs> temp = DebugHook;
if(temp != null)
{
temp(this, new DebugHookEventArgs(ld));
}
}
catch (Exception ex)
{
OnHookException(new HookExceptionEventArgs(ex));
}
}*/
private void OnHookException(HookExceptionEventArgs e)
{
var temp = HookException;
if(!temp.IsNull())
temp(this, e);
}
/// <summary>
/// Pops a value from the lua stack.
/// </summary>
/// <returns>Returns the top value from the lua stack.</returns>
/// <author>Reinhard Ostermeier</author>
public object Pop()
{
int top = LuaCore.lua_gettop(luaState);
return translator.popValues(luaState, top - 1)[0];
}
/// <summary>
/// Pushes a value onto the lua stack.
/// </summary>
/// <param name = "value">Value to push.</param>
/// <author>Reinhard Ostermeier</author>
public void Push(object value)
{
translator.push(luaState, value);
}
#endregion
internal void dispose(int reference)
{
///////////// if(luaState != LuaCore.lua_State.Zero)
if(!luaState.IsNull()) //Fix submitted by Qingrui Li
LuaLib.lua_unref(luaState, reference);
}
/*
* Gets a field of the table corresponding to the provided reference
* using rawget (do not use metatables)
*/
internal object rawGetObject(int reference, string field)
{
int oldTop = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, reference);
LuaCore.lua_pushstring(luaState, field);
LuaCore.lua_rawget(luaState, -2);
object obj = translator.getObject(luaState, -1);
LuaCore.lua_settop(luaState, oldTop);
return obj;
}
/*
* Gets a field of the table or userdata corresponding to the provided reference
*/
internal object getObject(int reference, string field)
{
int oldTop = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, reference);
object returnValue = getObject(field.Split(new char[] {'.'}));
LuaCore.lua_settop(luaState, oldTop);
return returnValue;
}
/*
* Gets a numeric field of the table or userdata corresponding the the provided reference
*/
internal object getObject(int reference, object field)
{
int oldTop = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, reference);
translator.push(luaState, field);
LuaCore.lua_gettable(luaState, -2);
object returnValue = translator.getObject(luaState, -1);
LuaCore.lua_settop(luaState, oldTop);
return returnValue;
}
/*
* Sets a field of the table or userdata corresponding the the provided reference
* to the provided value
*/
internal void setObject(int reference, string field, object val)
{
int oldTop = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, reference);
setObject(field.Split(new char[] {'.'}), val);
LuaCore.lua_settop(luaState, oldTop);
}
/*
* Sets a numeric field of the table or userdata corresponding the the provided reference
* to the provided value
*/
internal void setObject(int reference, object field, object val)
{
int oldTop = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, reference);
translator.push(luaState, field);
translator.push(luaState, val);
LuaCore.lua_settable(luaState, -3);
LuaCore.lua_settop(luaState, oldTop);
}
/*
* Registers an object's method as a Lua function (global or table field)
* The method may have any signature
*/
public LuaFunction RegisterFunction(string path, object target, MethodBase function /*MethodInfo function*/) //CP: Fix for struct constructor by Alexander Kappner (link: http://luaforge.net/forum/forum.php?thread_id = 2859&forum_id = 145)
{
// We leave nothing on the stack when we are done
int oldTop = LuaCore.lua_gettop(luaState);
var wrapper = new LuaMethodWrapper(translator, target, function.DeclaringType, function);
translator.push(luaState, new LuaCore.lua_CFunction(wrapper.call));
this[path] = translator.getObject(luaState, -1);
var f = GetFunction(path);
LuaCore.lua_settop(luaState, oldTop);
return f;
}
/*
* Compares the two values referenced by ref1 and ref2 for equality
*/
internal bool compareRef(int ref1, int ref2)
{
int top = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, ref1);
LuaLib.lua_getref(luaState, ref2);
int equal = LuaCore.lua_equal(luaState, -1, -2);
LuaCore.lua_settop(luaState, top);
return (equal != 0);
}
internal void pushCSFunction(LuaCore.lua_CFunction function)
{
translator.pushFunction(luaState, function);
}
#region IDisposable Members
public virtual void Dispose()
{
if(!translator.IsNull())
{
translator.pendingEvents.Dispose();
translator = null;
}
this.Close();
GC.Collect();
GC.WaitForPendingFinalizers();
}
#endregion
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using LuaInterface.Event;
using LuaInterface.Method;
using LuaInterface.Exceptions;
using LuaInterface.Extensions;
namespace LuaInterface
{
using LuaCore = KopiLua.Lua;
/*
* Main class of LuaInterface
* Object-oriented wrapper to Lua API
*
* Author: Fabio Mascarenhas
* Version: 1.0
*
* // steffenj: important changes in Lua class:
* - removed all Open*Lib() functions
* - all libs automatically open in the Lua class constructor (just assign nil to unwanted libs)
* */
[CLSCompliant(true)]
public class Lua : IDisposable
{
#region lua debug functions
/// <summary>
/// Event that is raised when an exception occures during a hook call.
/// </summary>
/// <author>Reinhard Ostermeier</author>
public event EventHandler<HookExceptionEventArgs> HookException;
/// <summary>
/// Event when lua hook callback is called
/// </summary>
/// <remarks>
/// Is only raised if SetDebugHook is called before.
/// </remarks>
/// <author>Reinhard Ostermeier</author>
public event EventHandler<DebugHookEventArgs> DebugHook;
/// <summary>
/// lua hook calback delegate
/// </summary>
/// <author>Reinhard Ostermeier</author>
private LuaCore.lua_Hook hookCallback = null;
#endregion
#region Globals auto-complete
private readonly List<string> globals = new List<string>();
private bool globalsSorted;
#endregion
private /*readonly */ LuaCore.lua_State luaState;
/// <summary>
/// True while a script is being executed
/// </summary>
public bool IsExecuting { get { return executing; } }
private LuaCore.lua_CFunction panicCallback;
private ObjectTranslator translator;
/// <summary>
/// Used to ensure multiple .net threads all get serialized by this single lock for access to the lua stack/objects
/// </summary>
private object luaLock = new object();
private bool _StatePassed;
private bool executing;
static string init_luanet =
"local metatable = {} \n" +
"local import_type = luanet.import_type \n" +
"local load_assembly = luanet.load_assembly \n" +
" \n" +
"-- Lookup a .NET identifier component. \n" +
"function metatable:__index(key) -- key is e.g. \"Form\" \n" +
" -- Get the fully-qualified name, e.g. \"System.Windows.Forms.Form\" \n" +
" local fqn = ((rawget(self, \".fqn\") and rawget(self, \".fqn\") .. \n" +
" \".\") or \"\") .. key \n" +
" \n" +
" -- Try to find either a luanet function or a CLR type \n" +
" local obj = rawget(luanet, key) or import_type(fqn) \n" +
" \n" +
" -- If key is neither a luanet function or a CLR type, then it is simply \n" +
" -- an identifier component. \n" +
" if obj == nil then \n" +
" -- It might be an assembly, so we load it too. \n" +
" load_assembly(fqn) \n" +
" obj = { [\".fqn\"] = fqn } \n" +
" setmetatable(obj, metatable) \n" +
" end \n" +
" \n" +
" -- Cache this lookup \n" +
" rawset(self, key, obj) \n" +
" return obj \n" +
"end \n" +
" \n" +
"-- A non-type has been called; e.g. foo = System.Foo() \n" +
"function metatable:__call(...) \n" +
" error(\"No such type: \" .. rawget(self, \".fqn\"), 2) \n" +
"end \n" +
" \n" +
"-- This is the root of the .NET namespace \n" +
"luanet[\".fqn\"] = false \n" +
"setmetatable(luanet, metatable) \n" +
" \n" +
"-- Preload the mscorlib assembly \n" +
"luanet.load_assembly(\"mscorlib\") \n";
#region Globals auto-complete
/// <summary>
/// An alphabetically sorted list of all globals (objects, methods, etc.) externally added to this Lua instance
/// </summary>
/// <remarks>Members of globals are also listed. The formatting is optimized for text input auto-completion.</remarks>
public IEnumerable<string> Globals
{
get
{
// Only sort list when necessary
if(!globalsSorted)
{
globals.Sort();
globalsSorted = true;
}
return globals;
}
}
#endregion
public Lua()
{
luaState = LuaCore.luaL_newstate(); // steffenj: Lua 5.1.1 API change (lua_open is gone)
//LuaCore.luaopen_base(luaState); // steffenj: luaopen_* no longer used
LuaCore.luaL_openlibs(luaState); // steffenj: Lua 5.1.1 API change (luaopen_base is gone, just open all libs right here)
LuaCore.lua_pushstring(luaState, "LUAINTERFACE LOADED");
LuaCore.lua_pushboolean(luaState, 1);
LuaCore.lua_settable(luaState, (int)PseudoIndex.Registry);
LuaCore.lua_newtable(luaState);
LuaCore.lua_setglobal(luaState, "luanet");
LuaCore.lua_pushvalue(luaState, (int)PseudoIndex.Globals);
LuaCore.lua_getglobal(luaState, "luanet");
LuaCore.lua_pushstring(luaState, "getmetatable");
LuaCore.lua_getglobal(luaState, "getmetatable");
LuaCore.lua_settable(luaState, -3);
LuaCore.lua_replace(luaState, (int)PseudoIndex.Globals);
translator = new ObjectTranslator(this, luaState);
LuaCore.lua_replace(luaState, (int)PseudoIndex.Globals);
LuaLib.luaL_dostring(luaState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring
// We need to keep this in a managed reference so the delegate doesn't get garbage collected
panicCallback = new LuaCore.lua_CFunction(PanicCallback);
LuaCore.lua_atpanic(luaState, panicCallback);
//LuaCore.lua_atlock(luaState, lockCallback = new LuaCore.lua_CFunction(LockCallback));
//LuaCore.lua_atunlock(luaState, unlockCallback = new LuaCore.lua_CFunction(UnlockCallback));
}
/*
* CAUTION: LuaInterface.Lua instances can't share the same lua state!
*/
public Lua(LuaCore.lua_State lState)
{
LuaCore.lua_pushstring(lState, "LUAINTERFACE LOADED");
LuaCore.lua_gettable(lState, (int)PseudoIndex.Registry);
if(LuaCore.lua_toboolean(lState, -1).ToBoolean())
{
LuaCore.lua_settop(lState, -2);
throw new LuaException("There is already a LuaInterface.Lua instance associated with this Lua state");
}
else
{
LuaCore.lua_settop(lState, -2);
LuaCore.lua_pushstring(lState, "LUAINTERFACE LOADED");
LuaCore.lua_pushboolean(lState, 1);
LuaCore.lua_settable(lState, (int)PseudoIndex.Registry);
luaState = lState;
LuaCore.lua_pushvalue(lState, (int)PseudoIndex.Globals);
LuaCore.lua_getglobal(lState, "luanet");
LuaCore.lua_pushstring(lState, "getmetatable");
LuaCore.lua_getglobal(lState, "getmetatable");
LuaCore.lua_settable(lState, -3);
LuaCore.lua_replace(lState, (int)PseudoIndex.Globals);
translator = new ObjectTranslator(this, luaState);
LuaCore.lua_replace(lState, (int)PseudoIndex.Globals);
LuaLib.luaL_dostring(lState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring
}
_StatePassed = true;
}
/// <summary>
/// Called for each lua_lock call
/// </summary>
/// <param name = "luaState"></param>
/// Not yet used
/*int LockCallback(LuaCore.lua_State luaState)
{
// Monitor.Enter(luaLock);
return 0;
}*/
/// <summary>
/// Called for each lua_unlock call
/// </summary>
/// <param name = "luaState"></param>
/// Not yet used
/*int UnlockCallback(LuaCore.lua_State luaState)
{
// Monitor.Exit(luaLock);
return 0;
}*/
public void Close()
{
if(_StatePassed)
return;
////// if(luaState != LuaCore.lua_State.Zero)
if(!luaState.IsNull())
LuaCore.lua_close(luaState);
//luaState = LuaCore.lua_State.Zero; <- suggested by Christopher Cebulski http://luaforge.net/forum/forum.php?thread_id = 44593&forum_id = 146
}
static int PanicCallback(LuaCore.lua_State luaState)
{
// string desc = LuaCore.lua_tostring(luaState, 1);
string reason = string.Format("unprotected error in call to Lua API ({0})", LuaCore.lua_tostring(luaState, -1));
// lua_tostring(L, -1);
throw new LuaException(reason);
}
/// <summary>
/// Assuming we have a Lua error string sitting on the stack, throw a C# exception out to the user's app
/// </summary>
/// <exception cref = "LuaScriptException">Thrown if the script caused an exception</exception>
private void ThrowExceptionFromError(int oldTop)
{
object err = translator.getObject(luaState, -1);
LuaCore.lua_settop(luaState, oldTop);
// A pre-wrapped exception - just rethrow it (stack trace of InnerException will be preserved)
var luaEx = err as LuaScriptException;
if(!luaEx.IsNull())
throw luaEx;
// A non-wrapped Lua error (best interpreted as a string) - wrap it and throw it
if(err.IsNull())
err = "Unknown Lua Error";
throw new LuaScriptException(err.ToString(), string.Empty);
}
/// <summary>
/// Convert C# exceptions into Lua errors
/// </summary>
/// <returns>num of things on stack</returns>
/// <param name = "e">null for no pending exception</param>
internal int SetPendingException(Exception e)
{
var caughtExcept = e;
if(!caughtExcept.IsNull())
{
translator.throwError(luaState, caughtExcept);
LuaCore.lua_pushnil(luaState);
return 1;
}
else
return 0;
}
/// <summary>
///
/// </summary>
/// <param name = "chunk"></param>
/// <param name = "name"></param>
/// <returns></returns>
public LuaFunction LoadString(string chunk, string name)
{
int oldTop = LuaCore.lua_gettop(luaState);
executing = true;
try
{
if(LuaLib.luaL_loadbuffer(luaState, chunk, name) != 0)
ThrowExceptionFromError(oldTop);
}
finally
{
executing = false;
}
var result = translator.getFunction(luaState, -1);
translator.popValues(luaState, oldTop);
return result;
}
/// <summary>
///
/// </summary>
/// <param name = "fileName"></param>
/// <returns></returns>
public LuaFunction LoadFile(string fileName)
{
int oldTop = LuaCore.lua_gettop(luaState);
if(LuaCore.luaL_loadfile(luaState, fileName) != 0)
ThrowExceptionFromError(oldTop);
var result = translator.getFunction(luaState, -1);
translator.popValues(luaState, oldTop);
return result;
}
/*
* Excutes a Lua chunk and returns all the chunk's return
* values in an array
*/
public object[] DoString(string chunk)
{
int oldTop = LuaCore.lua_gettop(luaState);
if(LuaLib.luaL_loadbuffer(luaState, chunk, "chunk") == 0)
{
executing = true;
try
{
if(LuaCore.lua_pcall(luaState, 0, -1, 0) == 0)
return translator.popValues(luaState, oldTop);
else
ThrowExceptionFromError(oldTop);
}
finally
{
executing = false;
}
}
else
ThrowExceptionFromError(oldTop);
return null; // Never reached - keeps compiler happy
}
/// <summary>
/// Executes a Lua chnk and returns all the chunk's return values in an array.
/// </summary>
/// <param name = "chunk">Chunk to execute</param>
/// <param name = "chunkName">Name to associate with the chunk</param>
/// <returns></returns>
public object[] DoString(string chunk, string chunkName)
{
int oldTop = LuaCore.lua_gettop(luaState);
executing = true;
if(LuaLib.luaL_loadbuffer(luaState, chunk, chunkName) == 0)
{
try
{
if(LuaCore.lua_pcall(luaState, 0, -1, 0) == 0)
return translator.popValues(luaState, oldTop);
else
ThrowExceptionFromError(oldTop);
}
finally
{
executing = false;
}
}
else
ThrowExceptionFromError(oldTop);
return null; // Never reached - keeps compiler happy
}
/*
* Excutes a Lua file and returns all the chunk's return
* values in an array
*/
public object[] DoFile(string fileName)
{
int oldTop = LuaCore.lua_gettop(luaState);
if(LuaCore.luaL_loadfile(luaState, fileName) == 0)
{
executing = true;
try
{
if(LuaCore.lua_pcall(luaState, 0, -1, 0) == 0)
return translator.popValues(luaState, oldTop);
else
ThrowExceptionFromError(oldTop);
}
finally
{
executing = false;
}
}
else
ThrowExceptionFromError(oldTop);
return null; // Never reached - keeps compiler happy
}
/*
* Indexer for global variables from the LuaInterpreter
* Supports navigation of tables by using . operator
*/
public object this[string fullPath]
{
get
{
object returnValue = null;
int oldTop = LuaCore.lua_gettop(luaState);
string[] path = fullPath.Split(new char[] { '.' });
LuaCore.lua_getglobal(luaState, path[0]);
returnValue = translator.getObject(luaState, -1);
if(path.Length>1)
{
string[] remainingPath = new string[path.Length-1];
Array.Copy(path, 1, remainingPath, 0, path.Length-1);
returnValue = getObject(remainingPath);
}
LuaCore.lua_settop(luaState, oldTop);
return returnValue;
}
set
{
int oldTop = LuaCore.lua_gettop(luaState);
string[] path = fullPath.Split(new char[] { '.' });
if(path.Length == 1)
{
translator.push(luaState, value);
LuaCore.lua_setglobal(luaState, fullPath);
}
else
{
LuaCore.lua_getglobal(luaState, path[0]);
string[] remainingPath = new string[path.Length-1];
Array.Copy(path, 1, remainingPath, 0, path.Length-1);
setObject(remainingPath, value);
}
LuaCore.lua_settop(luaState, oldTop);
// Globals auto-complete
if(value.IsNull())
{
// Remove now obsolete entries
globals.Remove(fullPath);
}
else
{
// Add new entries
if(!globals.Contains(fullPath))
registerGlobal(fullPath, value.GetType(), 0);
}
}
}
#region Globals auto-complete
/// <summary>
/// Adds an entry to <see cref = "globals"/> (recursivley handles 2 levels of members)
/// </summary>
/// <param name = "path">The index accessor path ot the entry</param>
/// <param name = "type">The type of the entry</param>
/// <param name = "recursionCounter">How deep have we gone with recursion?</param>
private void registerGlobal(string path, Type type, int recursionCounter)
{
// If the type is a global method, list it directly
if(type == typeof(LuaCore.lua_CFunction))
{
// Format for easy method invocation
globals.Add(path + "(");
}
// If the type is a class or an interface and recursion hasn't been running too long, list the members
else if((type.IsClass || type.IsInterface) && type != typeof(string) && recursionCounter < 2)
{
#region Methods
foreach(var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance))
{
if(
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(method.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) &&
(method.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0) &&
// Exclude some generic .NET methods that wouldn't be very usefull in Lua
method.Name != "GetType" && method.Name != "GetHashCode" && method.Name != "Equals" &&
method.Name != "ToString" && method.Name != "Clone" && method.Name != "Dispose" &&
method.Name != "GetEnumerator" && method.Name != "CopyTo" &&
!method.Name.StartsWith("get_", StringComparison.Ordinal) &&
!method.Name.StartsWith("set_", StringComparison.Ordinal) &&
!method.Name.StartsWith("add_", StringComparison.Ordinal) &&
!method.Name.StartsWith("remove_", StringComparison.Ordinal))
{
// Format for easy method invocation
string command = path + ":" + method.Name + "(";
if(method.GetParameters().Length == 0) command += ")";
globals.Add(command);
}
}
#endregion
#region Fields
foreach(var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance))
{
if(
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(field.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) &&
(field.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0))
{
// Go into recursion for members
registerGlobal(path + "." + field.Name, field.FieldType, recursionCounter + 1);
}
}
#endregion
#region Properties
foreach(var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if(
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(property.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) &&
(property.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0)
// Exclude some generic .NET properties that wouldn't be very usefull in Lua
&& property.Name != "Item")
{
// Go into recursion for members
registerGlobal(path + "." + property.Name, property.PropertyType, recursionCounter + 1);
}
}
#endregion
}
else
globals.Add(path); // Otherwise simply add the element to the list
// List will need to be sorted on next access
globalsSorted = false;
}
#endregion
/*
* Navigates a table in the top of the stack, returning
* the value of the specified field
*/
internal object getObject(string[] remainingPath)
{
object returnValue = null;
for(int i = 0; i < remainingPath.Length; i++)
{
LuaCore.lua_pushstring(luaState, remainingPath[i]);
LuaCore.lua_gettable(luaState, -2);
returnValue = translator.getObject(luaState, -1);
if(returnValue.IsNull())
break;
}
return returnValue;
}
/*
* Gets a numeric global variable
*/
public double GetNumber(string fullPath)
{
return (double)this[fullPath];
}
/*
* Gets a string global variable
*/
public string GetString(string fullPath)
{
return this[fullPath].ToString();
}
/*
* Gets a table global variable
*/
public LuaTable GetTable(string fullPath)
{
return (LuaTable)this[fullPath];
}
/*
* Gets a table global variable as an object implementing
* the interfaceType interface
*/
public object GetTable(Type interfaceType, string fullPath)
{
return CodeGeneration.Instance.GetClassInstance(interfaceType, GetTable(fullPath));
}
/*
* Gets a function global variable
*/
public LuaFunction GetFunction(string fullPath)
{
object obj = this[fullPath];
return (obj is LuaCore.lua_CFunction ? new LuaFunction((LuaCore.lua_CFunction)obj, this) : (LuaFunction)obj);
//return (obj is LuaCore.lua_CFunction ? new LuaFunction((LuaCore.lua_CFunction)obj, this) : /*(LuaFunction)*/new LuaFunction(obj.GetHashCode(), this));
}
/*
* Gets a function global variable as a delegate of
* type delegateType
*/
public Delegate GetFunction(Type delegateType, string fullPath)
{
return CodeGeneration.Instance.GetDelegate(delegateType, GetFunction(fullPath));
}
/*
* Calls the object as a function with the provided arguments,
* returning the function's returned values inside an array
*/
internal object[] callFunction(object function, object[] args)
{
return callFunction(function, args, null);
}
/*
* Calls the object as a function with the provided arguments and
* casting returned values to the types in returnTypes before returning
* them in an array
*/
internal object[] callFunction(object function, object[] args, Type[] returnTypes)
{
int nArgs = 0;
int oldTop = LuaCore.lua_gettop(luaState);
if(!LuaCore.lua_checkstack(luaState, args.Length+6).ToBoolean())
throw new LuaException("Lua stack overflow");
translator.push(luaState, function);
if(!args.IsNull())
{
nArgs = args.Length;
for(int i = 0; i < args.Length; i++)
translator.push(luaState, args[i]);
}
executing = true;
try
{
int error = LuaCore.lua_pcall(luaState, nArgs, -1, 0);
if(error != 0)
ThrowExceptionFromError(oldTop);
}
finally
{
executing = false;
}
return !returnTypes.IsNull() ? translator.popValues(luaState, oldTop, returnTypes) : translator.popValues(luaState, oldTop);
}
/*
* Navigates a table to set the value of one of its fields
*/
internal void setObject(string[] remainingPath, object val)
{
for(int i = 0; i < remainingPath.Length-1; i++)
{
LuaCore.lua_pushstring(luaState, remainingPath[i]);
LuaCore.lua_gettable(luaState, -2);
}
LuaCore.lua_pushstring(luaState, remainingPath[remainingPath.Length-1]);
translator.push(luaState, val);
LuaCore.lua_settable(luaState, -3);
}
/*
* Creates a new table as a global variable or as a field
* inside an existing table
*/
public void NewTable(string fullPath)
{
string[] path = fullPath.Split(new char[] { '.' });
int oldTop = LuaCore.lua_gettop(luaState);
if(path.Length == 1)
{
LuaCore.lua_newtable(luaState);
LuaCore.lua_setglobal(luaState, fullPath);
}
else
{
LuaCore.lua_getglobal(luaState, path[0]);
for(int i = 1; i < path.Length-1; i++)
{
LuaCore.lua_pushstring(luaState, path[i]);
LuaCore.lua_gettable(luaState, -2);
}
LuaCore.lua_pushstring(luaState, path[path.Length-1]);
LuaCore.lua_newtable(luaState);
LuaCore.lua_settable(luaState, -3);
}
LuaCore.lua_settop(luaState, oldTop);
}
public ListDictionary GetTableDict(LuaTable table)
{
var dict = new ListDictionary();
int oldTop = LuaCore.lua_gettop(luaState);
translator.push(luaState, table);
LuaCore.lua_pushnil(luaState);
while(LuaCore.lua_next(luaState, -2) != 0)
{
dict[translator.getObject(luaState, -2)] = translator.getObject(luaState, -1);
LuaCore.lua_settop(luaState, -2);
}
LuaCore.lua_settop(luaState, oldTop);
return dict;
}
/*
* Lets go of a previously allocated reference to a table, function
* or userdata
*/
#region lua debug functions
/// <summary>
/// Activates the debug hook
/// </summary>
/// <param name = "mask">Mask</param>
/// <param name = "count">Count</param>
/// <returns>see lua docs. -1 if hook is already set</returns>
/// <author>Reinhard Ostermeier</author>
/*public int SetDebugHook(EventMasks mask, int count)
{
if(hookCallback.IsNull())
{
hookCallback = new LuaCore.lua_Hook(DebugHookCallback);
return LuaCore.lua_sethook(luaState, hookCallback, (int)mask, count);
}
return -1;
}*/
/// <summary>
/// Removes the debug hook
/// </summary>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public int RemoveDebugHook()
{
hookCallback = null;
return LuaCore.lua_sethook(luaState, null, 0, 0);
}
/// <summary>
/// Gets the hook mask.
/// </summary>
/// <returns>hook mask</returns>
/// <author>Reinhard Ostermeier</author>
public EventMasks GetHookMask()
{
return (EventMasks)LuaCore.lua_gethookmask(luaState);
}
/// <summary>
/// Gets the hook count
/// </summary>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public int GetHookCount()
{
return LuaCore.lua_gethookcount(luaState);
}
/// <summary>
/// Gets the stack entry on a given level
/// </summary>
/// <param name = "level">level</param>
/// <param name = "luaDebug">lua debug structure</param>
/// <returns>Returns true if level was allowed, false if level was invalid.</returns>
/// <author>Reinhard Ostermeier</author>
/*public bool GetStack(int level, out LuaDebug luaDebug)
{
luaDebug = new LuaDebug();
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaCore.lua_getstack(luaState, level, ld) != 0;
}
finally
{
luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug));
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Gets info (see lua docs)
/// </summary>
/// <param name = "what">what (see lua docs)</param>
/// <param name = "luaDebug">lua debug structure</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
/*public int GetInfo(String what, ref LuaDebug luaDebug)
{
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaCore.lua_getinfo(luaState, what, ld);
}
finally
{
luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug));
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Gets local (see lua docs)
/// </summary>
/// <param name = "luaDebug">lua debug structure</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
/*public String GetLocal(LuaDebug luaDebug, int n)
{
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaCore.lua_getlocal(luaState, ld, n);
}
finally
{
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Sets local (see lua docs)
/// </summary>
/// <param name = "luaDebug">lua debug structure</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
/*public String SetLocal(LuaDebug luaDebug, int n)
{
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaCore.lua_setlocal(luaState, ld, n);
}
finally
{
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Gets up value (see lua docs)
/// </summary>
/// <param name = "funcindex">see lua docs</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string GetUpValue(int funcindex, int n)
{
return LuaCore.lua_getupvalue(luaState, funcindex, n).ToString();
}
/// <summary>
/// Sets up value (see lua docs)
/// </summary>
/// <param name = "funcindex">see lua docs</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string SetUpValue(int funcindex, int n)
{
return LuaCore.lua_setupvalue(luaState, funcindex, n).ToString();
}
/// <summary>
/// Delegate that is called on lua hook callback
/// </summary>
/// <param name = "luaState">lua state</param>
/// <param name = "luaDebug">Pointer to LuaDebug (lua_debug) structure</param>
/// <author>Reinhard Ostermeier</author>
/*private void DebugHookCallback(LuaCore.lua_State luaState, LuaCore.lua_Debug luaDebug)
{
try
{
LuaDebug ld = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(luaDebug, typeof(LuaDebug));
EventHandler<DebugHookEventArgs> temp = DebugHook;
if(temp != null)
{
temp(this, new DebugHookEventArgs(ld));
}
}
catch (Exception ex)
{
OnHookException(new HookExceptionEventArgs(ex));
}
}*/
private void OnHookException(HookExceptionEventArgs e)
{
var temp = HookException;
if(!temp.IsNull())
temp(this, e);
}
/// <summary>
/// Pops a value from the lua stack.
/// </summary>
/// <returns>Returns the top value from the lua stack.</returns>
/// <author>Reinhard Ostermeier</author>
public object Pop()
{
int top = LuaCore.lua_gettop(luaState);
return translator.popValues(luaState, top - 1)[0];
}
/// <summary>
/// Pushes a value onto the lua stack.
/// </summary>
/// <param name = "value">Value to push.</param>
/// <author>Reinhard Ostermeier</author>
public void Push(object value)
{
translator.push(luaState, value);
}
#endregion
internal void dispose(int reference)
{
///////////// if(luaState != LuaCore.lua_State.Zero)
if(!luaState.IsNull()) //Fix submitted by Qingrui Li
LuaLib.lua_unref(luaState, reference);
}
/*
* Gets a field of the table corresponding to the provided reference
* using rawget (do not use metatables)
*/
internal object rawGetObject(int reference, string field)
{
int oldTop = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, reference);
LuaCore.lua_pushstring(luaState, field);
LuaCore.lua_rawget(luaState, -2);
object obj = translator.getObject(luaState, -1);
LuaCore.lua_settop(luaState, oldTop);
return obj;
}
/*
* Gets a field of the table or userdata corresponding to the provided reference
*/
internal object getObject(int reference, string field)
{
int oldTop = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, reference);
object returnValue = getObject(field.Split(new char[] {'.'}));
LuaCore.lua_settop(luaState, oldTop);
return returnValue;
}
/*
* Gets a numeric field of the table or userdata corresponding the the provided reference
*/
internal object getObject(int reference, object field)
{
int oldTop = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, reference);
translator.push(luaState, field);
LuaCore.lua_gettable(luaState, -2);
object returnValue = translator.getObject(luaState, -1);
LuaCore.lua_settop(luaState, oldTop);
return returnValue;
}
/*
* Sets a field of the table or userdata corresponding the the provided reference
* to the provided value
*/
internal void setObject(int reference, string field, object val)
{
int oldTop = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, reference);
setObject(field.Split(new char[] {'.'}), val);
LuaCore.lua_settop(luaState, oldTop);
}
/*
* Sets a numeric field of the table or userdata corresponding the the provided reference
* to the provided value
*/
internal void setObject(int reference, object field, object val)
{
int oldTop = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, reference);
translator.push(luaState, field);
translator.push(luaState, val);
LuaCore.lua_settable(luaState, -3);
LuaCore.lua_settop(luaState, oldTop);
}
/*
* Registers an object's method as a Lua function (global or table field)
* The method may have any signature
*/
public LuaFunction RegisterFunction(string path, object target, MethodBase function /*MethodInfo function*/) //CP: Fix for struct constructor by Alexander Kappner (link: http://luaforge.net/forum/forum.php?thread_id = 2859&forum_id = 145)
{
// We leave nothing on the stack when we are done
int oldTop = LuaCore.lua_gettop(luaState);
var wrapper = new LuaMethodWrapper(translator, target, function.DeclaringType, function);
translator.push(luaState, new LuaCore.lua_CFunction(wrapper.call));
this[path] = translator.getObject(luaState, -1);
var f = GetFunction(path);
LuaCore.lua_settop(luaState, oldTop);
return f;
}
/*
* Compares the two values referenced by ref1 and ref2 for equality
*/
internal bool compareRef(int ref1, int ref2)
{
int top = LuaCore.lua_gettop(luaState);
LuaLib.lua_getref(luaState, ref1);
LuaLib.lua_getref(luaState, ref2);
int equal = LuaCore.lua_equal(luaState, -1, -2);
LuaCore.lua_settop(luaState, top);
return (equal != 0);
}
internal void pushCSFunction(LuaCore.lua_CFunction function)
{
translator.pushFunction(luaState, function);
}
#region IDisposable Members
public virtual void Dispose()
{
if(!translator.IsNull())
{
translator.pendingEvents.Dispose();
translator = null;
}
this.Close();
GC.Collect();
GC.WaitForPendingFinalizers();
}
#endregion
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Text;
using System.Collections.Generic;
namespace LuaInterface
{
/// <summary>
/// Base class to provide consistent disposal flow across lua objects. Uses code provided by Yves Duhoux and suggestions by Hans Schmeidenbacher and Qingrui Li
/// </summary>
public abstract class LuaBase : IDisposable
{
private bool _Disposed;
protected int _Reference;
protected Lua _Interpreter;
~LuaBase()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public virtual void Dispose(bool disposeManagedResources)
{
if(!_Disposed)
{
if(disposeManagedResources)
{
if(_Reference != 0)
_Interpreter.dispose(_Reference);
}
_Interpreter = null;
_Disposed = true;
}
}
public override bool Equals(object o)
{
if(o is LuaBase)
{
var l = (LuaBase)o;
return _Interpreter.compareRef(l._Reference, _Reference);
}
else
return false;
}
public override int GetHashCode()
{
return _Reference;
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Text;
using System.Collections.Generic;
namespace LuaInterface
{
/// <summary>
/// Base class to provide consistent disposal flow across lua objects. Uses code provided by Yves Duhoux and suggestions by Hans Schmeidenbacher and Qingrui Li
/// </summary>
public abstract class LuaBase : IDisposable
{
private bool _Disposed;
protected int _Reference;
protected Lua _Interpreter;
~LuaBase()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public virtual void Dispose(bool disposeManagedResources)
{
if(!_Disposed)
{
if(disposeManagedResources)
{
if(_Reference != 0)
_Interpreter.dispose(_Reference);
}
_Interpreter = null;
_Disposed = true;
}
}
public override bool Equals(object o)
{
if(o is LuaBase)
{
var l = (LuaBase)o;
return _Interpreter.compareRef(l._Reference, _Reference);
}
else
return false;
}
public override int GetHashCode()
{
return _Reference;
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Text;
using System.Collections.Generic;
namespace LuaInterface
{
using LuaCore = KopiLua.Lua;
public class LuaFunction : LuaBase
{
internal LuaCore.lua_CFunction function;
public LuaFunction(int reference, Lua interpreter)
{
_Reference = reference;
this.function = null;
_Interpreter = interpreter;
}
public LuaFunction(LuaCore.lua_CFunction function, Lua interpreter)
{
_Reference = 0;
this.function = function;
_Interpreter = interpreter;
}
/*
* Calls the function casting return values to the types
* in returnTypes
*/
internal object[] call(object[] args, Type[] returnTypes)
{
return _Interpreter.callFunction(this, args, returnTypes);
}
/*
* Calls the function and returns its return values inside
* an array
*/
public object[] Call(params object[] args)
{
return _Interpreter.callFunction(this, args);
}
/*
* Pushes the function into the Lua stack
*/
internal void push(LuaCore.lua_State luaState)
{
if(_Reference != 0)
LuaLib.lua_getref(luaState, _Reference);
else
_Interpreter.pushCSFunction(function);
}
public override string ToString()
{
return "function";
}
public override bool Equals(object o)
{
if(o is LuaFunction)
{
var l = (LuaFunction)o;
if(this._Reference != 0 && l._Reference != 0)
return _Interpreter.compareRef(l._Reference, this._Reference);
else
return this.function == l.function;
}
else
return false;
}
public override int GetHashCode()
{
return _Reference != 0 ? _Reference : function.GetHashCode();
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Text;
using System.Collections.Generic;
namespace LuaInterface
{
using LuaCore = KopiLua.Lua;
public class LuaFunction : LuaBase
{
internal LuaCore.lua_CFunction function;
public LuaFunction(int reference, Lua interpreter)
{
_Reference = reference;
this.function = null;
_Interpreter = interpreter;
}
public LuaFunction(LuaCore.lua_CFunction function, Lua interpreter)
{
_Reference = 0;
this.function = function;
_Interpreter = interpreter;
}
/*
* Calls the function casting return values to the types
* in returnTypes
*/
internal object[] call(object[] args, Type[] returnTypes)
{
return _Interpreter.callFunction(this, args, returnTypes);
}
/*
* Calls the function and returns its return values inside
* an array
*/
public object[] Call(params object[] args)
{
return _Interpreter.callFunction(this, args);
}
/*
* Pushes the function into the Lua stack
*/
internal void push(LuaCore.lua_State luaState)
{
if(_Reference != 0)
LuaLib.lua_getref(luaState, _Reference);
else
_Interpreter.pushCSFunction(function);
}
public override string ToString()
{
return "function";
}
public override bool Equals(object o)
{
if(o is LuaFunction)
{
var l = (LuaFunction)o;
if(this._Reference != 0 && l._Reference != 0)
return _Interpreter.compareRef(l._Reference, this._Reference);
else
return this.function == l.function;
}
else
return false;
}
public override int GetHashCode()
{
return _Reference != 0 ? _Reference : function.GetHashCode();
}
}
}
\ No newline at end of file
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