From 79a04823186b5f1020a49a099f7dfebe6d5ef035 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Thu, 3 May 2012 23:39:40 -0700 Subject: [PATCH] Implement reverse mapping of values to names This adds a bit of dumb mapping of values to names, while trying to be safe. This is the best we can do without resorting to parsing or interpreting ASTs. The difference in the output is: -- | Converted from Python list or set ADMINST_ALL adminstAll :: [String] -adminstAll = ["down", "offline", "up"] +adminstAll = [adminstDown, adminstOffline, adminstUp] Since for most such values we use strings, we don't gain in type safety on the Haskell side. But it makes the output more readable and it might open up other opportunities later. Signed-off-by: Iustin Pop <iustin@google.com> Reviewed-by: Michael Hanselmann <hansmi@google.com> --- autotools/convert-constants | 59 ++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/autotools/convert-constants b/autotools/convert-constants index cfac4121d..dbf0b13a4 100755 --- a/autotools/convert-constants +++ b/autotools/convert-constants @@ -84,13 +84,54 @@ def HaskellTypeVal(value): return None -def ConvertVariable(prefix, name, value): +def IdentifyOrigin(all_items, value): + """Tries to identify a constant name from a constant's value. + + This uses a simple algorithm: is there a constant (and only one) + with the same value? If so, then it returns that constants' name. + + @note: it is recommended to use this only for tuples/lists/sets, and + not for individual (top-level) values + @param all_items: a dictionary of name/values for the current module + @param value: the value for which we try to find an origin + + """ + found = [name for (name, v) in all_items.items() if v is value] + if len(found) == 1: + return found[0] + else: + return None + + +def FormatListElems(all_items, pfx_name, ovals, tvals): + """Formats a list's elements. + + This formats the elements as either values or, if we find all + origins, as names. + + @param all_items: a dictionary of name/values for the current module + @param pfx_name: the prefix name currently used + @param ovals: the list of actual (Python) values + @param tvals: the list of values we want to format in the Haskell form + + """ + origins = [IdentifyOrigin(all_items, v) for v in ovals] + if compat.all(x is not None for x in origins): + values = [NameRules(pfx_name + origin) for origin in origins] + else: + values = tvals + return ", ".join(values) + + +def ConvertVariable(prefix, name, value, all_items): """Converts a given variable to Haskell code. @param prefix: a prefix for the Haskell name (useful for module identification) @param name: the Python name @param value: the value + @param all_items: a dictionary of name/value for the module being + processed @return: a list of Haskell code lines """ @@ -121,12 +162,13 @@ def ConvertVariable(prefix, name, value): if value: lines.append("-- Following lines come from dictionary %s" % fqn) for k in sorted(value.keys()): - lines.extend(ConvertVariable(prefix, DictKeyName(name, k), value[k])) + lines.extend(ConvertVariable(prefix, DictKeyName(name, k), + value[k], all_items)) elif isinstance(value, tuple): tvs = [HaskellTypeVal(elem) for elem in value] if compat.all(e is not None for e in tvs): ttypes = ", ".join(e[0] for e in tvs) - tvals = ", ".join(e[1] for e in tvs) + tvals = FormatListElems(all_items, pfx_name, value, [e[1] for e in tvs]) lines.append("-- | Converted from Python tuple %s" % fqn) lines.append("%s :: (%s)" % (hs_name, ttypes)) lines.append("%s = (%s)" % (hs_name, tvals)) @@ -145,9 +187,10 @@ def ConvertVariable(prefix, name, value): ttypes, tvals = zip(*tvs) uniq_types = set(ttypes) if len(uniq_types) == 1: + values = FormatListElems(all_items, pfx_name, value, tvals) lines.append("-- | Converted from Python list or set %s" % fqn) lines.append("%s :: [%s]" % (hs_name, uniq_types.pop())) - lines.append("%s = [%s]" % (hs_name, ", ".join(tvals))) + lines.append("%s = [%s]" % (hs_name, values)) else: lines.append("-- | Skipped list/set %s, is not homogeneous" % fqn) else: @@ -169,11 +212,11 @@ def Convert(module, prefix): """ lines = [""] - all_names = dir(module) + all_items = dict((name, getattr(module, name)) for name in dir(module)) - for name in all_names: - value = getattr(module, name) - new_lines = ConvertVariable(prefix, name, value) + for name in sorted(all_items.keys()): + value = all_items[name] + new_lines = ConvertVariable(prefix, name, value, all_items) if new_lines: lines.extend(new_lines) lines.append("") -- GitLab