Ejemplo n.º 1
0
class Map(Type):
    
    """Map type."""
    
    key = TypedField(Type)
    value = TypedField(Type)
    
    def __str__(self):
        return '{{{}: {}}}'.format(self.key, self.value)
    
    def smaller_cmp(self, other):
        if type(self) != type(other):
            return NotImplemented
        return (self.key.issmaller(other.key) and
                self.value.issmaller(other.value))
    
    def join_helper(self, other, *, inverted=False):
        top = Top if not inverted else Bottom
        if type(self) != type(other):
            return top
        new_key = self.key.join(other.key, inverted=inverted)
        new_value = self.value.join(other.value, inverted=inverted)
        return self._replace(key=new_key, value=new_value)
    
    def widen_helper(self, height):
        new_key = self.key.widen(height - 1)
        new_value = self.value.widen(height - 1)
        return self._replace(key=new_key, value=new_value)
Ejemplo n.º 2
0
class DictType(Type):
    kt = TypedField(Type)
    vt = TypedField(Type)

    # Contravariant key types were also considered as a possibility.
    # This would affect each of the helpers below.

    def __str__(self):
        return '{' + str(self.kt) + ': ' + str(self.vt) + '}'

    def issubtype_helper(self, other):
        if type(self) != type(other):
            return False
        return (self.kt.issubtype(other.kt) and self.vt.issubtype(other.vt))

    def join_helper(self, other, *, inverted=False):
        if type(self) != type(other):
            return toptype if not inverted else bottomtype
        new_kt = self.kt.join(other.kt, inverted=inverted)
        new_vt = self.vt.join(other.vt, inverted=inverted)
        return self._replace(kt=new_kt, vt=new_vt)

    def match_against_helper(self, other):
        return [(self.kt, self.kt), (other.vt, other.vt)]

    def expand(self, store):
        new_kt = self.kt.expand(store)
        new_vt = self.vt.expand(store)
        return self._replace(kt=new_kt, vt=new_vt)

    def widen_helper(self, limit):
        new_kt = self.kt.widen(limit - 1)
        new_vt = self.vt.widen(limit - 1)
        return self._replace(kt=new_kt, vt=new_vt)
Ejemplo n.º 3
0
class TClause_NoTC(TClause):
    """TClause without type checks in emitted code."""

    tup = TypedField(str)
    elts = TypedField(str, seq=True)

    typecheck = False
Ejemplo n.º 4
0
class SingletonClause(Clause, ABCStruct):
    """An enumerator over a singleton set, i.e., that binds its
    left-hand side to a single value.
    """

    kind = Clause.KIND_ENUM

    robust = False

    lhs = TypedField(str, seq=True)
    """Enumeration variables."""
    val = TypedField(L.expr)
    """Expression computing value of singleton element."""
    @classmethod
    def from_expr(cls, node):
        """Construct from a condition expression of form
        
            <vars> == <rel>
        """
        checktype(node, L.AST)

        left, op, val = L.get_cmp(node)
        checktype(op, L.Eq)
        lhs = L.get_vartuple(left)

        return cls(lhs, val)

    @classmethod
    def from_AST(cls, node, factory):
        """Construct from Enumerator node of form
        
            <vars> in {<expr>}
        """
        checktype(node, L.Enumerator)

        lhs = L.get_vartuple(node.target)
        val = L.get_singletonset(node.iter)

        return cls(lhs, val)

    def __init__(self, lhs, val):
        self.enumlhs = self.lhs
        self.enumrel = None
        self.vars = self.enumvars

    def to_AST(self):
        return L.Enumerator(L.tuplify(self.lhs, lval=True), L.Set(
            (self.val, )))

    def rate(self, bindenv):
        return Rate.CONSTANT

    def get_code(self, bindenv, body):
        mask = Mask.from_vars(self.lhs, bindenv)
        bvars, uvars, _eqs = mask.split_vars(self.lhs)
        return make_tuplematch(self.val, mask, bvars, uvars, body)
Ejemplo n.º 5
0
class IndefImgset(Cost):
    """Indefinite image set, i.e., the size of the largest image set
    under any key for a given relation and mask.
    """

    rel = TypedField(str)
    mask = TypedField(L.mask)

    def __str__(self):
        return '{}_{}'.format(self.rel, self.mask.m)
Ejemplo n.º 6
0
class Filter(Struct):
    _immutable = False

    i = TypedField(int)
    """Index of clause for which this filter is generated."""
    name = TypedField(str)
    """Name of this filter."""
    clause = TypedField(L.clause)
    """Clause that this filter is based on."""
    preds = TypedField(str, seq=True)
    """Names of predecessor tags for this filter."""
