/*
* Created by SharpDevelop.
* User: elijah
* Date: 12/23/2011
* Time: 12:35 PM
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using SharpLua.Library;
namespace SharpLua.LuaTypes
{
///
/// A Lua class
///
[Serializable()]
public class LuaClass : LuaValue
{
private static List classNames = new List();
public bool Final = false;
public bool Static = false;
private string _name = "";
public string Name
{
get
{
return _name;
}
set
{
_name = Rename(value);
}
}
public List ParentClasses = new List();
public List ChildClasses = new List();
public LuaFunction IndexFunction;
public LuaFunction NewIndexFunction;
public LuaFunction CallFunction;
public LuaFunction ToStringFunction;
public LuaFunction Constructor;
public LuaFunction Destructor;
public LuaTable Self;
public LuaClass(string name, bool final, bool _static)
{
this.Name = Rename(name);
this.Final = final;
this.Static = _static;
this.IndexFunction = new LuaFunction(new LuaFunc((LuaValue[] args) =>
{return null; }));
this.CallFunction = new LuaFunction(new LuaFunc((LuaValue[] args) =>
{return null; }));
this.NewIndexFunction = new LuaFunction(new LuaFunc((LuaValue[] args) =>
{return null; }));
this.ToStringFunction = new LuaFunction(new LuaFunc((LuaValue[] args) =>
{return new LuaString("Lua Class: " + GetHashCode() + ", Name: " + Name); }));
this.Constructor = new LuaFunction(new LuaFunc((LuaValue[] args) =>
{
// do nothing
return LuaNil.Nil;
}));
this.Destructor = new LuaFunction(new LuaFunc((LuaValue[] args) =>
{
// do nothing
return LuaNil.Nil;
}));
this.Self = new LuaTable();
Self.Register("new", New);
Self.Register("Set", Set);
Self.Register("HasMember", HasMember);
Self.Register("Inherits", Inherits);
Self.Register("IsParentOf", IsParentOf);
Self.Register("GetParentClasses", GetParentClasses);
Self.Register("GetChildClasses", GetChildClasses);
Self.Register("CallParentMethod", CallParentMethod);
Self.Register("CreateSubclass", CreateSubClass);
Self.Register("CallMethod", CallMethod);
Self.Register("GetTable", GetTable);
GenerateMetaTable();
}
public override object Value {
get {
return Self;
}
}
public override string GetTypeCode()
{
return "class";
}
public LuaValue New(LuaValue[] args)
{
if (Static)
throw new Exception("Cannot create an instance of a static class!");
LuaClass n = ClassLib.CreateInstance(new LuaValue[] {this }) as LuaClass;
n.Constructor.Invoke(args);
return n;
}
public LuaValue Set(LuaValue[] args)
{
for (int i = 1; i < args.Length; i++)
TableLib.Copy(new LuaValue[] {Self, args[i]});
return Self;
}
public LuaValue HasMember(LuaValue[] args)
{ //(m)
return ClassLib.IsMemberOf(new LuaValue[] {args[0], this});
}
public LuaValue Inherits(LuaValue[] args)
{ //(_class)
foreach (LuaClass c in this.ParentClasses)
{
if (Name == c.Name)
return LuaBoolean.True;
}
return LuaBoolean.False;
}
public LuaValue IsParentOf(LuaValue[] args)
{
LuaClass _class = args[0] as LuaClass;
foreach (LuaClass c in ChildClasses)
if (c.Name == _class.Name)
return LuaBoolean.True;
return LuaBoolean.False;
}
public LuaValue GetTable(LuaValue[] args)
{
return Self;
}
public LuaValue GetParentClasses(LuaValue[] args)
{
LuaTable t = new LuaTable();
foreach (LuaClass p in ParentClasses)
t.AddValue(p);
return t;
}
public LuaValue GetChildClasses(LuaValue[] args)
{
List c = new List();
foreach (LuaClass p in ChildClasses)
c.Add(p);
return new LuaMultiValue(c.ToArray());
}
public LuaValue CallParentMethod(LuaValue[] args)
{
//method, ...
string method = args[0].Value.ToString();
// strip method name
List args2 = new List();
foreach (LuaValue a in args)
args2.Add(a);
args2.RemoveAt(0);
LuaFunction func = InternalCallParentMethod(method) as LuaFunction;
if (func == null)
throw new Exception("Cannot find function '" + method + "'!");
else
return func.Invoke(args2.ToArray());
}
public LuaValue InternalCallParentMethod(string method)
{
LuaValue m = LuaNil.Nil;
if (ParentClasses.Count > 0)
{
foreach (LuaClass c in ParentClasses)
{
m = ClassLib.FindMethod(new LuaValue[] {new LuaString(method), c});
if (m != null)
break;
}
}
if (m == LuaNil.Nil)
for (int i = 0;i < ParentClasses.Count; i++)
m = ParentClasses[i].InternalCallParentMethod(method);
return m;
}
// creates a subclass inheriting all args except arg[1] if its a table
// e.g. x = c:CreateSubclass()
public LuaValue CreateSubClass(LuaValue[] args)
{
List args2 = new List();
foreach (LuaValue a in args)
{
args2.Add(a);
}
args2.Add(this);
return ClassLib.CreateClass(args);
}
public LuaValue CallMethod(LuaValue[] args)
{
//(func, ...)
// strip method name
string func = args[0].Value.ToString();
List args2 = new List();
if ((args[1] as LuaUserdata) != null)
{
foreach (LuaValue a in ((args[1] as LuaUserdata).Value as LuaValue[]))
args2.Add(a);
}
else
{
foreach (LuaValue a in args)
args2.Add(a);
}
try
{
args2.RemoveAt(0);
}
catch
{
}
LuaFunction f = ClassLib.FindMethod(new LuaValue[] {new LuaString(func), this}) as LuaFunction;
if ((f == null))
f = InternalCallParentMethod(func) as LuaFunction;
// if its still LuaNil.Nil then throw an error
if ((f == null))
throw new Exception("Cannot find function '" + func + "'!");
return f.Invoke(args2.ToArray());
}
public override string ToString()
{
return ToStringFunction.Invoke(new LuaValue[] {}).ToString();
}
public LuaValue GetObject(LuaValue key, LuaClass p)
{
if ((p.Self.RawGetValue(key) != null) && (p.Self.RawGetValue(key) != LuaNil.Nil))
return p.Self.RawGetValue(key);
else
{
foreach (LuaClass c in p.ParentClasses)
return GetObject(key, c);
}
return LuaNil.Nil;
}
public void GenerateMetaTable()
{
Self.MetaTable = new LuaTable();
Self.MetaTable.Register("__index",new LuaFunc(delegate(LuaValue[] args)
{ //(table, key)
LuaValue key = args[0];
IndexFunction.Invoke(new LuaValue[] {Self, key}); // user defined __index function
// attempt to get from parents also
return GetObject(key, this); //CallMethod(new LuaValue[] {key});
}));
Self.MetaTable.Register("__call", new LuaFunc(delegate(LuaValue[] args)
{ //(func, ...)
if (args.Length == 0)
return LuaNil.Nil;
List args2 = new List();
foreach (LuaValue a in args)
args2.Add(a);
args2.RemoveAt(0);
CallFunction.Invoke(new LuaValue[] {args[0], new LuaMultiValue(args2.ToArray())}); // user defined __call function
return CallMethod(new LuaValue[] {args[0], new LuaUserdata(args2.ToArray())}); // call function
}));
Self.MetaTable.Register("__newindex",new LuaFunc(delegate(LuaValue[] args)
{
LuaValue key = args[1];
LuaValue value = args[2];
//(table, key, value)
NewIndexFunction.Invoke(new LuaValue[] {Self, key, value}); // user defined __newindex function
// check for user defined "metamethods"
string obj = key.Value.ToString();
if (obj == "__index")
{
// assign this to the __indexfunction variable
IndexFunction = value as LuaFunction;
}
else if (obj == "__newindex")
NewIndexFunction = value as LuaFunction;
else if (obj == "__call")
CallFunction = value as LuaFunction;
else if (obj == "__tostring")
ToStringFunction = value as LuaFunction;
else if (obj == "final")
Final = true;
else if (obj == "static")
Static = true;
else if (obj == "name")
Name = Rename(value.Value.ToString());
else if (obj == "constructor")
Constructor = (LuaFunction) value;
else if (obj == "destructor")
Destructor = (LuaFunction) value;
else // its a normal key/value pair
Self.SetKeyValue(key, value);
return LuaNil.Nil;
}));
Self.MetaTable.Register("__tostring", new LuaFunc(delegate(LuaValue[] args)
{
return ToStringFunction.Invoke(new LuaValue[] {});
}));
this.MetaTable = Self.MetaTable;
}
string Rename(string val)
{
classNames.Remove(this.Name);
if (classNames.Contains(val))
throw new Exception("Class '" + val + "' is already defined!");
return val;
}
}
}