1b35a1733607b07f36c3617932b67debb375a15c5Daniel Dunbarfrom __future__ import absolute_import 2be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarimport itertools 3be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 4128ce319ec47c46dc7da16aa3a75185899878745Daniel Dunbarimport lit.util 5b35a1733607b07f36c3617932b67debb375a15c5Daniel Dunbarfrom lit.ShCommands import Command, Pipeline, Seq 6be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 7be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarclass ShLexer: 8be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def __init__(self, data, win32Escapes = False): 9be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.data = data 10be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.pos = 0 11be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.end = len(data) 12be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.win32Escapes = win32Escapes 13be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 14be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def eat(self): 15be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar c = self.data[self.pos] 16be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.pos += 1 17be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return c 18be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 19be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def look(self): 20be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return self.data[self.pos] 21be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 22be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def maybe_eat(self, c): 23be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar """ 24be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar maybe_eat(c) - Consume the character c if it is the next character, 25be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar returning True if a character was consumed. """ 26be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.data[self.pos] == c: 27be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.pos += 1 28be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return True 29be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return False 30be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 31be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def lex_arg_fast(self, c): 32be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # Get the leading whitespace free section. 33be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar chunk = self.data[self.pos - 1:].split(None, 1)[0] 34be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 35be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # If it has special characters, the fast path failed. 36be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if ('|' in chunk or '&' in chunk or 37be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar '<' in chunk or '>' in chunk or 38be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar "'" in chunk or '"' in chunk or 3963a08e09ae301241d0bdd0618bb0533a1d303cf5Daniel Dunbar ';' in chunk or '\\' in chunk): 40be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return None 41be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 42be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.pos = self.pos - 1 + len(chunk) 43be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return chunk 44be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 45be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def lex_arg_slow(self, c): 46be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if c in "'\"": 47be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar str = self.lex_arg_quoted(c) 48be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar else: 49be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar str = c 50be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar while self.pos != self.end: 51be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar c = self.look() 5263a08e09ae301241d0bdd0618bb0533a1d303cf5Daniel Dunbar if c.isspace() or c in "|&;": 53be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar break 54be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar elif c in '><': 55be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # This is an annoying case; we treat '2>' as a single token so 56be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # we don't have to track whitespace tokens. 57be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 58be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # If the parse string isn't an integer, do the usual thing. 59be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if not str.isdigit(): 60be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar break 61be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 62be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # Otherwise, lex the operator and convert to a redirection 63be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # token. 64be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar num = int(str) 65be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar tok = self.lex_one_token() 66be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar assert isinstance(tok, tuple) and len(tok) == 1 67be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return (tok[0], num) 68be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar elif c == '"': 69be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.eat() 703f451cafb5ba3a022c8e05cf2d054835f807dd11Daniel Dunbar str += self.lex_arg_quoted('"') 71bd4fa2efd373c46dc14b87744b908f16f539c836Daniel Dunbar elif c == "'": 72bd4fa2efd373c46dc14b87744b908f16f539c836Daniel Dunbar self.eat() 73bd4fa2efd373c46dc14b87744b908f16f539c836Daniel Dunbar str += self.lex_arg_quoted("'") 74be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar elif not self.win32Escapes and c == '\\': 75be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # Outside of a string, '\\' escapes everything. 76be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.eat() 77be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.pos == self.end: 78128ce319ec47c46dc7da16aa3a75185899878745Daniel Dunbar lit.util.warning( 79b35a1733607b07f36c3617932b67debb375a15c5Daniel Dunbar "escape at end of quoted argument in: %r" % self.data) 80be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return str 81be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar str += self.eat() 82be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar else: 83be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar str += self.eat() 84be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return str 85be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 86be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def lex_arg_quoted(self, delim): 87be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar str = '' 88be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar while self.pos != self.end: 89be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar c = self.eat() 90be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if c == delim: 91be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return str 92be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar elif c == '\\' and delim == '"': 93be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # Inside a '"' quoted string, '\\' only escapes the quote 94be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # character and backslash, otherwise it is preserved. 95be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.pos == self.end: 96128ce319ec47c46dc7da16aa3a75185899878745Daniel Dunbar lit.util.warning( 97b35a1733607b07f36c3617932b67debb375a15c5Daniel Dunbar "escape at end of quoted argument in: %r" % self.data) 98be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return str 99be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar c = self.eat() 100be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if c == '"': # 101be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar str += '"' 102be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar elif c == '\\': 103be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar str += '\\' 104be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar else: 105be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar str += '\\' + c 106be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar else: 107be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar str += c 108128ce319ec47c46dc7da16aa3a75185899878745Daniel Dunbar lit.util.warning("missing quote character in %r" % self.data) 109be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return str 110be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 111be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def lex_arg_checked(self, c): 112be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar pos = self.pos 113be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar res = self.lex_arg_fast(c) 114be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar end = self.pos 115be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 116be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.pos = pos 117be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar reference = self.lex_arg_slow(c) 118be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if res is not None: 119be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if res != reference: 12026e0af54c2eb3efe468715edada97442e469bb19Daniel Dunbar raise ValueError("Fast path failure: %r != %r" % ( 12126e0af54c2eb3efe468715edada97442e469bb19Daniel Dunbar res, reference)) 122be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.pos != end: 12326e0af54c2eb3efe468715edada97442e469bb19Daniel Dunbar raise ValueError("Fast path failure: %r != %r" % ( 12426e0af54c2eb3efe468715edada97442e469bb19Daniel Dunbar self.pos, end)) 125be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return reference 126be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 127be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def lex_arg(self, c): 128be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return self.lex_arg_fast(c) or self.lex_arg_slow(c) 129be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 130be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def lex_one_token(self): 131be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar """ 132be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar lex_one_token - Lex a single 'sh' token. """ 133be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 134be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar c = self.eat() 13552d4de971fe523fe43d6f868331a14ed1743f35aNAKAMURA Takumi if c == ';': 136be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return (c,) 137be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if c == '|': 138be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.maybe_eat('|'): 139be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return ('||',) 140be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return (c,) 141be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if c == '&': 142be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.maybe_eat('&'): 143be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return ('&&',) 144be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.maybe_eat('>'): 145be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return ('&>',) 146be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return (c,) 147be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if c == '>': 148be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.maybe_eat('&'): 149be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return ('>&',) 150be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.maybe_eat('>'): 151be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return ('>>',) 152be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return (c,) 153be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if c == '<': 154be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.maybe_eat('&'): 155be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return ('<&',) 156be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.maybe_eat('>'): 157be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return ('<<',) 158be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return (c,) 159be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 160be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return self.lex_arg(c) 161be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 162be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def lex(self): 163be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar while self.pos != self.end: 164be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if self.look().isspace(): 165be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.eat() 166be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar else: 167be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar yield self.lex_one_token() 168be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 169be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar### 170be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 171be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarclass ShParser: 172c1bb2d432501dabdfcb1e78eccfb7377664c4d14Rafael Espindola def __init__(self, data, win32Escapes = False, pipefail = False): 173be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.data = data 174c1bb2d432501dabdfcb1e78eccfb7377664c4d14Rafael Espindola self.pipefail = pipefail 175be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.tokens = ShLexer(data, win32Escapes = win32Escapes).lex() 176be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 177be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def lex(self): 1782e10ff28f24a26829ae9a43fc49b91eb974489efDaniel Dunbar for item in self.tokens: 1792e10ff28f24a26829ae9a43fc49b91eb974489efDaniel Dunbar return item 1802e10ff28f24a26829ae9a43fc49b91eb974489efDaniel Dunbar return None 181be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 182be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def look(self): 1832e10ff28f24a26829ae9a43fc49b91eb974489efDaniel Dunbar token = self.lex() 1842e10ff28f24a26829ae9a43fc49b91eb974489efDaniel Dunbar if token is not None: 1852e10ff28f24a26829ae9a43fc49b91eb974489efDaniel Dunbar self.tokens = itertools.chain([token], self.tokens) 1862e10ff28f24a26829ae9a43fc49b91eb974489efDaniel Dunbar return token 187be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 188be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def parse_command(self): 189be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar tok = self.lex() 190be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if not tok: 19126e0af54c2eb3efe468715edada97442e469bb19Daniel Dunbar raise ValueError("empty command!") 192be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if isinstance(tok, tuple): 19326e0af54c2eb3efe468715edada97442e469bb19Daniel Dunbar raise ValueError("syntax error near unexpected token %r" % tok[0]) 194be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 195be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar args = [tok] 196be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar redirects = [] 197be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar while 1: 198be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar tok = self.look() 199be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 200be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # EOF? 201be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if tok is None: 202be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar break 203be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 204be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # If this is an argument, just add it to the current command. 205be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if isinstance(tok, str): 206be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar args.append(self.lex()) 207be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar continue 208be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 209be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # Otherwise see if it is a terminator. 210be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar assert isinstance(tok, tuple) 2111f7ebddd5f6f6787023a0b7b2cd3dd4e80e10447Chandler Carruth if tok[0] in ('|',';','&','||','&&'): 212be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar break 213be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 214be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # Otherwise it must be a redirection. 215be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar op = self.lex() 216be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar arg = self.lex() 217be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if not arg: 21826e0af54c2eb3efe468715edada97442e469bb19Daniel Dunbar raise ValueError("syntax error near token %r" % op[0]) 219be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar redirects.append((op, arg)) 220be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 221be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return Command(args, redirects) 222be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 223be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def parse_pipeline(self): 224be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar negate = False 225be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 226be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar commands = [self.parse_command()] 2271f7ebddd5f6f6787023a0b7b2cd3dd4e80e10447Chandler Carruth while self.look() == ('|',): 2281f7ebddd5f6f6787023a0b7b2cd3dd4e80e10447Chandler Carruth self.lex() 2291f7ebddd5f6f6787023a0b7b2cd3dd4e80e10447Chandler Carruth commands.append(self.parse_command()) 230c1bb2d432501dabdfcb1e78eccfb7377664c4d14Rafael Espindola return Pipeline(commands, negate, self.pipefail) 231be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 232be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def parse(self): 233be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar lhs = self.parse_pipeline() 234be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 235be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar while self.look(): 236be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar operator = self.lex() 237be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar assert isinstance(operator, tuple) and len(operator) == 1 238be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 239be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar if not self.look(): 24026e0af54c2eb3efe468715edada97442e469bb19Daniel Dunbar raise ValueError( 24126e0af54c2eb3efe468715edada97442e469bb19Daniel Dunbar "missing argument to operator %r" % operator[0]) 242be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 243be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar # FIXME: Operator precedence!! 244be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar lhs = Seq(lhs, operator[0], self.parse_pipeline()) 245be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 246be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return lhs 247be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 248be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar### 249be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 250be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarimport unittest 251be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 252be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarclass TestShLexer(unittest.TestCase): 253be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def lex(self, str, *args, **kwargs): 254be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return list(ShLexer(str, *args, **kwargs).lex()) 255be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 256be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def test_basic(self): 25763a08e09ae301241d0bdd0618bb0533a1d303cf5Daniel Dunbar self.assertEqual(self.lex('a|b>c&d<e;f'), 258be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ['a', ('|',), 'b', ('>',), 'c', ('&',), 'd', 25963a08e09ae301241d0bdd0618bb0533a1d303cf5Daniel Dunbar ('<',), 'e', (';',), 'f']) 260be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 261be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def test_redirection_tokens(self): 262be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.lex('a2>c'), 263be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ['a2', ('>',), 'c']) 264be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.lex('a 2>c'), 265be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ['a', ('>',2), 'c']) 266be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 267be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def test_quoting(self): 268be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.lex(""" 'a' """), 269be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ['a']) 270be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.lex(""" "hello\\"world" """), 271be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ['hello"world']) 272be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.lex(""" "hello\\'world" """), 273be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ["hello\\'world"]) 274be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.lex(""" "hello\\\\world" """), 275be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ["hello\\world"]) 276be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.lex(""" he"llo wo"rld """), 277be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ["hello world"]) 278be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.lex(""" a\\ b a\\\\b """), 279be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ["a b", "a\\b"]) 280be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.lex(""" "" "" """), 281be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ["", ""]) 282be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.lex(""" a\\ b """, win32Escapes = True), 283be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ['a\\', 'b']) 284be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 285be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarclass TestShParse(unittest.TestCase): 286be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def parse(self, str): 287be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar return ShParser(str).parse() 288be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 289be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def test_basic(self): 290be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('echo hello'), 291be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['echo', 'hello'], [])], False)) 292be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('echo ""'), 293be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['echo', ''], [])], False)) 294bd4fa2efd373c46dc14b87744b908f16f539c836Daniel Dunbar self.assertEqual(self.parse("""echo -DFOO='a'"""), 295bd4fa2efd373c46dc14b87744b908f16f539c836Daniel Dunbar Pipeline([Command(['echo', '-DFOO=a'], [])], False)) 296bd4fa2efd373c46dc14b87744b908f16f539c836Daniel Dunbar self.assertEqual(self.parse('echo -DFOO="a"'), 297bd4fa2efd373c46dc14b87744b908f16f539c836Daniel Dunbar Pipeline([Command(['echo', '-DFOO=a'], [])], False)) 298be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 299be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def test_redirection(self): 300be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('echo hello > c'), 301be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['echo', 'hello'], 302be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar [((('>'),), 'c')])], False)) 303be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('echo hello > c >> d'), 304be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['echo', 'hello'], [(('>',), 'c'), 305be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar (('>>',), 'd')])], False)) 306be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('a 2>&1'), 307be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['a'], [(('>&',2), '1')])], False)) 308be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 309be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def test_pipeline(self): 310be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('a | b'), 311be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['a'], []), 312be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Command(['b'], [])], 313be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar False)) 314be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 315be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('a | b | c'), 316be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['a'], []), 317be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Command(['b'], []), 318be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Command(['c'], [])], 319be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar False)) 320be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 321be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar def test_list(self): 322be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('a ; b'), 323be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Seq(Pipeline([Command(['a'], [])], False), 324be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar ';', 325be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['b'], [])], False))) 326be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 327be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('a & b'), 328be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Seq(Pipeline([Command(['a'], [])], False), 329be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar '&', 330be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['b'], [])], False))) 331be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 332be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('a && b'), 333be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Seq(Pipeline([Command(['a'], [])], False), 334be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar '&&', 335be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['b'], [])], False))) 336be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 337be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('a || b'), 338be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Seq(Pipeline([Command(['a'], [])], False), 339be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar '||', 340be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['b'], [])], False))) 341be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 342be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar self.assertEqual(self.parse('a && b || c'), 343be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Seq(Seq(Pipeline([Command(['a'], [])], False), 344be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar '&&', 345be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['b'], [])], False)), 346be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar '||', 347be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar Pipeline([Command(['c'], [])], False))) 348be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar 34963a08e09ae301241d0bdd0618bb0533a1d303cf5Daniel Dunbar self.assertEqual(self.parse('a; b'), 35063a08e09ae301241d0bdd0618bb0533a1d303cf5Daniel Dunbar Seq(Pipeline([Command(['a'], [])], False), 35163a08e09ae301241d0bdd0618bb0533a1d303cf5Daniel Dunbar ';', 35263a08e09ae301241d0bdd0618bb0533a1d303cf5Daniel Dunbar Pipeline([Command(['b'], [])], False))) 35363a08e09ae301241d0bdd0618bb0533a1d303cf5Daniel Dunbar 354be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarif __name__ == '__main__': 355be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar unittest.main() 356