Ejemplo n.º 7
0
class Tag(Struct):
    _immutable = False

    i = TypedField(int)
    """Index of clause for which this tag is generated."""
    name = TypedField(str)
    """Name of this tag."""
    tag_var = TypedField(str)
    """Query variable controlled by this tag."""
    clause = TypedField(L.clause)
    """Clause that this tag projects."""
Ejemplo n.º 8
0
class WrapInvariant(Struct):
    """Wrap invariant."""

    rel = TypedField(str)
    """Name of variable holding the relation to be maintained."""
    oper = TypedField(str)
    """Name of variable holding the operand relation."""
    unwrap = TypedField(bool)
    """True for Unwrap, False for Wrap."""
    def get_maint_func_name(self, op):
        op_name = L.set_update_name(op)
        return N.get_maint_func_name(self.rel, self.oper, op_name)
Ejemplo n.º 9
0
class Task(Struct):
    """A single transformation task."""

    display_name = TypedField(str)
    """Display name for status printing."""
    input_name = TypedField(str)
    """Input filename."""
    output_name = Field()
    """Output filename, or None if no transformation."""
    nopts = Field()
    """Normal options."""
    qopts = Field()
    """Query options."""
Ejemplo n.º 10
0
class LookupClause(EnumClause, ABCStruct):
    """An enumerator over a singleton set of an SMLookup node.
    Basically acts like a normal EnumClause, but the forward
    direction takes constant time due to the functional
    dependency from keys to value.
    """

    lhs = TypedField(str, seq=True)
    """Enumeration variables."""
    rel = TypedField(str)
    """Name of iterated relation."""
    @classmethod
    def from_AST(cls, node, factory):
        """Construct from an Enumerator node of form
        
            var in {<rel>.smlookup(<mask>, <key vars>)}
        
        """
        checktype(node, L.Enumerator)

        var = L.get_name(node.target)
        sm = L.get_singletonset(node.iter)
        checktype(sm, L.SMLookup)
        rel = L.get_name(sm.target)
        mask = Mask(sm.mask)
        keyvars = L.get_vartuple(sm.key)
        # Ensure the mask is consistent with how it's used.
        if mask != Mask.from_keylen(len(keyvars)):
            raise TypeError

        lhs = keyvars + (var, )
        return cls(lhs, rel)

    def to_AST(self):
        mask = Mask.from_keylen(len(self.lhs) - 1)
        keyvars = self.lhs[:-1]
        var = self.lhs[-1]
        sm = L.SMLookup(L.ln(self.rel),
                        mask.make_node().s, L.tuplify(keyvars), None)
        return L.Enumerator(L.sn(var), L.Set((sm, )))

    def rewrite_subst(self, subst, factory):
        # The normal rewriting won't get the smlookup keys.
        new_lhs = apply_subst_tuple(self.lhs, subst)
        return self._replace(lhs=new_lhs)

    def rate(self, bindenv):
        mask = Mask.from_vars(self.lhs, bindenv)
        if mask.is_keymask:
            return Rate.CONSTANT
        return super().rate(bindenv)
Ejemplo n.º 11
0
class DefImgsetCost(Cost):
    rel = TypedField(str)
    mask = TypedField(Mask)
    key = TypedField(str, seq=True)
    
    def __str__(self):
        return '{}_{}[{}]'.format(self.rel, self.mask,
                                  ', '.join(self.key))
    
    def to_indef(self):
        """Return the indefinite image set cost that generalizes
        this cost.
        """
        return IndefImgsetCost(self.rel, self.mask)
Ejemplo n.º 12
0
class USet(Struct):
    kind = KIND_USET
    
    i = TypedField(int)
    """Index of query enumerator where the subquery is iterated over."""
    name = TypedField(str)
    """Name of associated demand name."""
    vars = TypedField(str, seq=True)
    """Vars that get passed to the demand functions as parameters."""
    preds = Field()
    """Names of predecessor tags, or None if using clauses."""
    pred_clauses = Field()
    """Predecessor clauses, or None if using tags."""
    reorder_i = TypedField(int)
    """Relative order for demand graph."""
Ejemplo n.º 13
0
class Sum(Cost):
    """Sum of a sequence of costs."""

    terms = TypedField(Cost, seq=True)

    def __str__(self):
        return '(' + ' + '.join(str(t) for t in self.terms) + ')'
