using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.IO;
namespace bindingGen
{
///
/// 输入目录,在目录下生成./binding目录,存放导出的binding代码
///
class Program
{
// {0} 文件名
// {1} 第一个名称空间
// {2} 第二个名称空间
// {3} 内容
static string output = @"#include ""../{0}.h""
using namespace std;
namespace {1}
{{
namespace {2}
{{
{3}
}}
}}
";
// {0} 类名
// {1} 内容
static string registry = @"
LUAX_REGISTRY({0})
{{
{1}
}}
";
// {0} 类名
// {1} 内容
static string postprocess = @"
LUAX_POSTPROCESS({0})
{{
{1}
}}
";
// {0} 类名
// {1} 去掉_的函数名
// {2} 小写的类名
static string method = @"
// {2}:{1}()
LUAX_IMPL_METHOD({0}, _{1})
{{
LUAX_PREPARE(L, {0});
}}
";
// {0} 类名
// {1} 去掉_的函数名
static string method_new = @"
// {0}.{1}()
LUAX_IMPL_METHOD({0}, _{1})
{{
LUAX_STATE(L);
}}
";
static string make_register_methods(MatchCollection methods)
{
if (methods.Count == 0)
return "";
string register_methods = "";
register_methods += "\t\t\tLUAX_REGISTER_METHODS(state,\n";
int maxlen = 0;
foreach(var m in methods)
{
string method = m.ToString();
if (method.Count() > maxlen)
maxlen = method.Count();
}
for(int i = 0; i < methods.Count; ++i)
{
Match m = methods[i];
string method = m.ToString();
register_methods += "\t\t\t\t";
register_methods += "{ ";
register_methods += ('"' + method.Substring(1, method.Count() - 1) + "\",").PadRight(maxlen + 3, ' ');
register_methods += method.PadRight(maxlen + 1, ' ');
register_methods += "}";
if (i != methods.Count - 1)
register_methods += ',';
register_methods += '\n';
}
register_methods += "\t\t\t);";
return register_methods;
}
static string make_impl_methods(MatchCollection mc, string cname)
{
if (mc.Count == 0)
return "";
string methods = "";
foreach(var m in mc)
{
string name = m.ToString();
if(name != "_New")
{
methods += String.Format(method, cname, name.Substring(1, name.Count() - 1), cname.ToLower());
}
else
{
methods += String.Format(method_new, cname, name.Substring(1, name.Count() - 1));
}
}
return methods;
}
static string make_register_enum(MatchCollection mc, string src)
{
if (mc.Count == 0)
return "";
string reg_enum_l = @"(?<=enum\s";
string reg_enum_r = @"[\s\n]*\{((?!\{)[\s\S])*)[A-Z_]+(?=\s*,)";
string enums = "";
foreach(var m in mc)
{
string name = m.ToString();
enums += "\t\t\tLUAX_REGISTER_ENUM(state, ";
enums += "\"E" + name + "\",\n";
MatchCollection values = Regex.Matches(src, reg_enum_l + name + reg_enum_r);
string[] enames = new string[values.Count];
string[] keys = new string[values.Count];
int maxEname = 0, maxKey = 0;
for (int i = 0; i < values.Count; ++i)
{
enames[i] = values[i].ToString();
keys[i] = enames[i].Substring(enames[i].LastIndexOf('_') + 1, enames[i].Count() - enames[i].LastIndexOf('_') -1);
if (enames[i].Count() > maxEname) maxEname = enames[i].Count();
if (keys[i].Count() > maxKey) maxKey = keys[i].Count();
}
for(int i = 0; i < values.Count; ++i)
{
enums += "\t\t\t\t{ ";
enums += ('"' + keys[i] + "\",").PadRight(maxKey + 4);
enums += enames[i].PadRight(maxEname + 1);
enums += "}";
if (i != values.Count - 1)
enums += ",";
enums += "\n";
}
enums += "\t\t\t);\n";
}
return enums;
}
///
/// 用法:
/// bindingGen <目录>
///
///
static void Main(string[] args)
{
if (args.Length < 1)
return;
string dir = args[0];
Console.WriteLine("源目录: " + dir);
if (!Directory.Exists(dir))
return;
string reg_class = @"(?<=Portable\<)[0-9a-zA-Z]+(?=\>)";
string reg_methods = @"(?<=LUAX_DECL_METHOD\()[0-9a-zA-Z_]+(?=\))";
string reg_enums = @"(?<=LUAX_DECL_ENUM\()[0-9a-zA-Z_]+(?=\))";
string reg_namespace = @"(?<=namespace\s)[0-9a-zA-Z]+(?=[\s\n]*)";
if(!Directory.Exists(dir + "/binding"))
{
Directory.CreateDirectory(dir + "/binding");
}
string[] files = Directory.GetFiles(dir);
for(int i = 0; i < files.Count(); ++i)
{
string file = files[i];
if (!File.Exists(file))
continue;
file = file.Replace('\\', '/');
string name = file.Substring(file.LastIndexOf('/') + 1, file.LastIndexOf('.') - file.LastIndexOf('/') - 1);
string bindingFile = dir + "/binding/_" + name + ".cpp";
if (File.Exists(bindingFile))
continue;
string code = File.ReadAllText(file);
//
Match m = Regex.Match(code, reg_class);
if (!m.Success)
continue;
string className = m.ToString();
MatchCollection mc = Regex.Matches(code, reg_namespace);
// 应该两个名称空间
if(mc.Count != 2)
{
Console.WriteLine("Error: 源文件没有两个名称空间 " + file);
continue;
}
string namespace1 = mc[0].ToString();
string namespace2 = mc[1].ToString();
// 名称空间内的内容
string content = "";
mc = Regex.Matches(code, reg_methods);
content += String.Format(registry, className, make_register_methods(mc));
mc = Regex.Matches(code, reg_enums);
content += String.Format(postprocess, className, make_register_enum(mc, code));
mc = Regex.Matches(code, reg_methods);
content += make_impl_methods(mc, className);
string binding = String.Format(output, name, namespace1, namespace2, content);
Console.WriteLine("输出: "+bindingFile);
File.WriteAllText(bindingFile, binding);
}
}
}
}