forked from enlightenment/efl
218 lines
8.3 KiB
Python
Executable File
218 lines
8.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# encoding: utf-8
|
|
"""
|
|
|
|
Pyolian template based generator.
|
|
|
|
This is a really powerfull template-based, output-agnostic eolian generator.
|
|
You just need a template file and then you can render it with the
|
|
wanted eolian scope (class, namespace, enum, struct, etc...).
|
|
|
|
For example (from this source folder):
|
|
|
|
./generator.py test_gen_class.template --cls Efl.Loop.Timer
|
|
./generator.py test_gen_namespace.template --ns Efl.Ui
|
|
|
|
...of course you can pass any other class or namespace to the example above.
|
|
|
|
The generator is based on the great pyratemp engine (THANKS!), you can find
|
|
the full template syntax at: www.simple-is-better.org/template/pyratemp.html
|
|
|
|
Just keep in mind the syntax is a bit different in this implementation:
|
|
|
|
sub_start = "${" Was "$!" in original pyratemp (and in docs)
|
|
sub_end = "}$" Was "!$" in original pyratemp (and in docs)
|
|
_block_start = "<!--("
|
|
_block_end = ")-->"
|
|
comment_start = "#!"
|
|
comment_end = "!#"
|
|
|
|
|
|
You can also import this module and use the provided Template class if you
|
|
are more confortable from within python. To import from outside this directory
|
|
you need to hack sys.path in a way that this folder will be available on
|
|
PYTHON_PATH, fe:
|
|
|
|
pyolian_path = os.path.join(EFL_ROOT_PATH, 'src', 'scripts')
|
|
sys.path.insert(0, pyolian_path)
|
|
from pyolian.generator import Template
|
|
|
|
|
|
"""
|
|
import os
|
|
import datetime
|
|
|
|
try:
|
|
from . import eolian
|
|
from . import pyratemp
|
|
except ImportError:
|
|
import eolian
|
|
import pyratemp
|
|
|
|
|
|
# Use .eo files from the source tree (not the installed ones)
|
|
script_path = os.path.dirname(os.path.realpath(__file__))
|
|
root_path = os.path.abspath(os.path.join(script_path, '..', '..', '..'))
|
|
SCAN_FOLDER = os.path.join(root_path, 'src', 'lib')
|
|
|
|
|
|
# load the whole eolian db
|
|
eolian_db = eolian.Eolian_State()
|
|
if not isinstance(eolian_db, eolian.Eolian_State):
|
|
raise(RuntimeError('Eolian, failed to create Eolian state'))
|
|
|
|
if not eolian_db.directory_add(SCAN_FOLDER):
|
|
raise(RuntimeError('Eolian, failed to scan source directory'))
|
|
|
|
if not eolian_db.all_eot_files_parse():
|
|
raise(RuntimeError('Eolian, failed to parse all EOT files'))
|
|
|
|
if not eolian_db.all_eo_files_parse():
|
|
raise(RuntimeError('Eolian, failed to parse all EO files'))
|
|
|
|
# cleanup the database on exit
|
|
import atexit
|
|
def cleanup_db():
|
|
global eolian_db
|
|
del eolian_db
|
|
atexit.register(cleanup_db)
|
|
|
|
|
|
class Template(pyratemp.Template):
|
|
""" Pyolian template based generator.
|
|
|
|
You can directly use this class to generate custom outputs based
|
|
on the eolian database and your provided templates.
|
|
|
|
Usage is as simple as:
|
|
t = Template(<template_file>)
|
|
t.render(<output_file>, cls=..., ns=..., ...)
|
|
|
|
Args:
|
|
filename: Template file to load. (REQUIRED)
|
|
context: User provided context for the template (dict).
|
|
"""
|
|
def __init__(self, filename, encoding='utf-8', context=None, escape=None,
|
|
loader_class=pyratemp.LoaderFile,
|
|
parser_class=pyratemp.Parser,
|
|
renderer_class=pyratemp.Renderer,
|
|
eval_class=pyratemp.EvalPseudoSandbox):
|
|
|
|
# Build the global context for the template
|
|
global_ctx = {}
|
|
# user provided context (low pri)
|
|
if context:
|
|
global_ctx.update(context)
|
|
# standard names (not overwritables)
|
|
global_ctx.update({
|
|
# Template info
|
|
'date': datetime.datetime.now(),
|
|
'template_file': os.path.basename(filename),
|
|
# Eolian info
|
|
# 'eolian_version': eolian.__version__,
|
|
# 'eolian_version_info': eolian.__version_info__,
|
|
# Eolian Classes
|
|
'Object': eolian.Object,
|
|
'Class': eolian.Class,
|
|
'Part': eolian.Part,
|
|
'Constructor': eolian.Constructor,
|
|
'Event': eolian.Event,
|
|
'Function': eolian.Function,
|
|
'Function_Parameter': eolian.Function_Parameter,
|
|
'Implement': eolian.Implement,
|
|
'Type': eolian.Type,
|
|
'Typedecl': eolian.Typedecl,
|
|
'Enum_Type_Field': eolian.Enum_Type_Field,
|
|
'Struct_Type_Field': eolian.Struct_Type_Field,
|
|
'Expression': eolian.Expression,
|
|
'Variable': eolian.Variable,
|
|
'Documentation': eolian.Documentation,
|
|
'Documentation_Token': eolian.Documentation_Token,
|
|
# Eolian Enums
|
|
'Eolian_Function_Type': eolian.Eolian_Function_Type,
|
|
'Eolian_Parameter_Dir': eolian.Eolian_Parameter_Dir,
|
|
'Eolian_Class_Type': eolian.Eolian_Class_Type,
|
|
'Eolian_Object_Scope': eolian.Eolian_Object_Scope,
|
|
'Eolian_Typedecl_Type': eolian.Eolian_Typedecl_Type,
|
|
'Eolian_Type_Type': eolian.Eolian_Type_Type,
|
|
'Eolian_Type_Builtin_Type': eolian.Eolian_Type_Builtin_Type,
|
|
'Eolian_C_Type_Type': eolian.Eolian_C_Type_Type,
|
|
'Eolian_Expression_Type': eolian.Eolian_Expression_Type,
|
|
'Eolian_Expression_Mask': eolian.Eolian_Expression_Mask,
|
|
'Eolian_Variable_Type': eolian.Eolian_Variable_Type,
|
|
'Eolian_Binary_Operator': eolian.Eolian_Binary_Operator,
|
|
'Eolian_Unary_Operator': eolian.Eolian_Unary_Operator,
|
|
'Eolian_Doc_Token_Type': eolian.Eolian_Doc_Token_Type,
|
|
})
|
|
|
|
# Call the parent __init__ func
|
|
self.template_filename = filename
|
|
pyratemp.Template.__init__(self, filename=filename, encoding=encoding,
|
|
data=global_ctx, escape=escape,
|
|
loader_class=loader_class,
|
|
parser_class=parser_class,
|
|
renderer_class=renderer_class,
|
|
eval_class=eval_class)
|
|
|
|
def render(self, filename=None, verbose=True, cls=None, ns=None,
|
|
struct=None, enum=None, alias=None, **kargs):
|
|
# Build the context for the template
|
|
ctx = {}
|
|
if kargs:
|
|
ctx.update(kargs)
|
|
if cls:
|
|
ctx['cls'] = eolian_db.class_by_name_get(cls)
|
|
if ns:
|
|
ctx['namespace'] = eolian_db.namespace_get_by_name(ns)
|
|
if struct:
|
|
ctx['struct'] = eolian_db.struct_by_name_get(struct)
|
|
if enum:
|
|
ctx['enum'] = eolian_db.enum_by_name_get(enum)
|
|
if alias:
|
|
ctx['alias'] = eolian_db.alias_by_name_get(alias)
|
|
|
|
if verbose and filename:
|
|
print("rendering: {} => {}".format(
|
|
self.template_filename, filename))
|
|
|
|
# render with the augmented context
|
|
output = self(**ctx)
|
|
|
|
if filename is not None:
|
|
# create directory tree if needed
|
|
folder = os.path.dirname(filename)
|
|
if folder and not os.path.isdir(folder):
|
|
os.makedirs(folder)
|
|
# write to file
|
|
with open(filename, "w") as f:
|
|
f.write(output)
|
|
else:
|
|
# or print to stdout
|
|
print(output)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(description='Pyolian template based generator.')
|
|
parser.add_argument('template',
|
|
help='The template file to use. (REQUIRED)')
|
|
parser.add_argument('--output', '-o', metavar='FILE', default=None,
|
|
help='Where to write the rendered output. '
|
|
'If not given will print to stdout.')
|
|
parser.add_argument('--cls', metavar='CLASS_NAME', default=None,
|
|
help='The full name of the class to render, ex: Efl.Loop.Timer')
|
|
parser.add_argument('--ns', metavar='NAMESPACE', default=None,
|
|
help='The namespace to render, ex: Efl.Loop')
|
|
parser.add_argument('--struct', metavar='STRUCT_NAME', default=None,
|
|
help='The name of the struct to render, ex: Efl.Loop.Arguments')
|
|
parser.add_argument('--enum', metavar='ENUM_NAME', default=None,
|
|
help='The name of the enum to render, ex: Efl.Loop.Handler.Flags')
|
|
parser.add_argument('--alias', metavar='ALIAS_NAME', default=None,
|
|
help='The name of the alias to render, ex: Efl.Font.Size')
|
|
args = parser.parse_args()
|
|
|
|
t = Template(args.template)
|
|
t.render(args.output, cls=args.cls, ns=args.ns,
|
|
struct=args.struct, enum=args.enum, alias=args.alias)
|