Ejemplo n.º 14
0
class Sequence(Type):
    
    """Sequence of homogeneous elements. Covariant in element type."""
    
    elt = TypedField(Type)
    
    def __str__(self):
        return 'Seq<' + str(self.elt) + '>'
    
    def smaller_cmp(self, other):
        # Two Sequence-based types are comparable if they are of the
        # same Sequence subtype or if one of the types is a Sequence
        # proper. In either case it then comes down to the element type.
        if (type(self) != type(other) and
            type(other) != Sequence):
            return NotImplemented
        return self.elt.issmaller(other.elt)
    
    def join_helper(self, other, *, inverted=False):
        # The join of two distinct Sequence-based types is a Sequence
        # proper.
        top = Top if not inverted else Bottom
        if (type(self) != type(other) and
            not issubclass(type(other), Sequence)):
            return top
        new_elt = self.elt.join(other.elt, inverted=inverted)
        if type(self) == type(other):
            return self._replace(elt=new_elt)
        else:
            return Sequence(new_elt) if not inverted else Bottom 
    
    def widen_helper(self, height):
        new_elt = self.elt.widen(height - 1)
        return self._replace(elt=new_elt)
Ejemplo n.º 15
0
class SeqType(Type):
    et = TypedField(Type)
    brackets = '??'

    def __str__(self):
        return self.brackets[0] + str(self.et) + self.brackets[1]

    def issubtype_helper(self, other):
        if type(self) != type(other):
            return False
        return self.et.issubtype(other.et)

    def join_helper(self, other, inverted=False):
        if type(self) != type(other):
            return toptype if not inverted else bottomtype
        new_et = self.et.join(other.et, inverted=inverted)
        return self._replace(et=new_et)

    def match_against_helper(self, other):
        return [(self.et, other.et)]

    def expand(self, store):
        new_et = self.et.expand(store)
        return self._replace(et=new_et)

    def widen_helper(self, limit):
        new_et = self.et.widen(limit - 1)
        return self._replace(et=new_et)
Ejemplo n.º 16
0
class Min(Cost):
    """Minimum of a sequence of costs."""

    terms = TypedField(Cost, seq=True)

    def __str__(self):
        return 'min(' + ', '.join(str(t) for t in self.terms) + ')'
Ejemplo n.º 17
0
class Name(Cost):
    """Atomic cost, e.g. a domain size or a relation size."""

    name = TypedField(str)

    def __str__(self):
        return self.name
Ejemplo n.º 18
0
class Tuple(Type):
    
    """Tuple type. For tuples of the same arity, covariant in the
    component types.
    """
    
    elts = TypedField(Type, seq=True)
    
    def __str__(self):
        return '(' + ', '.join(str(e) for e in self.elts) + ')'
    
    def smaller_cmp(self, other):
        if type(self) != type(other):
            return NotImplemented
        if len(self.elts) != len(other.elts):
            return NotImplemented
        return all(e1.issmaller(e2)
                   for e1, e2 in zip(self.elts, other.elts))
    
    def join_helper(self, other, *, inverted=False):
        top = Top if not inverted else Bottom
        if type(self) != type(other):
            return top
        if len(self.elts) != len(other.elts):
            return top
        new_elts = [e1.join(e2, inverted=inverted)
                    for e1, e2 in zip(self.elts, other.elts)]
        return self._replace(elts=new_elts)
    
    def widen_helper(self, height):
        new_elts = [e.widen(height - 1) for e in self.elts]
        return self._replace(elts=new_elts)
Ejemplo n.º 19
0
class IncAggr(Struct):
    """Info for incrementalizing an aggregate query."""

    aggr = TypedField(L.Aggregate)
    """Aggregate node."""
    spec = TypedField(AggrSpec)
    """Aggregate query info."""
    name = TypedField(str)
    """Result set name."""
    demname = Field()
    """Aggregate demand name, or None if not using demand."""
    uset_lru = Field()
    """None or an integer bound for LRU cache size."""
    half_demand = TypedField(bool)
    """If using demand and this is True, use the "half-demand"
    strategy.
    """
    @property
    def has_demand(self):
        return self.demname is not None

    @property
    def tracks_counts(self):
        # Counts are needed to know when to remove entries from the
        # aggregate result map. If we're using the normal demand
        # strategy, we only remove entries when keys become undemanded,
        # so counts aren't needed.
        return not (self.has_demand and not self.half_demand)

    def __init__(self, aggr, spec, name, demname, uset_lru, half_demand):
        self.params = params = tuple(spec.params)
        """Aggregate parameters (same as operand parameters).
        Also same as aggregate demand parameters.
        """

        self.aggrmask = Mask.from_keylen(len(params))
        """Aggregate result retrieval mask."""

        self.oper_deltamask = spec.relmask.make_delta_mask()
        """Mask for doing delta test upon change to aggregate operand."""

        assert not (spec.has_oper_demand and not self.has_demand), \
            'Can\'t have non-demand-driven aggregate over demand-driven ' \
            'operand'

        assert not (half_demand and not self.has_demand), \
            'Can\'t use half-demand strategy when not using demand at all'
