def get_target_node(source, target, rules, max_single_nt_applications=1):
  """Return node corresponding to parses for target, or None."""
  tokens = source.split(" ")

  def node_fn(span_begin, span_end, rule, children):
    target_string = qcfg_rule.apply_target(
        rule, [node.target_string for node in children])
    return RuleApplicationNode(rule, children, span_begin, span_end,
                               target_string)

  def postprocess_fn(nodes):
    nodes = filter_nodes(nodes, target)
    return _aggregate(nodes, _fingerprint)

  nodes = qcfg_parser.parse(
      tokens,
      rules,
      node_fn=node_fn,
      postprocess_cell_fn=postprocess_fn,
      max_single_nt_applications=max_single_nt_applications)

  # Filter for nodes where target_string matches target exactly.
  ret_nodes = []
  for node in nodes:
    if node.target_string == target:
      ret_nodes.append(node)

  if not ret_nodes:
    return None

  # Add application and aggregation nodes for root.
  if len(ret_nodes) == 1:
    return RuleApplicationNode(ROOT_RULE_KEY, [ret_nodes[0]], 0, len(tokens),
                               target)
  elif len(ret_nodes) > 1:
    root_children = []
    for ret_node in ret_nodes:
      root_children.append(
          RuleApplicationNode(ROOT_RULE_KEY, [ret_node], 0, len(tokens),
                              target))
    return AggregationNode(root_children)
  else:
    raise ValueError
Return node corresponding to parses for target, or None.
language/compgen/csl/model/data/parsing_utils.py