예제 #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 parse_split_trees(cst):
    """Split the CST into multiple trees, one per candidate.
    This function returns a list of tree objects, 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
    """
    shared_memo = {}
    parsed = []
    for path, subtree in helper.flatten_branches(cst, []):
        ast, acc = parse_tree(subtree, {"memo": shared_memo}, path=path)
        parsed.append((ast, acc))
    return parsed
예제 #3
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?")