From 8c957eb3f12ce21b4781f39210c171e7fa6bc44e Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Sat, 25 Aug 2012 00:04:27 +0200 Subject: [PATCH] Extend convert-constants support for dicts This enhances convert-constants to not flatten dicts completely, but also generate a so-called association list for them. This allows either direct use of the 'lookup' function, or (for performance) conversion to Data.Map and optimised lookup later. Signed-off-by: Iustin Pop <iustin@google.com> Reviewed-by: Agata Murawska <agatamurawska@google.com> --- autotools/convert-constants | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/autotools/convert-constants b/autotools/convert-constants index 043d32ce8..e051821e6 100755 --- a/autotools/convert-constants +++ b/autotools/convert-constants @@ -131,6 +131,55 @@ def FormatListElems(all_items, pfx_name, ovals, tvals): return ", ".join(values) +def FormatDict(all_items, pfx_name, py_name, hs_name, mydict): + """Converts a dictionary to a Haskell association list ([(k, v)]), + if possible. + + @param all_items: a dictionary of name/values for the current module + @param pfx_name: the prefix name currently used + @param py_name: the Python name + @param hs_name: the Haskell name + @param mydict: a dictonary, unknown yet if homogenous or not + + """ + # need this for ordering + orig_list = mydict.items() + list_form = [(HaskellTypeVal(k), HaskellTypeVal(v)) for k, v in orig_list] + if compat.any(v is None or k is None for k, v in list_form): + # type not known + return [] + all_keys = [k for k, _ in list_form] + all_vals = [v for _, v in list_form] + key_types = set(k[0] for k in all_keys) + val_types = set(v[0] for v in all_vals) + if not(len(key_types) == 1 and len(val_types) == 1): + # multiple types + return [] + # record the key and value Haskell types + key_type = key_types.pop() + val_type = val_types.pop() + + # now try to find names for the keys, instead of raw values + key_origins = [IdentifyOrigin(all_items, k) for k, _ in orig_list] + if compat.all(x is not None for x in key_origins): + key_v = [NameRules(pfx_name + origin) for origin in key_origins] + else: + key_v = [k[1] for k in all_keys] + # ... and for values + val_origins = [IdentifyOrigin(all_items, v) for _, v in orig_list] + if compat.all(x is not None for x in val_origins): + val_v = [NameRules(pfx_name + origin) for origin in val_origins] + else: + val_v = [v[1] for v in all_vals] + + # finally generate the output + kv_pairs = ["(%s, %s)" % (k, v) for k, v in zip(key_v, val_v)] + return ["-- | Converted from Python dictionary %s" % py_name, + "%s :: [(%s, %s)]" % (hs_name, key_type, val_type), + "%s = [%s]" % (hs_name, ", ".join(kv_pairs)), + ] + + def ConvertVariable(prefix, name, value, all_items): """Converts a given variable to Haskell code. @@ -169,6 +218,10 @@ def ConvertVariable(prefix, name, value, all_items): elif isinstance(value, dict): if value: lines.append("-- Following lines come from dictionary %s" % fqn) + # try to build a real map here, if all keys have same type, and + # all values too (i.e. we have a homogeneous dictionary) + lines.extend(FormatDict(all_items, pfx_name, fqn, hs_name, value)) + # and now create individual names for k in sorted(value.keys()): lines.extend(ConvertVariable(prefix, DictKeyName(name, k), value[k], all_items)) -- GitLab