summaryrefslogtreecommitdiff
path: root/runtime/utils.py
blob: d1a30ee4b4a758ea3448c15ee79e63fe1d461e1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
"""Assorted helper functions for the TSRuntime."""
import hashlib

def freezedict(dictionary):
    """Freezes a dict to a hashable form, e.g. to store in a set."""
    return tuple(sorted(dictionary.items()))

def thawdict(dictionary):
    """Thaws a previously-frozen dict."""
    return dict(dictionary)

def is_empty(generator):
    """True iff the generator is empty.

    Used primarily to check if there are any satisfying assignments to a
    pattern, eg. in production_rule.py.
    """
    try:
        next(generator)
        return False
    except StopIteration:
        return True

class Translator:
    """Helper class for translation dictionaries.

    Useful, eg., when you want to translate between a set of constraints (using
    variable names) and ``filled-in'' constraints according to some assignment.
    """
    def __init__(self, translation):
        """Initializes the Translator.

        @translation should be a dictionary.
        """
        self.translation = translation

    def translate(self, element):
        """Returns the translation of @element (or @element if no translation).
        """
        return self.translation.get(element, element)

    def translate_tuple(self, elements):
        """Translates all elements of tuple @elements in @self.translation."""
        return tuple(map(self.translate, elements))

    def translate_tuples(self, elements):
        """Translates a list of tuples."""
        return list(map(self.translate_tuple, elements))

    def translate_list(self, elements):
        """Translates each member of a list."""
        return list(map(self.translate, elements))

    def compose(self, after, default_identity=False):
        """Returns the composition of @self.translation with the dict @after.

        Used eg. when we have an assignment to _variables_ that we want to turn
        in to an assignment to _nodes_ using a node-to-variable map.
        """
        composed = dict()
        for key, value in self.translation.items():
            try:
                composed[key] = after[value]
            except KeyError:
                if default_identity:
                    composed[key] = value
        return composed

    def concatenated_with(self, other):
        """Returns the concatenation of @self.translation and @after."""
        concatenated = self.translation.copy()
        concatenated.update(other)
        return concatenated

def real_hash(item):
    """Returns a "cryptographically-secure-ish" hash of @item.

    This is used in particular in assignment.py for giving newly-created nodes
    unambiguous, reproducible names based only on their 'source' assignment.
    """
    if isinstance(item, str):
        return hashlib.sha224(item.encode()).hexdigest()
    if isinstance(item, dict):
        # NOTE: this assumes that the str(...) does not include any
        # non-deterministic information (eg. ids). Maybe it would be best to
        # let real_hash operate directly on the sorted list.
        return real_hash(str(sorted(item.items())))
    raise NotImplementedError
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback