medit/moo/mooscript/mooscriptgen.py
2010-11-02 01:56:33 -07:00

434 lines
12 KiB
Python

#! /usr/bin/env python
import sys
import os
import tempfile
import mooscriptparser as parser
tmpl_decl_file_start = """\
#ifndef MOO_SCRIPT_CLASSES_GENERATED_H
#define MOO_SCRIPT_CLASSES_GENERATED_H
#include "mooscript-classes-base.h"
namespace mom {
"""
tmpl_decl_file_end = """\
} // namespace mom
#endif /* MOO_SCRIPT_CLASSES_GENERATED_H */
"""
tmpl_decl_forward_cls = """\
class %(ClassName)s;
"""
tmpl_decl_cls_struct_start = """\
class %(ClassName)s : public %(BaseClass)s
{
%(CLASS_DECL)s
public:
"""
tmpl_decl_cls_struct_end = """\
};
"""
def split_camel_case_name(name):
comps = []
cur = ''
for c in name:
if c.islower() or not cur:
cur += c
else:
comps.append(cur)
cur = c
if cur:
comps.append(cur)
return comps
def make_class_dict(cls):
comps = split_camel_case_name(cls.name)
dic= dict(ClassName=cls.name,
CLASS_NAME='_'.join([s.upper() for s in comps]),
class_name='_'.join([s.lower() for s in comps]),
BaseClass='Object',
CLASS_DECL='MOM_OBJECT_DECL(%s)' % (cls.name,),
CLASS_DEFN='MOM_OBJECT_DEFN(%s)' % (cls.name,))
if cls.singleton:
dic['BaseClass'] = '_Singleton<%s>' % (cls.name,)
dic['CLASS_DECL'] = 'MOM_SINGLETON_DECL(%s)' % (cls.name,)
dic['CLASS_DEFN'] = 'MOM_SINGLETON_DEFN(%s)' % (cls.name,)
elif cls.gobject:
dic['BaseClass'] = '_GObjectWrapper<%s, %s>' % (cls.name, cls.gobject)
dic['CLASS_DECL'] = 'MOM_GOBJECT_DECL(%s, %s)' % (cls.name, cls.gobject)
dic['CLASS_DEFN'] = 'MOM_GOBJECT_DEFN(%s, %s)' % (cls.name, cls.gobject)
return dic
def make_method_dict(meth, cls):
dic = make_class_dict(cls)
comps = meth.name.replace('-', '_').split('_')
dic['method_name'] = '_'.join(comps)
dic['signal_name'] = '-'.join(comps)
return dic
tmpl_gen_method_decl = """\
Variant %(method_name)s__imp__(const ArgSet &args);
"""
tmpl_method_decl = """\
%(retval)s%(method_name)s(%(args)s);
"""
def format_param_decl(p):
if isinstance(p.type, parser.Class):
if p.optional:
return '%s *%s' % (p.type.name, p.name)
else:
return '%s &%s' % (p.type.name, p.name)
else:
basic_names = {
'bool': 'bool ',
'string': 'const String &',
'variant': 'const Variant &',
'list': 'const VariantArray &',
'int': 'gint64 ',
'index': 'gint64 ',
'arglist': 'const ArgList &',
'argset': 'const ArgSet &',
}
return basic_names[p.type.name] + p.name
def format_retval(retval):
if retval is None:
return 'void '
elif isinstance(retval.type, parser.Class):
return '%s *' % (retval.type.name,)
else:
basic_names = {
'bool': 'bool ',
'string': 'String ',
'variant': 'Variant ',
'list': 'VariantArray ',
'int': 'gint64 ',
'index': 'gint64 ',
}
return basic_names[retval.type.name]
def _write_method_decl(cls, meth, tmpl, out):
args = ''
if meth.params:
for p in meth.params:
if args:
args += ', '
args += format_param_decl(p)
dic = make_method_dict(meth, cls)
dic['retval'] = format_retval(meth.retval)
dic['args'] = args
out.write(tmpl % dic)
def write_gen_method_decl(cls, meth, out):
_write_method_decl(cls, meth, tmpl_gen_method_decl, out)
def write_method_decl(cls, meth, out):
_write_method_decl(cls, meth, tmpl_method_decl, out)
def write_method_impl_decl(cls, meth, out):
_write_method_decl(cls, meth, tmpl_method_impl_decl, out)
def write_module_decl(out, mod):
out.write(tmpl_decl_file_start)
classes = mod.classes.values()
for cls in classes:
dic = make_class_dict(cls)
out.write(tmpl_decl_forward_cls % dic)
out.write('\n')
for cls in classes:
dic = make_class_dict(cls)
out.write(tmpl_decl_cls_struct_start % dic)
if cls.methods:
out.write('\n')
out.write(' /* methods */\n')
for meth in cls.methods.values():
write_method_decl(cls, meth, out)
out.write('\n')
out.write(' /* methods */\n')
for meth in cls.methods.values():
write_gen_method_decl(cls, meth, out)
# if cls.signals:
# out.write('\n')
# out.write(' /* signals */\n')
# for sig in cls.signals.values():
# write_method_decl(cls, sig, out)
out.write(tmpl_decl_cls_struct_end % dic)
out.write('\n')
# for cls in classes:
# dic = make_class_dict(cls)
# out.write(tmpl_decl_get_type_func % dic)
# for cls in classes:
# if cls.methods:
# out.write('\n')
# for meth in cls.methods.values():
# write_method_impl_decl(cls, meth, out)
out.write(tmpl_decl_file_end)
tmpl_impl_file_start = """\
#include "mooscript-classes.h"
#include "mooscript-classes-util.h"
namespace mom {
static moo::Vector<FunctionCallInfo> func_calls;
FunctionCallInfo current_func()
{
if (!func_calls.empty())
return func_calls[func_calls.size() - 1];
else
moo_return_val_if_reached(FunctionCallInfo("<no function>"));
}
class PushFunctionCall
{
public:
explicit PushFunctionCall(const char *name)
{
func_calls.append(FunctionCallInfo(name));
}
~PushFunctionCall()
{
func_calls.pop_back();
}
};
"""
tmpl_impl_file_end = """\
} // namespace mom
"""
tmpl_impl_object_defn = """\
%(CLASS_DEFN)s
"""
tmpl_impl_class_init_start = """\
void %(ClassName)s::InitMetaObject(MetaObject &meta)
{
"""
tmpl_impl_class_init_end = """\
}
"""
tmpl_impl_method = """\
meta.add_method("%(method_name)s", &%(ClassName)s::%(method_name)s__imp__);
"""
tmpl_impl_signal = """\
meta.add_signal("%(signal_name)s");
"""
def write_class_init(cls, out):
dic = make_class_dict(cls)
out.write(tmpl_impl_class_init_start % dic)
for meth in cls.methods.values():
meth_dic = make_method_dict(meth, cls)
out.write(tmpl_impl_method % meth_dic)
for meth in cls.signals.values():
meth_dic = make_method_dict(meth, cls)
out.write(tmpl_impl_signal % meth_dic)
out.write(tmpl_impl_class_init_end % dic)
tmpl_method_impl_start = """\
Variant %(ClassName)s::%(method_name)s__imp__(const ArgSet &args)
{
PushFunctionCall pfc__("%(ClassName)s::%(method_name)s");
"""
tmpl_method_impl_end = """\
}
"""
tmpl_check_no_args = """\
if (!args.pos.empty() || !args.kw.empty())
Error::raisef("in function %s, no arguments expected",
(const char*) current_func().name);
"""
tmpl_check_no_kwargs = """\
if (!args.kw.empty())
Error::raisef("in function %s, no keyword arguments expected",
(const char*) current_func().name);
"""
tmpl_get_obj_arg = """\
if (args.pos.size() <= %(iarg)d)
Error::raisef("in function %%s, argument '%(argname)s' missing",
(const char*) current_func().name);
%(type)s &%(arg)s = get_object_arg<%(type)s>(args.pos[%(iarg)d], "%(argname)s");
"""
tmpl_get_obj_arg_opt = """\
%(type)s *%(arg)s = get_object_arg_opt<%(type)s>(args.pos.size() > %(iarg)d ? args.pos[%(iarg)d] : Variant(), "%(argname)s");
"""
def write_check_arg_object(meth, p, i, out):
dic = {'arg': 'arg%d' % (i,), 'iarg': i, 'type': p.type.name, 'argname': p.name}
if p.optional:
out.write(tmpl_get_obj_arg_opt % dic)
else:
out.write(tmpl_get_obj_arg % dic)
tmpl_get_arg = """\
if (args.pos.size() <= %(iarg)d)
Error::raisef("in function %%s, argument '%(argname)s' missing",
(const char*) current_func().name);
%(type)s %(arg)s = %(get_arg)s(args.pos[%(iarg)d], "%(argname)s");
"""
tmpl_get_arg_opt = """\
%(type)s %(arg)s = %(get_arg)s_opt(args.pos.size() > %(iarg)d ? args.pos[%(iarg)d] : Variant(), "%(argname)s");
"""
def write_check_arg(meth, p, i, out):
if isinstance(p.type, parser.Class):
write_check_arg_object(meth, p, i, out)
else:
typenames = {
'bool': 'bool',
'string': 'String',
'variant': 'Variant',
'list': 'VariantArray',
'int': 'gint64',
'index': 'gint64',
}
get_arg = {
'bool': 'get_arg_bool',
'string': 'get_arg_string',
'variant': 'get_arg_variant',
'list': 'get_arg_array',
'int': 'get_arg_int',
'index': 'get_arg_index',
}
dic = {'arg': 'arg%d' % (i,), 'iarg': i, 'type': typenames[p.type.name], 'get_arg': get_arg[p.type.name], 'argname': p.name}
if p.optional:
out.write(tmpl_get_arg_opt % dic)
else:
out.write(tmpl_get_arg % dic)
def write_method_impl_check_args(meth, out):
if not meth.params:
out.write(tmpl_check_no_args)
elif meth.kwargs:
pass
elif meth.varargs:
out.write(tmpl_check_no_kwargs)
else:
out.write(tmpl_check_no_kwargs)
i = 0
for p in meth.params:
write_check_arg(meth, p, i, out)
i += 1
def write_wrap_retval(meth, out):
if meth.retval is None:
return
out.write('return ')
wrap_func = None
if isinstance(meth.retval.type, parser.Class):
wrap_func = 'wrap_object'
else:
funcs = {
'bool': 'wrap_bool',
'string': 'wrap_string',
'variant': 'wrap_variant',
'list': 'wrap_array',
'int': 'wrap_int',
'index': 'wrap_index',
}
wrap_func = funcs[meth.retval.type.name]
out.write(wrap_func)
out.write('(')
def write_method_impl_call_func(meth, out):
out.write(' ')
write_wrap_retval(meth, out)
out.write(meth.name + '(')
if meth.params:
if meth.kwargs:
out.write('args')
elif meth.varargs:
out.write('args.pos')
else:
out.write(', '.join(['arg%d' % (i,) for i in range(len(meth.params))]))
out.write(')')
if meth.retval is not None:
out.write(')')
out.write(';\n')
if meth.retval is None:
out.write(' return Variant();\n')
def write_method_impl(cls, meth, out):
meth_dic = make_method_dict(meth, cls)
out.write(tmpl_method_impl_start % meth_dic)
write_method_impl_check_args(meth, out)
write_method_impl_call_func(meth, out)
out.write(tmpl_method_impl_end % meth_dic)
out.write('\n')
def write_module_impl(out, mod):
out.write(tmpl_impl_file_start)
classes = mod.classes.values()
for cls in classes:
dic = make_class_dict(cls)
out.write(tmpl_impl_object_defn % dic)
out.write('\n')
for cls in classes:
write_class_init(cls, out)
out.write('\n')
for cls in classes:
for meth in cls.methods.values():
write_method_impl(cls, meth, out)
out.write(tmpl_impl_file_end)
def generate_file(filename, gen_func, *args):
tmp = tempfile.NamedTemporaryFile(dir=os.path.dirname(filename), delete=False)
try:
gen_func(tmp, *args)
tmp.close()
os.rename(tmp.name, filename)
finally:
if os.path.exists(tmp.name):
os.unlink(tmp.name)
def do_generate(input_file, decl_file, impl_file):
p = parser.Parser()
mod = p.parse(input_file)
generate_file(decl_file, write_module_decl, mod)
generate_file(impl_file, write_module_impl, mod)
if __name__ == '__main__':
from optparse import OptionParser
op = OptionParser()
op.add_option("--input", dest="input", help="read classes description from FILE", metavar="FILE")
op.add_option("--decl", dest="decl", help="write declarations to DECL", metavar="DECL")
op.add_option("--impl", dest="impl", help="write implementation to IMPL", metavar="IMPL")
opts, args = op.parse_args()
if args:
op.error("too many arguments")
do_generate(opts.input, opts.decl, opts.impl)