Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
import unittest
from bashlex import tokenizer, state, flags, errors
from bashlex.tokenizer import token as t
from bashlex.tokenizer import tokentype as tt
tokenize = lambda s: list(tokenizer.tokenizer(s, state.parserstate()))
hasdollarset = set([flags.word.HASDOLLAR])
class test_tokenizer(unittest.TestCase):
def assertTokens(self, s, tokens):
result = tokenize(s)
# pop the last token if it's a new line since that gets appended
# to the input string by default and we don't really care about
# that here
if result[-1].value == '\n':
result.pop()
self.assertEquals(result, tokens)
for t in tokens:
self.assertEquals(str(t.value), s[t.lexpos:t.endlexpos])
s = 'wx y =z '
self.assertTokens(s, [
t(tt.WORD, 'wx', [0, 2]),
t(tt.WORD, 'y', [6, 7]),
t(tt.WORD, '=z', [8, 10])])
s = "a 'b' c"
self.assertTokens(s, [
t(tt.WORD, 'a', [0, 1]),
t(tt.WORD, "'b'", [2, 5], set([flags.word.QUOTED])),
t(tt.WORD, 'c', [6, 7])])
s = "a 'b ' c"
self.assertTokens(s, [
t(tt.WORD, 'a', [0, 1]),
t(tt.WORD, "'b '", [2, 7], set([flags.word.QUOTED])),
t(tt.WORD, 'c', [8, 9])])
if node:
parts.append(node)
istring += string[tindex:sindex[0]]
elif c == '`':
tindex = sindex[0]
# bare instance of ``
if nextchar() == '`':
sindex[0] += 1
istring += '``'
else:
x = _stringextract(string, sindex[0], "`")
if x == -1:
raise errors.ParsingError('bad substitution: no closing "`" '
'in %s' % string)
else:
if wordtoken.flags & flags.word.NOCOMSUB:
pass
else:
sindex[0] = x
word = string[tindex+1:sindex[0]]
command, ttindex = _recursiveparse(parserobj, word, 0)
_adjustpositions(command, tindex+1, len(string))
ttindex += 1 # ttindex is on the closing char
# assert sindex[0] == ttindex
# go one past the closing `
sindex[0] += 1
node = ast.node(kind='commandsubstitution',
command=command,
pos=(tindex, sindex[0]))
"{" : tokentype.LEFT_CURLY,
"}" : tokentype.RIGHT_CURLY,
"!" : tokentype.BANG,
"[[" : tokentype.COND_START,
"]]" : tokentype.COND_END,
"coproc" : tokentype.COPROC
}
class MatchedPairError(errors.ParsingError):
def __init__(self, startline, message, tokenizer):
# TODO use startline?
super(MatchedPairError, self).__init__(message,
tokenizer.source,
tokenizer._shell_input_line_index - 1)
wordflags = flags.word
parserflags = flags.parser
class token(object):
def __init__(self, type_, value, pos=None, flags=None):
if type_ is not None:
assert isinstance(type_, tokentype)
if flags is None:
flags = set()
self.ttype = type_
self.value = value
if pos is not None:
self.lexpos = pos[0]
self.endlexpos = pos[1]
def _expandword(parser, tokenword):
if parser._expansionlimit == -1:
# we enter this branch in the following conditions:
# - currently parsing a substitution as a result of an expansion
# - the previous expansion had limit == 0
#
# this means that this node is a descendant of a substitution in an
# unexpanded word and will be filtered in the limit == 0 condition below
#
# (the reason we even expand when limit == 0 is to get quote removal)
node = ast.node(kind='word', word=tokenword,
pos=(tokenword.lexpos, tokenword.endlexpos), parts=[])
return node
else:
quoted = bool(tokenword.flags & flags.word.QUOTED)
doublequoted = quoted and tokenword.value[0] == '"'
# TODO set qheredocument
parts, expandedword = subst._expandwordinternal(parser,
tokenword, 0,
doublequoted, 0, 0)
# limit reached, don't include substitutions (still expanded to get
# quote removal though)
if parser._expansionlimit == 0:
parts = [node for node in parts if 'substitution' not in node.kind]
node = ast.node(kind='word', word=expandedword,
pos=(tokenword.lexpos, tokenword.endlexpos), parts=parts)
return node
tindex = sindex[0] + 1
node, sindex[0] = _extractprocesssubst(parserobj, string, tindex)
parts.append(ast.node(kind='processsubstitution', command=node,
pos=(tindex - 2, sindex[0])))
istring += string[tindex - 2:sindex[0]]
# goto dollar_add_string
# TODO
# elif c == '=':
# pass
# elif c == ':':
# pass
elif c == '~':
if (wordtoken.flags & set([flags.word.NOTILDE, flags.word.DQUOTE]) or
(sindex[0] > 0 and not (wordtoken.flags & flags.word.NOTILDE)) or
qdoublequotes or qheredocument):
wordtoken.flags.clear()
wordtoken.flags.add(flags.word.ITILDE)
sindex[0] += 1
istring += c
else:
stopatcolon = wordtoken.flags & set([flags.word.ASSIGNRHS,
flags.word.ASSIGNMENT,
flags.word.TILDEEXP])
expand = True
for i in range(sindex[0], len(string)):
r = string[i]
if r == '/':
break
if r in "\\'\"":
expand = False
else:
tindex = sindex[0] + 1
node, sindex[0] = _extractprocesssubst(parserobj, string, tindex)
parts.append(ast.node(kind='processsubstitution', command=node,
pos=(tindex - 2, sindex[0])))
istring += string[tindex - 2:sindex[0]]
# goto dollar_add_string
# TODO
# elif c == '=':
# pass
# elif c == ':':
# pass
elif c == '~':
if (wordtoken.flags & set([flags.word.NOTILDE, flags.word.DQUOTE]) or
(sindex[0] > 0 and not (wordtoken.flags & flags.word.NOTILDE)) or
qdoublequotes or qheredocument):
wordtoken.flags.clear()
wordtoken.flags.add(flags.word.ITILDE)
sindex[0] += 1
istring += c
else:
stopatcolon = wordtoken.flags & set([flags.word.ASSIGNRHS,
flags.word.ASSIGNMENT,
flags.word.TILDEEXP])
expand = True
for i in range(sindex[0], len(string)):
r = string[i]
if r == '/':
break
if r in "\\'\"":
def nextchar():
sindex[0] += 1
if sindex[0] < len(string):
return string[sindex[0]]
def peekchar():
if sindex[0]+1 < len(string):
return string[sindex[0]+1]
while True:
if sindex[0] == len(string):
break
# goto finished_with_string
c = string[sindex[0]]
if c in '<>':
if (nextchar() != '(' or qheredocument or qdoublequotes or
(wordtoken.flags & set([flags.word.DQUOTE, flags.word.NOPROCSUB]))):
sindex[0] -= 1
# goto add_character
sindex[0] += 1
istring += c
else:
tindex = sindex[0] + 1
node, sindex[0] = _extractprocesssubst(parserobj, string, tindex)
parts.append(ast.node(kind='processsubstitution', command=node,
pos=(tindex - 2, sindex[0])))
istring += string[tindex - 2:sindex[0]]
# goto dollar_add_string
# TODO
# elif c == '=':