Ejemplo n.º 20
0
class ObjType(Type):
    name = TypedField(str)

    def __str__(self):
        return self.name

    def matches_helper(self, other):
        return False
Ejemplo n.º 21
0
class SetFromMapInvariant(Struct):
    """SetFromMap invariant."""

    # The map key must be a tuple. The mask must be a mapmask with a
    # number of bound components equal to the arity of the map key.

    rel = TypedField(str)
    """Name of variable holding the relation to be created."""
    map = TypedField(str)
    """Name of map being indexed."""
    mask = TypedField(L.mask)
    """Mask for relating the map to the set."""
    def __init__(self, rel, map, mask):
        assert L.is_mapmask(mask)

    def get_maint_func_name(self, op):
        assert op in ['assign', 'delete']
        return N.get_maint_func_name(self.rel, self.map, op)
Ejemplo n.º 22
0
class Primitive(Type):
    
    """Built-in type."""
    
    # Note that t holds a Python class, not a Type.
    t = TypedField(type)
    
    def __str__(self):
        return self.t.__name__
Ejemplo n.º 23
0
class Refine(Type):
    
    name = TypedField(str)
    base = TypedField(Type)
    
    def __str__(self):
        return '{}:{}'.format(self.name, self.base)
    
    def smaller_cmp(self, other):
        return self.base.issmaller(other)
    
    def join_helper(self, other, *, inverted=False):
        # Since we don't have Union types, the only direct ancestor of
        # this type is the base. Therefore, the join of this type with
        # any other type T is the same as the join of the base with T.
        #
        # The only descendants of this type are Bottom and other Refine
        # types. The Refine types only have one parent, so they don't
        # have any ancestors that are incomparable with this type.
        # Consequently, the meet of this type with any incomparable
        # type is Bottom.
        if not inverted:
            return self.base.join(other, inverted=inverted)
        else:
            return Bottom
    
    def widen_helper(self, height):
        # Suppose this type is Refine<name, T>, and that widening is
        # needed. Let U be a widened version of T with T <= U.
        #
        # We can't return Refine<..., U> as our widening, because it is
        # not generally true that Refine<..., T> <= Refine<..., U>.
        # Instead, our widening is just T itself.
        widened_base = self.base.widen(height - 1)
        if widened_base == self.base:
            # Turns out widening is not even needed.
            return self
        else:
            # Something has to give. Return the base with widening, but
            # give it one more level of leeway since we're getting rid
            # of ourselves.
            return self.base.widen(height)
Ejemplo n.º 24
0
class AuxmapInvariant(Struct):
    """Auxiliary map invariant."""

    map = TypedField(str)
    """Name of variable holding the map to be created."""
    rel = TypedField(str)
    """Name of relation being indexed."""
    mask = TypedField(L.mask)
    """Mask for the indexing."""
    unwrap_key = TypedField(bool)
    """Whether the bound part is a single unwrapped component."""
    unwrap_value = TypedField(bool)
    """Whether the unbound part is a single unwrapped component."""
    def __init__(self, map, rel, mask, unwrap_key, unwrap_value):
        assert not (unwrap_key and mask.m.count('b') > 1)
        assert not (unwrap_value and mask.m.count('u') > 1)

    def get_maint_func_name(self, op):
        op_name = L.set_update_name(op)
        return N.get_maint_func_name(self.map, self.rel, op_name)
Ejemplo n.º 25
0
class DefImgset(Cost):
    """Definite image set, i.e., the size of a particular image set
    under a given sequence of key variables, for the given relation and
    mask.
    """

    rel = TypedField(str)
    mask = TypedField(L.mask)
    key = TypedField(str, seq=True)

    def __init__(self, rel, mask, key):
        assert mask.m.count('b') == len(key)

    def __str__(self):
        return '{}_{}[{}]'.format(self.rel, self.mask.m, ', '.join(self.key))

    def to_indef(self):
        """Return the indefinite image-set cost that generalizes this
        cost.
        """
        return IndefImgset(self.rel, self.mask)
