Eolian: Initial code for generating enums

This commit is contained in:
Kai Huuhko 2014-06-22 20:29:36 +03:00
parent 0fa41e652d
commit e62205769f
1 changed files with 133 additions and 42 deletions

View File

@ -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()