Eolian: Initial code for generating enums
This commit is contained in:
parent
0fa41e652d
commit
e62205769f
|
@ -4,6 +4,8 @@ import os
|
|||
import textwrap
|
||||
import keyword
|
||||
|
||||
from collections import Counter
|
||||
|
||||
from argparse import ArgumentParser
|
||||
parser = ArgumentParser(description="Python generator for eolian")
|
||||
# parser.add_argument(
|
||||
|
@ -32,6 +34,11 @@ eolian.init()
|
|||
DOCSTRINGS_ENABLED = True
|
||||
|
||||
import re
|
||||
|
||||
enum_re = re.compile(r"typedef\s+enum\s*{([^}]*)}([^;]+);")
|
||||
memb_re = re.compile(
|
||||
r"\n +(?P<value>\w+)[(), =<\d\-+]*([/*<]* (?P<comment>[^/]+)? ?\*/)?")
|
||||
|
||||
docstring_replacements = (
|
||||
("@brief ", ""),
|
||||
(re.compile(r"@ingroup .+", re.S), r""),
|
||||
|
@ -79,6 +86,9 @@ return_type_mapping = {
|
|||
"Eo *": ("_Eo_Base", 'object_from_instance({0})'),
|
||||
}
|
||||
|
||||
anon_enums = [] # (filename, enum_members), ...
|
||||
enums = {} # enum_name: (filename, enum_members), ...
|
||||
|
||||
|
||||
def conv_cls_name(name):
|
||||
s = name.split("_")
|
||||
|
@ -147,6 +157,17 @@ class Generator(object):
|
|||
def printout(self):
|
||||
return "\n".join(self.result)
|
||||
|
||||
def write_enum(self, name):
|
||||
filename, members = enums[name]
|
||||
self.write("from efl.utils.enum import IntEnum")
|
||||
self.write("# File: " + filename)
|
||||
self.write("class %s(IntEnum):" % (name))
|
||||
self.indent()
|
||||
for value, comment in members:
|
||||
self.write("%s # %s" % (value, comment))
|
||||
self.dedent()
|
||||
self.write()
|
||||
|
||||
|
||||
class PyxGenerator(Generator):
|
||||
def method_header_write(self, name, params, clsm=False):
|
||||
|
@ -195,6 +216,7 @@ class Method(object):
|
|||
self.cdefs = []
|
||||
self.returns = []
|
||||
self.docs = []
|
||||
self.enum_types = []
|
||||
self.ret_type = None
|
||||
self.py_name = None
|
||||
self.eo_prefix = eo_prefix
|
||||
|
@ -227,7 +249,11 @@ class Method(object):
|
|||
pdir, ptype, name, desc = p.information
|
||||
ptype2 = ptype.replace("const ", "").replace("unsigned ", "")
|
||||
if not ptype2 in param_type_mapping:
|
||||
raise TypeError("Unknown param type: %s" % (ptype2))
|
||||
if not ptype2 in enums:
|
||||
raise TypeError("Unknown param type: %s" % (ptype2))
|
||||
else:
|
||||
self.enum_types.append(ptype2)
|
||||
enums_counter[ptype2] += 1
|
||||
self.params.append((ptype, name))
|
||||
if pdir == eolian.ParameterDir.IN:
|
||||
self.py_params.append((ptype, name))
|
||||
|
@ -247,7 +273,11 @@ class Method(object):
|
|||
if ret_type:
|
||||
ret_type2 = ret_type.replace("const ", "").replace("unsigned ", "")
|
||||
if not ret_type2 in return_type_mapping:
|
||||
raise TypeError("Unknown return type: %s" % (ret_type2))
|
||||
if not ret_type2 in enums:
|
||||
raise TypeError("Unknown return type: %s" % (ret_type2))
|
||||
else:
|
||||
self.enum_types.append(ret_type2)
|
||||
enums_counter[ret_type2] += 1
|
||||
self.ret_type = ret_type
|
||||
ret_desc = func.return_comment_get(func.type)
|
||||
|
||||
|
@ -352,6 +382,7 @@ class Property(object):
|
|||
super(type(self), self).__init__()
|
||||
self.docs = []
|
||||
self.eo_prefix = eo_prefix
|
||||
self.enum_types = []
|
||||
|
||||
@classmethod
|
||||
def parse(cls, func, eo_prefix):
|
||||
|
@ -394,7 +425,11 @@ class Property(object):
|
|||
assert pdir == eolian.ParameterDir.IN, "prop has other than IN"
|
||||
ptype2 = ptype.replace("const ", "").replace("unsigned ", "")
|
||||
if not ptype2 in param_type_mapping:
|
||||
raise TypeError("Unknown param type: %s" % (ptype2))
|
||||
if not ptype2 in enums:
|
||||
raise TypeError("Unknown param type: %s" % (ptype2))
|
||||
else:
|
||||
self.enum_types.append(ptype2)
|
||||
enums_counter[ptype2] += 1
|
||||
m.params.append((ptype, name))
|
||||
py_params.append(name)
|
||||
m.c_params.append((ptype, name))
|
||||
|
@ -412,7 +447,12 @@ class Property(object):
|
|||
ret_type2 = m.ret_type.replace(
|
||||
"const ", "").replace("unsigned ", "")
|
||||
if not ret_type2 in return_type_mapping:
|
||||
raise TypeError("Unknown return type: %s" % (ret_type2))
|
||||
if not ret_type2 in enums:
|
||||
raise TypeError(
|
||||
"Unknown return type: %s" % (ret_type2))
|
||||
else:
|
||||
self.enum_types.append(ret_type2)
|
||||
enums_counter[ret_type2] += 1
|
||||
|
||||
if func.type == eolian.FunctionType.PROP_GET or \
|
||||
func.type == eolian.FunctionType.PROPERTY:
|
||||
|
@ -425,7 +465,11 @@ class Property(object):
|
|||
assert pdir == eolian.ParameterDir.IN, "prop has other than IN"
|
||||
ptype2 = ptype.replace("const ", "").replace("unsigned ", "")
|
||||
if not ptype2 in param_type_mapping:
|
||||
raise TypeError("Unknown param type: %s" % (ptype2))
|
||||
if not ptype2 in enums:
|
||||
raise TypeError("Unknown param type: %s" % (ptype2))
|
||||
else:
|
||||
self.enum_types.append(ptype2)
|
||||
enums_counter[ptype2] += 1
|
||||
m.params.append((ptype, name))
|
||||
m.cdefs.append((ptype, name))
|
||||
m.c_params.append((ptype, "&%s" % (name)))
|
||||
|
@ -436,11 +480,20 @@ class Property(object):
|
|||
ret_type2 = m.ret_type.replace(
|
||||
"const ", "").replace("unsigned ", "")
|
||||
if not ret_type2 in return_type_mapping:
|
||||
raise TypeError("Unknown return type: %s" % (ret_type2))
|
||||
if not ret_type2 in enums:
|
||||
raise TypeError(
|
||||
"Unknown return type: %s" % (ret_type2))
|
||||
else:
|
||||
self.enum_types.append(ret_type2)
|
||||
enums_counter[ret_type2] += 1
|
||||
|
||||
return self
|
||||
|
||||
def pyx_generate(self, gen):
|
||||
if self.enum_types:
|
||||
for t in set(self.enum_types):
|
||||
gen.write_enum(t)
|
||||
|
||||
gen.write("property %s:" % (self.name))
|
||||
|
||||
gen.indent()
|
||||
|
@ -583,8 +636,9 @@ class Class(object):
|
|||
for ctor in ctors:
|
||||
try:
|
||||
o = Constructor.parse(ctor, prefix)
|
||||
except Exception:
|
||||
log.exception(
|
||||
except Exception as e:
|
||||
log.warn(e)
|
||||
log.info(
|
||||
"Skipping %s.%s because of an exception"
|
||||
% (cls.name, ctor.name))
|
||||
continue
|
||||
|
@ -595,8 +649,9 @@ class Class(object):
|
|||
for prop in props:
|
||||
try:
|
||||
o = Property.parse(prop, prefix)
|
||||
except Exception:
|
||||
log.exception(
|
||||
except Exception as e:
|
||||
log.warn(e)
|
||||
log.info(
|
||||
"Skipping %s.%s because of an exception"
|
||||
% (cls.name, prop.name))
|
||||
continue
|
||||
|
@ -606,8 +661,9 @@ class Class(object):
|
|||
for method in methods:
|
||||
try:
|
||||
o = Method.parse(method, prefix)
|
||||
except Exception:
|
||||
log.exception(
|
||||
except Exception as e:
|
||||
log.warn(e)
|
||||
log.info(
|
||||
"Skipping %s.%s because of an exception"
|
||||
% (cls.name, method.name))
|
||||
continue
|
||||
|
@ -705,42 +761,77 @@ py_path = os.path.join(args.output, "__init__" + ".py")
|
|||
if os.path.exists(py_path):
|
||||
os.remove(py_path)
|
||||
|
||||
|
||||
for path in args.paths:
|
||||
for dirpath, dirnames, filenames in os.walk(path):
|
||||
eolian.directory_scan(dirpath)
|
||||
eolian.all_eo_files_parse()
|
||||
for filename in filenames:
|
||||
if filename.endswith(".eo"):
|
||||
f = os.path.join(dirpath, filename)
|
||||
if not eolian.eo_file_parse(f):
|
||||
log.warn("Errors in parsing %s" % (f))
|
||||
cls = eolian.class_find_by_file(f)
|
||||
try:
|
||||
gencls = Class.parse(cls)
|
||||
except Exception:
|
||||
log.exception(
|
||||
"Skipping %s because of an exception" % (cls.name))
|
||||
continue
|
||||
if filename.endswith(".h"):
|
||||
with open(os.path.join(dirpath, filename), "r") as h:
|
||||
s = h.read()
|
||||
matches = re.finditer(enum_re, s)
|
||||
for m in matches:
|
||||
name = m.group(2)
|
||||
members = m.group(1)
|
||||
log.debug("==== %s ====" % (name))
|
||||
log.debug("--- RAW ---")
|
||||
log.debug(members)
|
||||
members = re.finditer(memb_re, members)
|
||||
members2 = []
|
||||
log.debug("--- REGEXED ---")
|
||||
for match in members:
|
||||
value = match.group("value")
|
||||
comment = match.group("comment")
|
||||
if comment:
|
||||
comment2 = []
|
||||
for line in comment.splitlines():
|
||||
comment2.append(line.strip())
|
||||
comment = " ".join(comment2)
|
||||
log.debug(value, comment)
|
||||
members2.append((value, comment))
|
||||
if name:
|
||||
name = name.strip("_ ")
|
||||
enums[name] = (filename, members2)
|
||||
else:
|
||||
anon_enums.append((filename, members2))
|
||||
|
||||
pyxgen = PyxGenerator()
|
||||
gencls.pyx_generate(pyxgen)
|
||||
enums_counter = Counter(enums.keys())
|
||||
|
||||
f_base = os.path.splitext(filename)[0]
|
||||
pxi_path = os.path.join(args.output, f_base + ".pxi")
|
||||
o = pyxgen.printout()
|
||||
if o:
|
||||
with open(pxi_path, "w") as f:
|
||||
f.write(o.encode("utf-8"))
|
||||
log.info(pxi_path + " written")
|
||||
with open(py_path, "a") as py_f:
|
||||
for path in args.paths:
|
||||
for dirpath, dirnames, filenames in os.walk(path):
|
||||
eolian.directory_scan(dirpath)
|
||||
eolian.all_eo_files_parse()
|
||||
for filename in filenames:
|
||||
if filename.endswith(".eo"):
|
||||
f = os.path.join(dirpath, filename)
|
||||
if not eolian.eo_file_parse(f):
|
||||
log.warn("Errors in parsing %s" % (f))
|
||||
cls = eolian.class_find_by_file(f)
|
||||
try:
|
||||
gencls = Class.parse(cls)
|
||||
except Exception:
|
||||
log.exception(
|
||||
"Skipping %s because of an exception" % (cls.name))
|
||||
continue
|
||||
|
||||
pygen = Generator()
|
||||
gencls.py_generate(pygen)
|
||||
pyxgen = PyxGenerator()
|
||||
gencls.pyx_generate(pyxgen)
|
||||
|
||||
o = pygen.printout()
|
||||
if o:
|
||||
with open(py_path, "a") as f:
|
||||
f.write(o.encode("utf-8"))
|
||||
f.write("\n")
|
||||
log.info(py_path + " appended")
|
||||
f_base = os.path.splitext(filename)[0]
|
||||
pxi_path = os.path.join(args.output, f_base + ".pxi")
|
||||
o = pyxgen.printout()
|
||||
if o:
|
||||
with open(pxi_path, "w") as f:
|
||||
f.write(o.encode("utf-8"))
|
||||
log.info(pxi_path + " written")
|
||||
|
||||
pygen = Generator()
|
||||
gencls.py_generate(pygen)
|
||||
|
||||
o = pygen.printout()
|
||||
if o:
|
||||
py_f.write(o.encode("utf-8"))
|
||||
py_f.write("\n")
|
||||
log.info(py_path + " appended")
|
||||
|
||||
eolian.shutdown()
|
||||
|
|
Loading…
Reference in New Issue