Ejemplo n.º 26
0
class SumCost(Cost):
    
    terms = TypedField(Cost, seq=True)
    
    @classmethod
    def from_sums(cls, costs):
        """Form as the concatenation of other SumCosts."""
        assert all(isinstance(c, SumCost) for c in costs)
        return SumCost(tuple(chain.from_iterable(c.terms for c in costs)))
    
    def __str__(self):
        return '(' + ' + '.join(str(s) for s in self.terms) + ')'
Ejemplo n.º 27
0
class ProductCost(Cost):
    
    terms = TypedField(Cost, seq=True)
    
    @classmethod
    def from_products(cls, costs):
        """Form as the concatenation of other ProductCosts."""
        assert all(isinstance(c, ProductCost) for c in costs)
        return ProductCost(tuple(chain.from_iterable(c.terms for c in costs)))
    
    def __str__(self):
        return '(' + '*'.join(str(t) for t in self.terms) + ')'
Ejemplo n.º 28
0
class RestrictiveType(Type):
    name = TypedField(str)
    base = TypedField(Type)

    def __str(self):
        return self.name

    def issubtype_helper(self, other):
        return self.base.issubtype(other)

    def matches_helper(self, other):
        return False

    def join_helper(self, other, *, inverted=False):
        # My join with any type that's not directly comparable
        # is the same as my base's join with that type, since
        # my base is my only direct ancestor.
        #
        # My meet with any type that's not directly comparable
        # is bottom, since the only possible non-bottom subtypes
        # are other refinements, which would have no ancestors
        # that are incomparable to me.
        if not inverted:
            return self.base.join(other, inverted=inverted)
        else:
            return bottomtype

    def expand(self, store):
        new_base = self.base.expand(store)
        return self._replace(base=new_base)

    def widen_helper(self, limit):
        # Rather than lose information in the base, it's probably
        # better to just replace ourselves with the base.
        widened_base = self.base.widen(limit - 1)
        if self.base != widened_base:
            new_type = self.base.widen(limit)
        else:
            new_type = self
        return new_type
Ejemplo n.º 29
0
class DeltaInfo(Struct):
    """Information about maintenance joins."""

    rel = TypedField(str)
    """Delta relation."""
    elem = TypedField(L.AST)
    """Delta element expression AST."""
    lhs = TypedField(str, seq=True)
    """Delta clause LHS identifier list."""
    op = TypedField(str)
    """'add' or 'remove'."""
    @classmethod
    def from_options(cls, options):
        """Construct from comprehension options dict.
        If delta info isn't provided, return None instead
        of an instance.
        """
        if options is None or '_deltarel' not in options:
            return None

        rel = options['_deltarel']
        elem = options['_deltaelem']
        elem = L.pe(elem)
        lhs = options['_deltalhs']
        lhs = L.get_vartuple(L.pe(lhs))
        op = options['_deltaop']
        return cls(rel, elem, lhs, op)

    def __init__(self, rel, elem, lhs, op):
        assert op in ['add', 'remove']

    def updateopts(self, options):
        """Return a modified options dict with the delta keys set."""
        options = dict(options)
        options['_deltarel'] = self.rel
        options['_deltaelem'] = L.ts(self.elem)
        options['_deltalhs'] = L.ts(L.tuplify(self.lhs, lval=True))
        options['_deltaop'] = self.op
        return options
Ejemplo n.º 30
0
class CondClause(Clause, ABCStruct):
    """A condition expression clause."""

    kind = Clause.KIND_COND

    cond = TypedField(L.expr)
    """Condition expression."""
    @classmethod
    def from_AST(cls, node, factory):
        """Construct from expression node."""
        checktype(node, L.expr)

        return cls(node)

    def __init__(self, cond):
        self.vars = tuple(L.VarsFinder.run(cond, ignore_functions=True))

        if L.is_vareqcmp(cond):
            self.eqvars = L.get_vareqcmp(cond)
        else:
            self.eqvars = None

    def to_AST(self):
        return self.cond

    def fits_string(self, bindenv, s):
        return self.cond == L.pe(s)

    def rate(self, bindenv):
        if set(self.vars).issubset(bindenv):
            return Rate.CONSTANT
        else:
            return Rate.UNRUNNABLE

    def get_code(self, bindenv, body):
        assert set(self.vars).issubset(bindenv)
        code = L.pc('''
            if COND:
                BODY
            ''',
                    subst={
                        'COND': self.cond,
                        '<c>BODY': body
                    })
        return code