예제 #1
0
    def _parse_tree(cst, candidate, path):
        # get the label of the top-most element of the CST
        # this should be either 'pause', 'conj', 'disj', or a relation
        assert type(cst) == list
        label = cst[0]
        assert label != 'state'

        # root node in cst is a PAUSE
        if label == 'pause':
            # obtain the candidate partial program from the "pause" node
            candidate = lisp.unparse(helper.get_candidate_from_pause(cst),
                                     collapse_lvar=True)
            obj = _parse_tree(cst[2], candidate, path)
            choices.append(obj)
            return obj

        # root node in cst is a CONJ
        if label == 'conj':
            # obtain all children of conj nodes
            leafs = [
                _parse_tree(leaf, candidate, path)
                for p, leaf in helper.flatten_branches(cst, path)
            ]
            return FlatConj(constraints=leafs,
                            candidate=candidate,
                            path=path,
                            unparsed="(" + " && ".join(l.unparsed
                                                       for l in leafs) + ")")
        if label == 'disj':
            # obtain all children of disj nodes
            leafs = [
                _parse_tree(leaf, candidate, p)
                for p, leaf in helper.flatten_branches(cst, path)
            ]
            return FlatDisj(constraints=leafs,
                            candidate=candidate,
                            path=path,
                            unparsed="(" + " || ".join(l.unparsed
                                                       for l in leafs) + ")")

        # root node is a RELATION; leaf node
        leafstr = lisp.unparse(cst, True)
        leaf_tokens = lisp.tokenize(leafstr)
        leaf_type = leaf_tokens[1]
        tok_seq = get_token_ids(leaf_tokens)
        return Constraint(unparsed=leafstr,
                          candidate=candidate,
                          type=leaf_type,
                          seq=tok_seq,
                          len=len(tok_seq),
                          path=path[:])
예제 #2
0
def get_candidate(cst, path, collapse_lvar=False):
    """Retrieve the candidate at a path in the cst, and
    convert it into a string.

    Arguments:

    cst  -- a constraint tree, consisting of conj / disj / pause
            internal nodes and constraint leafs. the tree 
            representing the "state" of the PBE problem
            and comes from Interaction.state
    path -- array of 0's and 1's, indicating whether to go left or right
            at a disjunction
    collapse_lvar -- whether to rename all logic variables to "_"
    """
    if cst[0] == 'conj':
        return get_candidate(cst[1], path, collapse_lvar)
    if cst[0] == 'disj':
        if path[0] == 0:
            return get_candidate(cst[1], path[1:], collapse_lvar)
        else:
            return get_candidate(cst[2], path[1:], collapse_lvar)

    assert len(path) == 0 and cst[0] == 'pause'
    state = get_candidate_from_pause(cst)
    return lisp.unparse(state, collapse_lvar)
예제 #3
0
def get_candidates(cst, current_path=None, candidate=None):
    """Retrieve all (path, candidate) pairs in a cst. Each path is 
    encoded as an array of 0 / 1 indicating to go left / right at a 
    disjunction. Each candidate is stringified.

    cst  -- a constraint tree, consisting of conj / disj / pause
            internal nodes and constraint leafs. the tree 
            representing the "state" of the PBE problem
            and comes from Interaction.state
    current_path (optional) -- accumulator variable for recursion
            indicating path from the root to the current cst node
    candidate (optional) -- accumulator variable for recursion
            indicating current candidate
    """
    if current_path is None:
        current_path = []

    if type(cst) == list:
        label = cst[0]
        if label == 'pause':
            candidate = get_candidate_from_pause(cst)
            candidate = lisp.unparse(candidate, True)
            return get_candidates(cst[2], current_path, candidate)
        if label == 'state':
            raise ValueError("Should not have state")
        if label == 'conj': # only go left
            return get_candidates(cst[1], current_path, candidate)
        if label == 'disj':
            return get_candidates(cst[1], current_path + [0], candidate) + \
                   get_candidates(cst[2], current_path + [1], candidate)
        return [(current_path, candidate)]
예제 #4
0
    def _send(self, datum):
        """Helper frunction to write to the scheme process.

        Arguments:

        datum -- the content of the message to be relayed, as a parsed
                 lisp data structure.
        """
        self.proc.stdin.write((lisp.unparse(datum) + '\n').encode('utf-8'))
        self.proc.stdin.flush()
