Example #1
0
def visit(node: Node, data: dict, context: Context) -> EvalObject:
    if isinstance(node, BinaryNode):
        if node.op in ['=', '<', '>', '>=', '<=']:
            if node.visited:
                previous = context.previous[context.get_current_index()]
                res = Table(table_copy(previous.name, context), previous.fv,
                            previous.is_negative)
            else:
                res = visit_condition(node, context)
                node.visited = True
        else:
            left = visit(node.left, data, context)
            right = visit(node.right, data, context)
            if node.op in ['*', '/', 'MOD', '+', '-']:
                raise RuntimeError(
                    "Arithmetic operator without condition operator found in" +
                    node.to_str())
            elif node.op == 'OR':
                res = union(left, right, context)
            elif node.op == 'AND':
                res = intersection(left, right, context)
            elif node.op == 'IMPLIES':
                res = union(negation(left, context), right, context)
            elif node.op == 'EQUIV':
                if isinstance(left, Table) and isinstance(right, Table):
                    l_tuples = get_tuples(left.name, left.fv, context)
                    r_tuples = get_tuples(right.name, right.fv, context)
                    if l_tuples == r_tuples:
                        res = Bool(True)
                    else:
                        res = Bool(False)
                else:
                    raise RuntimeError(
                        "EQUIV must contain tables on both sides")
            elif node.op == 'SINCE':
                if node.sub:
                    start, end = node.sub
                    ts_diff = context.current_ts - context.previous_ts
                    res = None
                    for to in range(0, end + 1):
                        frm = max(0, to - (end - start))
                        if frm > 0:
                            if ts_diff <= to:
                                res = context.previous[
                                    context.get_current_index() - ts_diff]
                            else:
                                res = Bool(False)
                        else:
                            if frm <= ts_diff <= to:
                                previous = context.previous[
                                    context.get_current_index() - ts_diff]
                            else:
                                previous = Bool(False)
                            res = union(right,
                                        intersection(left, previous, context),
                                        context)
                        if to < end:
                            context.current.append(res)

                else:
                    previous = context.previous[context.get_current_index()]
                    res = union(right, intersection(left, previous, context),
                                context)
            else:
                raise RuntimeError("Unhandled operator " + node.op)
    elif isinstance(node, UnaryNode):
        child = visit(node.child, data, context)
        if node.op == 'NOT':
            res = negation(child, context)
        elif node.op == 'EXISTS':
            if isinstance(child, Table):
                if set(node.sub).issubset([e[0] for e in child.fv]):
                    fv = set()
                    for e in child.fv:
                        if not e[0] in node.sub:
                            fv.add(e)
                    if fv == set():
                        if child.is_negative:
                            res = Bool(False)
                        else:
                            if get_tuples(child.name, child.fv, context):
                                res = Bool(True)
                            else:
                                res = Bool(False)
                    else:
                        if child.is_negative:
                            res = Table(empty_table(fv, context), fv,
                                        child.is_negative)
                        else:
                            res = Table(projection(child.name, fv, context),
                                        fv, child.is_negative)
                else:
                    raise RuntimeError("EXISTS: %s has to be subset of %s" %
                                       (node.sub, child.fv))
            else:
                raise RuntimeError("EXISTS of non-Table not supported")
        elif node.op == 'FORALL':
            if isinstance(child, Table):
                if set(node.sub).issubset(child.fv):
                    fv = child.fv.difference(set(node.sub))
                    if fv == set():
                        if child.is_negative:
                            if get_tuples(child.name, child.fv, context):
                                res = Bool(True)
                            else:
                                res = Bool(False)
                        else:
                            res = Bool(False)
                    else:
                        if child.is_negative:
                            res = Table(projection(child.name, fv, context),
                                        fv, child.is_negative)
                        else:
                            res = Table(empty_table(fv, context), fv,
                                        child.is_negative)
                else:
                    raise RuntimeError(
                        "FORALL: %s has to be subset of %s" % node.sub,
                        child.fv)
            else:
                raise RuntimeError("FORALL of non-Table not supported")
        elif node.op == 'PREVIOUS':
            previous = context.previous[context.get_current_index() - 1]
            if node.sub:
                start, end = node.sub
                ts_diff = context.current_ts - context.previous_ts
                if start <= ts_diff <= end:
                    if isinstance(previous, Table):
                        res = Table(table_copy(previous.name, context),
                                    previous.fv, previous.is_negative)
                    else:
                        res = previous
                else:
                    res = Table(empty_table(previous.fv, context), previous.fv,
                                False)
            else:
                if isinstance(previous, Table):
                    res = Table(table_copy(previous.name, context),
                                previous.fv, previous.is_negative)
                else:
                    res = previous
        elif node.op == 'ONCE':
            if node.sub:
                start, end = node.sub
                ts_diff = context.current_ts - context.previous_ts
                res = None
                for to in range(0, end + 1):
                    frm = max(0, to - (end - start))
                    if frm > 0:
                        if ts_diff <= to:
                            res = context.previous[context.get_current_index()
                                                   - ts_diff]
                        else:
                            res = Bool(False)
                    else:
                        if frm <= ts_diff <= to:
                            previous = context.previous[
                                context.get_current_index() - ts_diff]
                        else:
                            previous = Bool(False)
                        res = union(child, previous, context)
                    if to < end:
                        context.current.append(res)
            else:
                previous = context.previous[context.get_current_index()]
                res = union(child, previous, context)
        elif node.op in ['SUM', 'MIN', 'MAX', 'CNT', 'AVG']:
            if len(node.sub) == 2:
                out, aggreg = node.sub
                res = aggregation(child, node.op, out, aggreg, context)
            elif len(node.sub) == 3:
                out, aggreg, group_by = node.sub
                res = aggregation(child, node.op, out, aggreg, context,
                                  group_by)
            else:
                raise RuntimeError("Error parsing aggregation")
        else:
            raise RuntimeError("Unhandled operator: " + node.op)
    elif isinstance(node, Leaf):
        res = parse_leaf(node, data, context)
    else:
        raise RuntimeError("Error while parsing node: " + node.to_str())
    context.current.append(res)

    # if isinstance(res, Table):
    #     if isinstance(node, BinaryNode):
    #         print(res.name, res.fv, node.op, end=" ")
    #         print(get_tuples(res.name, res.fv, context))
    #     elif isinstance(node, UnaryNode):
    #         print(res.name, res.fv, node.op, end=" ")
    #         print(get_tuples(res.name, res.fv, context))
    #     elif isinstance(node, Leaf):
    #         print(res.name, res.fv, node.typ, node.value, end=" ")
    #         print(get_tuples(res.name, res.fv, context))
    # elif isinstance(res, Bool):
    #     if isinstance(node, BinaryNode):
    #         print(res.v, node.op)
    #     elif isinstance(node, UnaryNode):
    #         print(res.v, node.op)
    #     elif isinstance(node, Leaf):
    #         print(res.v, node.typ, node.value)

    return res