The two main drawbacks for convert-constants are the fact that it can't handle sets/frozensets (mainly due to the fact that I don't know how useful this would be to the Haskell code) and that it cannot export dictionaries.
To fix the second case, the current patch changes the code to support flattening (potentially nested) dictionaries into single name space. Yes, this could generate conflicts, but they will be detected at compile time. --- autotools/convert-constants | 70 +++++++++++++++++++++++++++++------------- 1 files changed, 48 insertions(+), 22 deletions(-) diff --git a/autotools/convert-constants b/autotools/convert-constants index 3f2b362..8dd1a11 100755 --- a/autotools/convert-constants +++ b/autotools/convert-constants @@ -26,13 +26,14 @@ import re from ganeti import constants -CONSTANT_RE = re.compile("^[A-Z][A-Z0-9_]+$") +CONSTANT_RE = re.compile("^[A-Z][A-Z0-9_-]+$") def NameRules(name): """Converts the upper-cased Python name to Haskell camelCase. """ + name = name.replace("-", "_") elems = name.split("_") return elems[0].lower() + "".join(e.capitalize() for e in elems[1:]) @@ -46,6 +47,51 @@ def StringValueRules(value): return value +def DictKeyName(dict_name, key_name): + """Converts a dict plus key name to a full name. + + """ + return"%s_%s" % (dict_name, str(key_name).upper()) + + +def ConvertVariable(name, value): + """Converts a given variable to Haskell code. + + @param name: the Python name + @param value: the value + @return: a list of Haskell code lines + + """ + lines = [] + hs_name = NameRules(name) + if not CONSTANT_RE.match(name): + lines.append("-- Skipped %s, not constant" % name) + elif isinstance(value, basestring): + lines.append("-- | Converted from Python constant %s" % name) + lines.append("%s :: String" % hs_name) + lines.append("%s = \"%s\"" % (hs_name, StringValueRules(value))) + elif isinstance(value, int): + lines.append("-- | Converted from Python constant %s" % name) + lines.append("%s :: Int" % hs_name) + lines.append("%s = %d" % (hs_name, value)) + elif isinstance(value, long): + lines.append("-- | Converted from Python constant %s" % name) + lines.append("%s :: Integer" % hs_name) + lines.append("%s = %d" % (hs_name, value)) + elif isinstance(value, float): + lines.append("-- | Converted from Python constant %s" % name) + lines.append("%s :: Double" % hs_name) + lines.append("%s = %f" % (hs_name, value)) + elif isinstance(value, dict): + if value: + lines.append("-- Following lines come from dictionary %s" % name) + for k in sorted(value.keys()): + lines.extend(ConvertVariable(DictKeyName(name, k), value[k])) + else: + lines.append("-- Skipped %s, %s not handled" % (name, type(value))) + return lines + + def Convert(): """Converts the constants to Haskell. @@ -56,27 +102,7 @@ def Convert(): for name in all_names: value = getattr(constants, name) - hs_name = NameRules(name) - if not CONSTANT_RE.match(name): - lines.append("-- Skipped %s, not constant" % name) - elif isinstance(value, basestring): - lines.append("-- | Converted from Python constant %s" % name) - lines.append("%s :: String" % hs_name) - lines.append("%s = \"%s\"" % (hs_name, StringValueRules(value))) - elif isinstance(value, int): - lines.append("-- | Converted from Python constant %s" % name) - lines.append("%s :: Int" % hs_name) - lines.append("%s = %d" % (hs_name, value)) - elif isinstance(value, long): - lines.append("-- | Converted from Python constant %s" % name) - lines.append("%s :: Integer" % hs_name) - lines.append("%s = %d" % (hs_name, value)) - elif isinstance(value, float): - lines.append("-- | Converted from Python constant %s" % name) - lines.append("%s :: Double" % hs_name) - lines.append("%s = %f" % (hs_name, value)) - else: - lines.append("-- Skipped %s, %s not handled" % (name, type(value))) + lines.extend(ConvertVariable(name, value)) lines.append("") return "\n".join(lines) -- 1.7.3.1