예제 #5
0
def parse_tree(cst, acc=None, prev=None, candidate=None, path=None):
    """Recursive function that converts a constraint tree into a parsed form
    consisting of subclasses of gnn_nodes.Node

    cst  -- a constraint tree, consisting of conj / disj / pause
            internal nodes and constraint leafs. the tree
            representing the "state" of the PBE problem
            and comes from Interaction.state
    acc  -- an accumulator that is passed by value
    prev -- a previous instance of parsed_tree() accumulator from the previous
            step of the same problem
    candidate -- candidate partial program related to this part of the subtree
    path -- array of 0's and 1's, indicating whether to go left or right
            at a disjunction
    """
    # set up initial values that are objects
    path = path or []
    acc = acc or {"constraints": [], "memo": {}, "lvar": {}}
    if "constraints" not in acc:
        acc["constraints"] = []  # repository of constraints
    if "memo" not in acc:
        acc["memo"] = {}  # memoized parsed subtree
    if "lvar" not in acc:
        acc["lvar"] = {}  # all logic variables
    prev = prev or {}

    node_type = get_cst_node_type(cst)

    # get the pause & state out of the way
    if node_type == 'pause':
        candidate = lisp.unparse(helper.get_candidate_from_pause(cst), True)
        return parse_tree(cst[2], acc, prev, candidate, path)
    if node_type == 'state':
        raise ValueError("Should never be here!")

    # logical constructs
    if node_type == 'conj':
        children = []
        for subpath, subcst in helper.flatten_branches(cst, path):
            # for conj, subpath is ignored!
            child, acc = parse_tree(subcst, acc, prev, candidate, path)
            children.append(child)
        return NAryConj(children, path), acc
        #left, acc = parse_tree(cst[1], acc, prev, candidate, path)
        #right, acc = parse_tree(cst[2], acc, prev, candidate, path)
        #return Conj(left, right, path), acc
    if node_type == 'disj':
        children = []
        for subpath, subcst in helper.flatten_branches(cst, path):
            child, acc = parse_tree(subcst, acc, prev, candidate, subpath)
            children.append(child)
        return NAryDisj(children, path), acc
        #left, acc = parse_tree(cst[1], acc, prev, candidate, path+[0])
        #right, acc = parse_tree(cst[2], acc, prev, candidate, path+[1])
        #return Disj(left, right, path), acc

    # if using MEMOIZE, check if this (sub-)tree has already been parsed, and
    # its parsed version stored
    unparsed = lisp.unparse(cst)
    if MEMOIZE and unparsed in acc["memo"]:
        return acc["memo"][unparsed], acc

    # logic variables: add to repository of logic variables if not exist
    if node_type == 'lvar':
        if cst not in acc['lvar']:
            new_node = prev.get('lvar', {}).get(cst)
            new_node = new_node or LVar(cst)
            acc['lvar'][cst] = new_node
        return acc["lvar"][cst], acc

    # relations
    if node_type in ('evalo', 'lookupo', '==', 'eval-listo', 'not-falseo',
                     'not-nullo'):
        # a relations can have multiple children in its tree
        child_asts = []
        for child_cst in cst[1:]:
            child_ast, acc = parse_tree(child_cst, acc, prev, candidate, path)
            child_asts.append(child_ast)
        NodeClass = GNN_NODE_CLASS[node_type]
        new_node_args = child_asts + [path, unparsed, candidate]
        new_node = NodeClass(*new_node_args)
        acc["constraints"].append(new_node)
        return new_node, acc

    # pairs
    if node_type == 'pair':
        if len(cst) == 3 and cst[1] == '.':
            # first
            left, acc = parse_tree(cst[0], acc, prev, candidate, path)
            # second
            right, acc = parse_tree(cst[2], acc, prev, candidate, path)
        else:
            # first
            left, acc = parse_tree(cst[0], acc, prev, candidate, path)
            # rest
            right, acc = parse_tree(cst[1:], acc, prev, candidate, path)
        new_node = Pair(left, right)
        if MEMOIZE and not has_lvar(unparsed):
            acc["memo"][unparsed] = new_node
        return new_node, acc

    # language constructs (inside the relations leafs)
    if node_type == 'const':
        new_node = Constant(unparsed)
        if MEMOIZE and not has_lvar(unparsed):
            acc["memo"][unparsed] = new_node
        return new_node, acc

    raise ValueError("Should not be here?")