def parsesingle(s, strictmode=True, expansionlimit=None, convertpos=False): '''like parse, but only consumes a single top level node, e.g. parsing 'a\nb' will only return a node for 'a', leaving b unparsed''' p = _parser(s, strictmode=strictmode, expansionlimit=expansionlimit) tree = p.parse() if convertpos: bast.posconverter(s).visit(tree) return tree
def parse(s, strictmode=True, expansionlimit=None, convertpos=False): '''parse the input string, returning a list of nodes top level node kinds are: - command - a simple command - pipeline - a series of simple commands - list - a series of one or more pipelines - compound - contains constructs for { list; }, (list), if, for.. leafs are word nodes (which in turn can also contain any of the aforementioned nodes due to command substitutions). when strictmode is set to False, we will: - skip reading a heredoc if we're at the end of the input expansionlimit is used to limit the amount of recursive parsing done due to command substitutions found during word expansion. ''' p = _parser(s, strictmode=strictmode, expansionlimit=expansionlimit) parts = [p.parse()] class endfinder(bast.nodevisitor): def __init__(self): self.end = -1 def visitheredoc(self, node, value): self.end = node.pos[1] # find the 'real' end incase we have a heredoc in there ef = _endfinder() ef.visit(parts[-1]) index = max(parts[-1].pos[1], ef.end) + 1 while index < len(s): part = _parser(s[index:], strictmode=strictmode).parse() if not isinstance(part, bast.node): break bast.posshifter(index).visit(part) parts.append(part) ef = _endfinder() ef.visit(parts[-1]) index = max(parts[-1].pos[1], ef.end) + 1 if convertpos: for tree in parts: bast.posconverter(s).visit(tree) return parts