xref: /OK3568_Linux_fs/yocto/poky/bitbake/lib/bb/pysh/pyshyacc.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun# pyshyacc.py - PLY grammar definition for pysh
2*4882a593Smuzhiyun#
3*4882a593Smuzhiyun# Copyright 2007 Patrick Mezard
4*4882a593Smuzhiyun#
5*4882a593Smuzhiyun# This software may be used and distributed according to the terms
6*4882a593Smuzhiyun# of the GNU General Public License, incorporated herein by reference.
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun"""PLY grammar file.
9*4882a593Smuzhiyun"""
10*4882a593Smuzhiyunimport os.path
11*4882a593Smuzhiyunimport sys
12*4882a593Smuzhiyun
13*4882a593Smuzhiyunimport bb.pysh.pyshlex as pyshlex
14*4882a593Smuzhiyuntokens = pyshlex.tokens
15*4882a593Smuzhiyun
16*4882a593Smuzhiyunfrom ply import yacc
17*4882a593Smuzhiyunimport bb.pysh.sherrors as sherrors
18*4882a593Smuzhiyun
19*4882a593Smuzhiyunclass IORedirect:
20*4882a593Smuzhiyun    def __init__(self, op, filename, io_number=None):
21*4882a593Smuzhiyun        self.op = op
22*4882a593Smuzhiyun        self.filename = filename
23*4882a593Smuzhiyun        self.io_number = io_number
24*4882a593Smuzhiyun
25*4882a593Smuzhiyunclass HereDocument:
26*4882a593Smuzhiyun    def __init__(self, op, name, content, io_number=None):
27*4882a593Smuzhiyun        self.op = op
28*4882a593Smuzhiyun        self.name = name
29*4882a593Smuzhiyun        self.content = content
30*4882a593Smuzhiyun        self.io_number = io_number
31*4882a593Smuzhiyun
32*4882a593Smuzhiyundef make_io_redirect(p):
33*4882a593Smuzhiyun    """Make an IORedirect instance from the input 'io_redirect' production."""
34*4882a593Smuzhiyun    name, io_number, io_target = p
35*4882a593Smuzhiyun    assert name=='io_redirect'
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun    if io_target[0]=='io_file':
38*4882a593Smuzhiyun        io_type, io_op, io_file = io_target
39*4882a593Smuzhiyun        return IORedirect(io_op, io_file, io_number)
40*4882a593Smuzhiyun    elif io_target[0]=='io_here':
41*4882a593Smuzhiyun        io_type, io_op, io_name, io_content = io_target
42*4882a593Smuzhiyun        return HereDocument(io_op, io_name, io_content, io_number)
43*4882a593Smuzhiyun    else:
44*4882a593Smuzhiyun        assert False, "Invalid IO redirection token %s" % repr(io_type)
45*4882a593Smuzhiyun
46*4882a593Smuzhiyunclass SimpleCommand:
47*4882a593Smuzhiyun    """
48*4882a593Smuzhiyun    assigns contains (name, value) pairs.
49*4882a593Smuzhiyun    """
50*4882a593Smuzhiyun    def __init__(self, words, redirs, assigns):
51*4882a593Smuzhiyun        self.words = list(words)
52*4882a593Smuzhiyun        self.redirs = list(redirs)
53*4882a593Smuzhiyun        self.assigns = list(assigns)
54*4882a593Smuzhiyun
55*4882a593Smuzhiyunclass Pipeline:
56*4882a593Smuzhiyun    def __init__(self, commands, reverse_status=False):
57*4882a593Smuzhiyun        self.commands = list(commands)
58*4882a593Smuzhiyun        assert self.commands    #Grammar forbids this
59*4882a593Smuzhiyun        self.reverse_status = reverse_status
60*4882a593Smuzhiyun
61*4882a593Smuzhiyunclass AndOr:
62*4882a593Smuzhiyun    def __init__(self, op, left, right):
63*4882a593Smuzhiyun        self.op = str(op)
64*4882a593Smuzhiyun        self.left = left
65*4882a593Smuzhiyun        self.right = right
66*4882a593Smuzhiyun
67*4882a593Smuzhiyunclass ForLoop:
68*4882a593Smuzhiyun    def __init__(self, name, items, cmds):
69*4882a593Smuzhiyun        self.name = str(name)
70*4882a593Smuzhiyun        self.items = list(items)
71*4882a593Smuzhiyun        self.cmds = list(cmds)
72*4882a593Smuzhiyun
73*4882a593Smuzhiyunclass WhileLoop:
74*4882a593Smuzhiyun    def __init__(self, condition, cmds):
75*4882a593Smuzhiyun        self.condition = list(condition)
76*4882a593Smuzhiyun        self.cmds = list(cmds)
77*4882a593Smuzhiyun
78*4882a593Smuzhiyunclass UntilLoop:
79*4882a593Smuzhiyun    def __init__(self, condition, cmds):
80*4882a593Smuzhiyun        self.condition = list(condition)
81*4882a593Smuzhiyun        self.cmds = list(cmds)
82*4882a593Smuzhiyun
83*4882a593Smuzhiyunclass FunDef:
84*4882a593Smuzhiyun    def __init__(self, name, body):
85*4882a593Smuzhiyun        self.name = str(name)
86*4882a593Smuzhiyun        self.body = body
87*4882a593Smuzhiyun
88*4882a593Smuzhiyunclass BraceGroup:
89*4882a593Smuzhiyun    def __init__(self, cmds):
90*4882a593Smuzhiyun        self.cmds = list(cmds)
91*4882a593Smuzhiyun
92*4882a593Smuzhiyunclass IfCond:
93*4882a593Smuzhiyun    def __init__(self, cond, if_cmds, else_cmds):
94*4882a593Smuzhiyun        self.cond = list(cond)
95*4882a593Smuzhiyun        self.if_cmds = if_cmds
96*4882a593Smuzhiyun        self.else_cmds = else_cmds
97*4882a593Smuzhiyun
98*4882a593Smuzhiyunclass Case:
99*4882a593Smuzhiyun    def __init__(self, name, items):
100*4882a593Smuzhiyun        self.name = name
101*4882a593Smuzhiyun        self.items = items
102*4882a593Smuzhiyun
103*4882a593Smuzhiyunclass SubShell:
104*4882a593Smuzhiyun    def __init__(self, cmds):
105*4882a593Smuzhiyun        self.cmds = cmds
106*4882a593Smuzhiyun
107*4882a593Smuzhiyunclass RedirectList:
108*4882a593Smuzhiyun    def __init__(self, cmd, redirs):
109*4882a593Smuzhiyun        self.cmd = cmd
110*4882a593Smuzhiyun        self.redirs = list(redirs)
111*4882a593Smuzhiyun
112*4882a593Smuzhiyundef get_production(productions, ptype):
113*4882a593Smuzhiyun    """productions must be a list of production tuples like (name, obj) where
114*4882a593Smuzhiyun    name is the production string identifier.
115*4882a593Smuzhiyun    Return the first production named 'ptype'. Raise KeyError if None can be
116*4882a593Smuzhiyun    found.
117*4882a593Smuzhiyun    """
118*4882a593Smuzhiyun    for production in productions:
119*4882a593Smuzhiyun        if production is not None and production[0]==ptype:
120*4882a593Smuzhiyun            return production
121*4882a593Smuzhiyun    raise KeyError(ptype)
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun#-------------------------------------------------------------------------------
124*4882a593Smuzhiyun# PLY grammar definition
125*4882a593Smuzhiyun#-------------------------------------------------------------------------------
126*4882a593Smuzhiyun
127*4882a593Smuzhiyundef p_multiple_commands(p):
128*4882a593Smuzhiyun    """multiple_commands : newline_sequence
129*4882a593Smuzhiyun                         | complete_command
130*4882a593Smuzhiyun                         | multiple_commands complete_command"""
131*4882a593Smuzhiyun    if len(p)==2:
132*4882a593Smuzhiyun        if p[1] is not None:
133*4882a593Smuzhiyun            p[0] = [p[1]]
134*4882a593Smuzhiyun        else:
135*4882a593Smuzhiyun            p[0] = []
136*4882a593Smuzhiyun    else:
137*4882a593Smuzhiyun        p[0] = p[1] + [p[2]]
138*4882a593Smuzhiyun
139*4882a593Smuzhiyundef p_complete_command(p):
140*4882a593Smuzhiyun    """complete_command : list separator
141*4882a593Smuzhiyun                        | list"""
142*4882a593Smuzhiyun    if len(p)==3 and p[2] and p[2][1] == '&':
143*4882a593Smuzhiyun        p[0] = ('async', p[1])
144*4882a593Smuzhiyun    else:
145*4882a593Smuzhiyun        p[0] = p[1]
146*4882a593Smuzhiyun
147*4882a593Smuzhiyundef p_list(p):
148*4882a593Smuzhiyun    """list : list separator_op and_or
149*4882a593Smuzhiyun            |                   and_or"""
150*4882a593Smuzhiyun    if len(p)==2:
151*4882a593Smuzhiyun        p[0] = [p[1]]
152*4882a593Smuzhiyun    else:
153*4882a593Smuzhiyun        #if p[2]!=';':
154*4882a593Smuzhiyun        #    raise NotImplementedError('AND-OR list asynchronous execution is not implemented')
155*4882a593Smuzhiyun        p[0] = p[1] + [p[3]]
156*4882a593Smuzhiyun
157*4882a593Smuzhiyundef p_and_or(p):
158*4882a593Smuzhiyun    """and_or : pipeline
159*4882a593Smuzhiyun              | and_or AND_IF linebreak pipeline
160*4882a593Smuzhiyun              | and_or OR_IF  linebreak pipeline"""
161*4882a593Smuzhiyun    if len(p)==2:
162*4882a593Smuzhiyun        p[0] = p[1]
163*4882a593Smuzhiyun    else:
164*4882a593Smuzhiyun        p[0] = ('and_or', AndOr(p[2], p[1], p[4]))
165*4882a593Smuzhiyun
166*4882a593Smuzhiyundef p_maybe_bang_word(p):
167*4882a593Smuzhiyun    """maybe_bang_word : Bang"""
168*4882a593Smuzhiyun    p[0] = ('maybe_bang_word', p[1])
169*4882a593Smuzhiyun
170*4882a593Smuzhiyundef p_pipeline(p):
171*4882a593Smuzhiyun    """pipeline : pipe_sequence
172*4882a593Smuzhiyun                | bang_word pipe_sequence"""
173*4882a593Smuzhiyun    if len(p)==3:
174*4882a593Smuzhiyun        p[0] = ('pipeline', Pipeline(p[2][1:], True))
175*4882a593Smuzhiyun    else:
176*4882a593Smuzhiyun        p[0] = ('pipeline', Pipeline(p[1][1:]))
177*4882a593Smuzhiyun
178*4882a593Smuzhiyundef p_pipe_sequence(p):
179*4882a593Smuzhiyun    """pipe_sequence : command
180*4882a593Smuzhiyun                     | pipe_sequence PIPE linebreak command"""
181*4882a593Smuzhiyun    if len(p)==2:
182*4882a593Smuzhiyun        p[0] = ['pipe_sequence', p[1]]
183*4882a593Smuzhiyun    else:
184*4882a593Smuzhiyun        p[0] = p[1] + [p[4]]
185*4882a593Smuzhiyun
186*4882a593Smuzhiyundef p_command(p):
187*4882a593Smuzhiyun    """command : simple_command
188*4882a593Smuzhiyun               | compound_command
189*4882a593Smuzhiyun               | compound_command redirect_list
190*4882a593Smuzhiyun               | function_definition"""
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun    if p[1][0] in ( 'simple_command',
193*4882a593Smuzhiyun                    'for_clause',
194*4882a593Smuzhiyun                    'while_clause',
195*4882a593Smuzhiyun                    'until_clause',
196*4882a593Smuzhiyun                    'case_clause',
197*4882a593Smuzhiyun                    'if_clause',
198*4882a593Smuzhiyun                    'function_definition',
199*4882a593Smuzhiyun                    'subshell',
200*4882a593Smuzhiyun                    'brace_group',):
201*4882a593Smuzhiyun        if len(p) == 2:
202*4882a593Smuzhiyun            p[0] = p[1]
203*4882a593Smuzhiyun        else:
204*4882a593Smuzhiyun            p[0] = ('redirect_list', RedirectList(p[1], p[2][1:]))
205*4882a593Smuzhiyun    else:
206*4882a593Smuzhiyun        raise NotImplementedError('%s command is not implemented' % repr(p[1][0]))
207*4882a593Smuzhiyun
208*4882a593Smuzhiyundef p_compound_command(p):
209*4882a593Smuzhiyun    """compound_command : brace_group
210*4882a593Smuzhiyun                        | subshell
211*4882a593Smuzhiyun                        | for_clause
212*4882a593Smuzhiyun                        | case_clause
213*4882a593Smuzhiyun                        | if_clause
214*4882a593Smuzhiyun                        | while_clause
215*4882a593Smuzhiyun                        | until_clause"""
216*4882a593Smuzhiyun    p[0] = p[1]
217*4882a593Smuzhiyun
218*4882a593Smuzhiyundef p_subshell(p):
219*4882a593Smuzhiyun    """subshell : LPARENS compound_list RPARENS"""
220*4882a593Smuzhiyun    p[0] = ('subshell', SubShell(p[2][1:]))
221*4882a593Smuzhiyun
222*4882a593Smuzhiyundef p_compound_list(p):
223*4882a593Smuzhiyun    """compound_list : term
224*4882a593Smuzhiyun                     | newline_list term
225*4882a593Smuzhiyun                     |              term separator
226*4882a593Smuzhiyun                     | newline_list term separator"""
227*4882a593Smuzhiyun    productions = p[1:]
228*4882a593Smuzhiyun    try:
229*4882a593Smuzhiyun        sep = get_production(productions, 'separator')
230*4882a593Smuzhiyun        if sep[1]!=';':
231*4882a593Smuzhiyun            raise NotImplementedError()
232*4882a593Smuzhiyun    except KeyError:
233*4882a593Smuzhiyun        pass
234*4882a593Smuzhiyun    term = get_production(productions, 'term')
235*4882a593Smuzhiyun    p[0] = ['compound_list'] + term[1:]
236*4882a593Smuzhiyun
237*4882a593Smuzhiyundef p_term(p):
238*4882a593Smuzhiyun    """term : term separator and_or
239*4882a593Smuzhiyun            |                and_or"""
240*4882a593Smuzhiyun    if len(p)==2:
241*4882a593Smuzhiyun        p[0] = ['term', p[1]]
242*4882a593Smuzhiyun    else:
243*4882a593Smuzhiyun        if p[2] is not None and p[2][1] == '&':
244*4882a593Smuzhiyun            p[0] = ['term', ('async', p[1][1:])] + [p[3]]
245*4882a593Smuzhiyun        else:
246*4882a593Smuzhiyun            p[0] = p[1] + [p[3]]
247*4882a593Smuzhiyun
248*4882a593Smuzhiyundef p_maybe_for_word(p):
249*4882a593Smuzhiyun    # Rearrange 'For' priority wrt TOKEN. See p_for_word
250*4882a593Smuzhiyun    """maybe_for_word : For"""
251*4882a593Smuzhiyun    p[0] = ('maybe_for_word', p[1])
252*4882a593Smuzhiyun
253*4882a593Smuzhiyundef p_for_clause(p):
254*4882a593Smuzhiyun    """for_clause : for_word name linebreak                            do_group
255*4882a593Smuzhiyun                  | for_word name linebreak in          sequential_sep do_group
256*4882a593Smuzhiyun                  | for_word name linebreak in wordlist sequential_sep do_group"""
257*4882a593Smuzhiyun    productions = p[1:]
258*4882a593Smuzhiyun    do_group = get_production(productions, 'do_group')
259*4882a593Smuzhiyun    try:
260*4882a593Smuzhiyun        items = get_production(productions, 'in')[1:]
261*4882a593Smuzhiyun    except KeyError:
262*4882a593Smuzhiyun        raise NotImplementedError('"in" omission is not implemented')
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun    try:
265*4882a593Smuzhiyun        items = get_production(productions, 'wordlist')[1:]
266*4882a593Smuzhiyun    except KeyError:
267*4882a593Smuzhiyun        items = []
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun    name = p[2]
270*4882a593Smuzhiyun    p[0] = ('for_clause', ForLoop(name, items, do_group[1:]))
271*4882a593Smuzhiyun
272*4882a593Smuzhiyundef p_name(p):
273*4882a593Smuzhiyun    """name : token""" #Was NAME instead of token
274*4882a593Smuzhiyun    p[0] = p[1]
275*4882a593Smuzhiyun
276*4882a593Smuzhiyundef p_in(p):
277*4882a593Smuzhiyun    """in : In"""
278*4882a593Smuzhiyun    p[0] = ('in', p[1])
279*4882a593Smuzhiyun
280*4882a593Smuzhiyundef p_wordlist(p):
281*4882a593Smuzhiyun    """wordlist : wordlist token
282*4882a593Smuzhiyun                |          token"""
283*4882a593Smuzhiyun    if len(p)==2:
284*4882a593Smuzhiyun        p[0] = ['wordlist', ('TOKEN', p[1])]
285*4882a593Smuzhiyun    else:
286*4882a593Smuzhiyun        p[0] = p[1] + [('TOKEN', p[2])]
287*4882a593Smuzhiyun
288*4882a593Smuzhiyundef p_case_clause(p):
289*4882a593Smuzhiyun    """case_clause : Case token linebreak in linebreak case_list    Esac
290*4882a593Smuzhiyun                   | Case token linebreak in linebreak case_list_ns Esac
291*4882a593Smuzhiyun                   | Case token linebreak in linebreak              Esac"""
292*4882a593Smuzhiyun    if len(p) < 8:
293*4882a593Smuzhiyun        items = []
294*4882a593Smuzhiyun    else:
295*4882a593Smuzhiyun        items = p[6][1:]
296*4882a593Smuzhiyun    name = p[2]
297*4882a593Smuzhiyun    p[0] = ('case_clause', Case(name, [c[1] for c in items]))
298*4882a593Smuzhiyun
299*4882a593Smuzhiyundef p_case_list_ns(p):
300*4882a593Smuzhiyun    """case_list_ns : case_list case_item_ns
301*4882a593Smuzhiyun                    |           case_item_ns"""
302*4882a593Smuzhiyun    p_case_list(p)
303*4882a593Smuzhiyun
304*4882a593Smuzhiyundef p_case_list(p):
305*4882a593Smuzhiyun    """case_list : case_list case_item
306*4882a593Smuzhiyun                 |           case_item"""
307*4882a593Smuzhiyun    if len(p)==2:
308*4882a593Smuzhiyun        p[0] = ['case_list', p[1]]
309*4882a593Smuzhiyun    else:
310*4882a593Smuzhiyun        p[0] = p[1] + [p[2]]
311*4882a593Smuzhiyun
312*4882a593Smuzhiyundef p_case_item_ns(p):
313*4882a593Smuzhiyun    """case_item_ns :         pattern RPARENS               linebreak
314*4882a593Smuzhiyun                    |         pattern RPARENS compound_list linebreak
315*4882a593Smuzhiyun                    | LPARENS pattern RPARENS               linebreak
316*4882a593Smuzhiyun                    | LPARENS pattern RPARENS compound_list linebreak"""
317*4882a593Smuzhiyun    p_case_item(p)
318*4882a593Smuzhiyun
319*4882a593Smuzhiyundef p_case_item(p):
320*4882a593Smuzhiyun    """case_item :         pattern RPARENS linebreak     DSEMI linebreak
321*4882a593Smuzhiyun                 |         pattern RPARENS compound_list DSEMI linebreak
322*4882a593Smuzhiyun                 | LPARENS pattern RPARENS linebreak     DSEMI linebreak
323*4882a593Smuzhiyun                 | LPARENS pattern RPARENS compound_list DSEMI linebreak"""
324*4882a593Smuzhiyun    if len(p) < 7:
325*4882a593Smuzhiyun        name = p[1][1:]
326*4882a593Smuzhiyun    else:
327*4882a593Smuzhiyun        name = p[2][1:]
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun    try:
330*4882a593Smuzhiyun        cmds = get_production(p[1:], "compound_list")[1:]
331*4882a593Smuzhiyun    except KeyError:
332*4882a593Smuzhiyun        cmds = []
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun    p[0] = ('case_item', (name, cmds))
335*4882a593Smuzhiyun
336*4882a593Smuzhiyundef p_pattern(p):
337*4882a593Smuzhiyun    """pattern :              token
338*4882a593Smuzhiyun               | pattern PIPE token"""
339*4882a593Smuzhiyun    if len(p)==2:
340*4882a593Smuzhiyun        p[0] = ['pattern', ('TOKEN', p[1])]
341*4882a593Smuzhiyun    else:
342*4882a593Smuzhiyun        p[0] = p[1] + [('TOKEN', p[2])]
343*4882a593Smuzhiyun
344*4882a593Smuzhiyundef p_maybe_if_word(p):
345*4882a593Smuzhiyun    # Rearrange 'If' priority wrt TOKEN. See p_if_word
346*4882a593Smuzhiyun    """maybe_if_word : If"""
347*4882a593Smuzhiyun    p[0] = ('maybe_if_word', p[1])
348*4882a593Smuzhiyun
349*4882a593Smuzhiyundef p_maybe_then_word(p):
350*4882a593Smuzhiyun    # Rearrange 'Then' priority wrt TOKEN. See p_then_word
351*4882a593Smuzhiyun    """maybe_then_word : Then"""
352*4882a593Smuzhiyun    p[0] = ('maybe_then_word', p[1])
353*4882a593Smuzhiyun
354*4882a593Smuzhiyundef p_if_clause(p):
355*4882a593Smuzhiyun    """if_clause : if_word compound_list then_word compound_list else_part Fi
356*4882a593Smuzhiyun                 | if_word compound_list then_word compound_list           Fi"""
357*4882a593Smuzhiyun    else_part = []
358*4882a593Smuzhiyun    if len(p)==7:
359*4882a593Smuzhiyun        else_part = p[5]
360*4882a593Smuzhiyun    p[0] = ('if_clause', IfCond(p[2][1:], p[4][1:], else_part))
361*4882a593Smuzhiyun
362*4882a593Smuzhiyundef p_else_part(p):
363*4882a593Smuzhiyun    """else_part : Elif compound_list then_word compound_list else_part
364*4882a593Smuzhiyun                 | Elif compound_list then_word compound_list
365*4882a593Smuzhiyun                 | Else compound_list"""
366*4882a593Smuzhiyun    if len(p)==3:
367*4882a593Smuzhiyun        p[0] = p[2][1:]
368*4882a593Smuzhiyun    else:
369*4882a593Smuzhiyun        else_part = []
370*4882a593Smuzhiyun        if len(p)==6:
371*4882a593Smuzhiyun            else_part = p[5]
372*4882a593Smuzhiyun        p[0] = ('elif', IfCond(p[2][1:], p[4][1:], else_part))
373*4882a593Smuzhiyun
374*4882a593Smuzhiyundef p_while_clause(p):
375*4882a593Smuzhiyun    """while_clause : While compound_list do_group"""
376*4882a593Smuzhiyun    p[0] = ('while_clause', WhileLoop(p[2][1:], p[3][1:]))
377*4882a593Smuzhiyun
378*4882a593Smuzhiyundef p_maybe_until_word(p):
379*4882a593Smuzhiyun    # Rearrange 'Until' priority wrt TOKEN. See p_until_word
380*4882a593Smuzhiyun    """maybe_until_word : Until"""
381*4882a593Smuzhiyun    p[0] = ('maybe_until_word', p[1])
382*4882a593Smuzhiyun
383*4882a593Smuzhiyundef p_until_clause(p):
384*4882a593Smuzhiyun    """until_clause : until_word compound_list do_group"""
385*4882a593Smuzhiyun    p[0] = ('until_clause', UntilLoop(p[2][1:], p[3][1:]))
386*4882a593Smuzhiyun
387*4882a593Smuzhiyundef p_function_definition(p):
388*4882a593Smuzhiyun    """function_definition : fname LPARENS RPARENS linebreak function_body"""
389*4882a593Smuzhiyun    p[0] = ('function_definition', FunDef(p[1], p[5]))
390*4882a593Smuzhiyun
391*4882a593Smuzhiyundef p_function_body(p):
392*4882a593Smuzhiyun    """function_body : compound_command
393*4882a593Smuzhiyun                     | compound_command redirect_list"""
394*4882a593Smuzhiyun    if len(p)!=2:
395*4882a593Smuzhiyun        raise NotImplementedError('functions redirections lists are not implemented')
396*4882a593Smuzhiyun    p[0] = p[1]
397*4882a593Smuzhiyun
398*4882a593Smuzhiyundef p_fname(p):
399*4882a593Smuzhiyun    """fname : TOKEN""" #Was NAME instead of token
400*4882a593Smuzhiyun    p[0] = p[1]
401*4882a593Smuzhiyun
402*4882a593Smuzhiyundef p_brace_group(p):
403*4882a593Smuzhiyun    """brace_group : Lbrace compound_list Rbrace"""
404*4882a593Smuzhiyun    p[0] = ('brace_group', BraceGroup(p[2][1:]))
405*4882a593Smuzhiyun
406*4882a593Smuzhiyundef p_maybe_done_word(p):
407*4882a593Smuzhiyun    #See p_assignment_word for details.
408*4882a593Smuzhiyun    """maybe_done_word : Done"""
409*4882a593Smuzhiyun    p[0] = ('maybe_done_word', p[1])
410*4882a593Smuzhiyun
411*4882a593Smuzhiyundef p_maybe_do_word(p):
412*4882a593Smuzhiyun    """maybe_do_word : Do"""
413*4882a593Smuzhiyun    p[0] = ('maybe_do_word', p[1])
414*4882a593Smuzhiyun
415*4882a593Smuzhiyundef p_do_group(p):
416*4882a593Smuzhiyun    """do_group : do_word compound_list done_word"""
417*4882a593Smuzhiyun    #Do group contains a list of AndOr
418*4882a593Smuzhiyun    p[0] = ['do_group'] + p[2][1:]
419*4882a593Smuzhiyun
420*4882a593Smuzhiyundef p_simple_command(p):
421*4882a593Smuzhiyun    """simple_command : cmd_prefix cmd_word cmd_suffix
422*4882a593Smuzhiyun                      | cmd_prefix cmd_word
423*4882a593Smuzhiyun                      | cmd_prefix
424*4882a593Smuzhiyun                      | cmd_name cmd_suffix
425*4882a593Smuzhiyun                      | cmd_name"""
426*4882a593Smuzhiyun    words, redirs, assigns = [], [], []
427*4882a593Smuzhiyun    for e in p[1:]:
428*4882a593Smuzhiyun        name = e[0]
429*4882a593Smuzhiyun        if name in ('cmd_prefix', 'cmd_suffix'):
430*4882a593Smuzhiyun            for sube in e[1:]:
431*4882a593Smuzhiyun                subname = sube[0]
432*4882a593Smuzhiyun                if subname=='io_redirect':
433*4882a593Smuzhiyun                    redirs.append(make_io_redirect(sube))
434*4882a593Smuzhiyun                elif subname=='ASSIGNMENT_WORD':
435*4882a593Smuzhiyun                    assigns.append(sube)
436*4882a593Smuzhiyun                else:
437*4882a593Smuzhiyun                    words.append(sube)
438*4882a593Smuzhiyun        elif name in ('cmd_word', 'cmd_name'):
439*4882a593Smuzhiyun            words.append(e)
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun    cmd = SimpleCommand(words, redirs, assigns)
442*4882a593Smuzhiyun    p[0] = ('simple_command', cmd)
443*4882a593Smuzhiyun
444*4882a593Smuzhiyundef p_cmd_name(p):
445*4882a593Smuzhiyun    """cmd_name : TOKEN"""
446*4882a593Smuzhiyun    p[0] = ('cmd_name', p[1])
447*4882a593Smuzhiyun
448*4882a593Smuzhiyundef p_cmd_word(p):
449*4882a593Smuzhiyun    """cmd_word : token"""
450*4882a593Smuzhiyun    p[0] = ('cmd_word', p[1])
451*4882a593Smuzhiyun
452*4882a593Smuzhiyundef p_maybe_assignment_word(p):
453*4882a593Smuzhiyun    #See p_assignment_word for details.
454*4882a593Smuzhiyun    """maybe_assignment_word : ASSIGNMENT_WORD"""
455*4882a593Smuzhiyun    p[0] = ('maybe_assignment_word', p[1])
456*4882a593Smuzhiyun
457*4882a593Smuzhiyundef p_cmd_prefix(p):
458*4882a593Smuzhiyun    """cmd_prefix :            io_redirect
459*4882a593Smuzhiyun                  | cmd_prefix io_redirect
460*4882a593Smuzhiyun                  |            assignment_word
461*4882a593Smuzhiyun                  | cmd_prefix assignment_word"""
462*4882a593Smuzhiyun    try:
463*4882a593Smuzhiyun        prefix = get_production(p[1:], 'cmd_prefix')
464*4882a593Smuzhiyun    except KeyError:
465*4882a593Smuzhiyun        prefix = ['cmd_prefix']
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun    try:
468*4882a593Smuzhiyun        value = get_production(p[1:], 'assignment_word')[1]
469*4882a593Smuzhiyun        value = ('ASSIGNMENT_WORD', value.split('=', 1))
470*4882a593Smuzhiyun    except KeyError:
471*4882a593Smuzhiyun        value = get_production(p[1:], 'io_redirect')
472*4882a593Smuzhiyun    p[0] = prefix + [value]
473*4882a593Smuzhiyun
474*4882a593Smuzhiyundef p_cmd_suffix(p):
475*4882a593Smuzhiyun    """cmd_suffix   :            io_redirect
476*4882a593Smuzhiyun                    | cmd_suffix io_redirect
477*4882a593Smuzhiyun                    |            token
478*4882a593Smuzhiyun                    | cmd_suffix token
479*4882a593Smuzhiyun                    |            maybe_for_word
480*4882a593Smuzhiyun                    | cmd_suffix maybe_for_word
481*4882a593Smuzhiyun                    |            maybe_done_word
482*4882a593Smuzhiyun                    | cmd_suffix maybe_done_word
483*4882a593Smuzhiyun                    |            maybe_do_word
484*4882a593Smuzhiyun                    | cmd_suffix maybe_do_word
485*4882a593Smuzhiyun                    |            maybe_until_word
486*4882a593Smuzhiyun                    | cmd_suffix maybe_until_word
487*4882a593Smuzhiyun                    |            maybe_assignment_word
488*4882a593Smuzhiyun                    | cmd_suffix maybe_assignment_word
489*4882a593Smuzhiyun                    |            maybe_if_word
490*4882a593Smuzhiyun                    | cmd_suffix maybe_if_word
491*4882a593Smuzhiyun                    |            maybe_then_word
492*4882a593Smuzhiyun                    | cmd_suffix maybe_then_word
493*4882a593Smuzhiyun                    |            maybe_bang_word
494*4882a593Smuzhiyun                    | cmd_suffix maybe_bang_word"""
495*4882a593Smuzhiyun    try:
496*4882a593Smuzhiyun        suffix = get_production(p[1:], 'cmd_suffix')
497*4882a593Smuzhiyun        token = p[2]
498*4882a593Smuzhiyun    except KeyError:
499*4882a593Smuzhiyun        suffix = ['cmd_suffix']
500*4882a593Smuzhiyun        token = p[1]
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun    if isinstance(token, tuple):
503*4882a593Smuzhiyun        if token[0]=='io_redirect':
504*4882a593Smuzhiyun            p[0] = suffix + [token]
505*4882a593Smuzhiyun        else:
506*4882a593Smuzhiyun            #Convert maybe_*  to TOKEN if necessary
507*4882a593Smuzhiyun            p[0] = suffix + [('TOKEN', token[1])]
508*4882a593Smuzhiyun    else:
509*4882a593Smuzhiyun        p[0] = suffix + [('TOKEN', token)]
510*4882a593Smuzhiyun
511*4882a593Smuzhiyundef p_redirect_list(p):
512*4882a593Smuzhiyun    """redirect_list : io_redirect
513*4882a593Smuzhiyun                     | redirect_list io_redirect"""
514*4882a593Smuzhiyun    if len(p) == 2:
515*4882a593Smuzhiyun        p[0] = ['redirect_list', make_io_redirect(p[1])]
516*4882a593Smuzhiyun    else:
517*4882a593Smuzhiyun        p[0] = p[1] + [make_io_redirect(p[2])]
518*4882a593Smuzhiyun
519*4882a593Smuzhiyundef p_io_redirect(p):
520*4882a593Smuzhiyun    """io_redirect :           io_file
521*4882a593Smuzhiyun                   | IO_NUMBER io_file
522*4882a593Smuzhiyun                   |           io_here
523*4882a593Smuzhiyun                   | IO_NUMBER io_here"""
524*4882a593Smuzhiyun    if len(p)==3:
525*4882a593Smuzhiyun        p[0] = ('io_redirect', p[1], p[2])
526*4882a593Smuzhiyun    else:
527*4882a593Smuzhiyun        p[0] = ('io_redirect', None, p[1])
528*4882a593Smuzhiyun
529*4882a593Smuzhiyundef p_io_file(p):
530*4882a593Smuzhiyun    #Return the tuple (operator, filename)
531*4882a593Smuzhiyun    """io_file : LESS      filename
532*4882a593Smuzhiyun               | LESSAND   filename
533*4882a593Smuzhiyun               | GREATER   filename
534*4882a593Smuzhiyun               | GREATAND  filename
535*4882a593Smuzhiyun               | DGREAT    filename
536*4882a593Smuzhiyun               | LESSGREAT filename
537*4882a593Smuzhiyun               | CLOBBER   filename"""
538*4882a593Smuzhiyun    #Extract the filename from the file
539*4882a593Smuzhiyun    p[0] = ('io_file', p[1], p[2][1])
540*4882a593Smuzhiyun
541*4882a593Smuzhiyundef p_filename(p):
542*4882a593Smuzhiyun    #Return the filename
543*4882a593Smuzhiyun    """filename : TOKEN"""
544*4882a593Smuzhiyun    p[0] = ('filename', p[1])
545*4882a593Smuzhiyun
546*4882a593Smuzhiyundef p_io_here(p):
547*4882a593Smuzhiyun    """io_here : DLESS here_end
548*4882a593Smuzhiyun               | DLESSDASH here_end"""
549*4882a593Smuzhiyun    p[0] = ('io_here', p[1], p[2][1], p[2][2])
550*4882a593Smuzhiyun
551*4882a593Smuzhiyundef p_here_end(p):
552*4882a593Smuzhiyun    """here_end : HERENAME TOKEN"""
553*4882a593Smuzhiyun    p[0] = ('here_document', p[1], p[2])
554*4882a593Smuzhiyun
555*4882a593Smuzhiyundef p_newline_sequence(p):
556*4882a593Smuzhiyun    # Nothing in the grammar can handle leading NEWLINE productions, so add
557*4882a593Smuzhiyun    # this one with the lowest possible priority relatively to newline_list.
558*4882a593Smuzhiyun    """newline_sequence : newline_list"""
559*4882a593Smuzhiyun    p[0] = None
560*4882a593Smuzhiyun
561*4882a593Smuzhiyundef p_newline_list(p):
562*4882a593Smuzhiyun    """newline_list : NEWLINE
563*4882a593Smuzhiyun                    | newline_list NEWLINE"""
564*4882a593Smuzhiyun    p[0] = None
565*4882a593Smuzhiyun
566*4882a593Smuzhiyundef p_linebreak(p):
567*4882a593Smuzhiyun    """linebreak : newline_list
568*4882a593Smuzhiyun                 | empty"""
569*4882a593Smuzhiyun    p[0] = None
570*4882a593Smuzhiyun
571*4882a593Smuzhiyundef p_separator_op(p):
572*4882a593Smuzhiyun    """separator_op : COMMA
573*4882a593Smuzhiyun                    | COMMA COMMA
574*4882a593Smuzhiyun                    | AMP"""
575*4882a593Smuzhiyun    p[0] = p[1]
576*4882a593Smuzhiyun
577*4882a593Smuzhiyundef p_separator(p):
578*4882a593Smuzhiyun    """separator : separator_op linebreak
579*4882a593Smuzhiyun                 | newline_list"""
580*4882a593Smuzhiyun    if len(p)==2:
581*4882a593Smuzhiyun        #Ignore newlines
582*4882a593Smuzhiyun        p[0] = None
583*4882a593Smuzhiyun    else:
584*4882a593Smuzhiyun        #Keep the separator operator
585*4882a593Smuzhiyun        p[0] = ('separator', p[1])
586*4882a593Smuzhiyun
587*4882a593Smuzhiyundef p_sequential_sep(p):
588*4882a593Smuzhiyun    """sequential_sep : COMMA linebreak
589*4882a593Smuzhiyun                      | newline_list"""
590*4882a593Smuzhiyun    p[0] = None
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun# Low priority TOKEN => for_word conversion.
593*4882a593Smuzhiyun# Let maybe_for_word be used as a token when necessary in higher priority
594*4882a593Smuzhiyun# rules.
595*4882a593Smuzhiyundef p_for_word(p):
596*4882a593Smuzhiyun    """for_word : maybe_for_word"""
597*4882a593Smuzhiyun    p[0] = p[1]
598*4882a593Smuzhiyun
599*4882a593Smuzhiyundef p_if_word(p):
600*4882a593Smuzhiyun    """if_word : maybe_if_word"""
601*4882a593Smuzhiyun    p[0] = p[1]
602*4882a593Smuzhiyun
603*4882a593Smuzhiyundef p_then_word(p):
604*4882a593Smuzhiyun    """then_word : maybe_then_word"""
605*4882a593Smuzhiyun    p[0] = p[1]
606*4882a593Smuzhiyun
607*4882a593Smuzhiyundef p_done_word(p):
608*4882a593Smuzhiyun    """done_word : maybe_done_word"""
609*4882a593Smuzhiyun    p[0] = p[1]
610*4882a593Smuzhiyun
611*4882a593Smuzhiyundef p_do_word(p):
612*4882a593Smuzhiyun    """do_word : maybe_do_word"""
613*4882a593Smuzhiyun    p[0] = p[1]
614*4882a593Smuzhiyun
615*4882a593Smuzhiyundef p_until_word(p):
616*4882a593Smuzhiyun    """until_word : maybe_until_word"""
617*4882a593Smuzhiyun    p[0] = p[1]
618*4882a593Smuzhiyun
619*4882a593Smuzhiyundef p_assignment_word(p):
620*4882a593Smuzhiyun    """assignment_word : maybe_assignment_word"""
621*4882a593Smuzhiyun    p[0] = ('assignment_word', p[1][1])
622*4882a593Smuzhiyun
623*4882a593Smuzhiyundef p_bang_word(p):
624*4882a593Smuzhiyun    """bang_word : maybe_bang_word"""
625*4882a593Smuzhiyun    p[0] = ('bang_word', p[1][1])
626*4882a593Smuzhiyun
627*4882a593Smuzhiyundef p_token(p):
628*4882a593Smuzhiyun    """token : TOKEN
629*4882a593Smuzhiyun             | Fi"""
630*4882a593Smuzhiyun    p[0] = p[1]
631*4882a593Smuzhiyun
632*4882a593Smuzhiyundef p_empty(p):
633*4882a593Smuzhiyun    'empty :'
634*4882a593Smuzhiyun    p[0] = None
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun# Error rule for syntax errors
637*4882a593Smuzhiyundef p_error(p):
638*4882a593Smuzhiyun    msg = []
639*4882a593Smuzhiyun    w = msg.append
640*4882a593Smuzhiyun    if p:
641*4882a593Smuzhiyun        w('%r\n' % p)
642*4882a593Smuzhiyun        w('followed by:\n')
643*4882a593Smuzhiyun        for i in range(5):
644*4882a593Smuzhiyun            n = yacc.token()
645*4882a593Smuzhiyun            if not n:
646*4882a593Smuzhiyun                break
647*4882a593Smuzhiyun            w('  %r\n' % n)
648*4882a593Smuzhiyun    else:
649*4882a593Smuzhiyun        w('Unexpected EOF')
650*4882a593Smuzhiyun    raise sherrors.ShellSyntaxError(''.join(msg))
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun# Build the parser
653*4882a593Smuzhiyuntry:
654*4882a593Smuzhiyun    import pyshtables
655*4882a593Smuzhiyunexcept ImportError:
656*4882a593Smuzhiyun    outputdir = os.path.dirname(__file__)
657*4882a593Smuzhiyun    if not os.access(outputdir, os.W_OK):
658*4882a593Smuzhiyun        outputdir = ''
659*4882a593Smuzhiyun    yacc.yacc(tabmodule = 'pyshtables', outputdir = outputdir, debug = 0)
660*4882a593Smuzhiyunelse:
661*4882a593Smuzhiyun    yacc.yacc(tabmodule = 'pysh.pyshtables', write_tables = 0, debug = 0)
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun
664*4882a593Smuzhiyundef parse(input, eof=False, debug=False):
665*4882a593Smuzhiyun    """Parse a whole script at once and return the generated AST and unconsumed
666*4882a593Smuzhiyun    data in a tuple.
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun    NOTE: eof is probably meaningless for now, the parser being unable to work
669*4882a593Smuzhiyun    in pull mode. It should be set to True.
670*4882a593Smuzhiyun    """
671*4882a593Smuzhiyun    lexer = pyshlex.PLYLexer()
672*4882a593Smuzhiyun    remaining = lexer.add(input, eof)
673*4882a593Smuzhiyun    if lexer.is_empty():
674*4882a593Smuzhiyun        return [], remaining
675*4882a593Smuzhiyun    if debug:
676*4882a593Smuzhiyun        debug = 2
677*4882a593Smuzhiyun    return yacc.parse(lexer=lexer, debug=debug), remaining
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun#-------------------------------------------------------------------------------
680*4882a593Smuzhiyun# AST rendering helpers
681*4882a593Smuzhiyun#-------------------------------------------------------------------------------
682*4882a593Smuzhiyun
683*4882a593Smuzhiyundef format_commands(v):
684*4882a593Smuzhiyun    """Return a tree made of strings and lists. Make command trees easier to
685*4882a593Smuzhiyun    display.
686*4882a593Smuzhiyun    """
687*4882a593Smuzhiyun    if isinstance(v, list):
688*4882a593Smuzhiyun        return [format_commands(c) for c in v]
689*4882a593Smuzhiyun    if isinstance(v, tuple):
690*4882a593Smuzhiyun        if len(v)==2 and isinstance(v[0], str) and not isinstance(v[1], str):
691*4882a593Smuzhiyun            if v[0] == 'async':
692*4882a593Smuzhiyun                return ['AsyncList', map(format_commands, v[1])]
693*4882a593Smuzhiyun            else:
694*4882a593Smuzhiyun                #Avoid decomposing tuples like ('pipeline', Pipeline(...))
695*4882a593Smuzhiyun                return format_commands(v[1])
696*4882a593Smuzhiyun        return format_commands(list(v))
697*4882a593Smuzhiyun    elif isinstance(v, IfCond):
698*4882a593Smuzhiyun        name = ['IfCond']
699*4882a593Smuzhiyun        name += ['if', map(format_commands, v.cond)]
700*4882a593Smuzhiyun        name += ['then', map(format_commands, v.if_cmds)]
701*4882a593Smuzhiyun        name += ['else', map(format_commands, v.else_cmds)]
702*4882a593Smuzhiyun        return name
703*4882a593Smuzhiyun    elif isinstance(v, ForLoop):
704*4882a593Smuzhiyun        name = ['ForLoop']
705*4882a593Smuzhiyun        name += [repr(v.name)+' in ', map(str, v.items)]
706*4882a593Smuzhiyun        name += ['commands', map(format_commands, v.cmds)]
707*4882a593Smuzhiyun        return name
708*4882a593Smuzhiyun    elif isinstance(v, AndOr):
709*4882a593Smuzhiyun        return [v.op, format_commands(v.left), format_commands(v.right)]
710*4882a593Smuzhiyun    elif isinstance(v, Pipeline):
711*4882a593Smuzhiyun        name = 'Pipeline'
712*4882a593Smuzhiyun        if v.reverse_status:
713*4882a593Smuzhiyun            name = '!' + name
714*4882a593Smuzhiyun        return [name, format_commands(v.commands)]
715*4882a593Smuzhiyun    elif isinstance(v, Case):
716*4882a593Smuzhiyun        name = ['Case']
717*4882a593Smuzhiyun        name += [v.name, format_commands(v.items)]
718*4882a593Smuzhiyun    elif isinstance(v, SimpleCommand):
719*4882a593Smuzhiyun        name = ['SimpleCommand']
720*4882a593Smuzhiyun        if v.words:
721*4882a593Smuzhiyun            name += ['words', map(str, v.words)]
722*4882a593Smuzhiyun        if v.assigns:
723*4882a593Smuzhiyun            assigns = [tuple(a[1]) for a in v.assigns]
724*4882a593Smuzhiyun            name += ['assigns', map(str, assigns)]
725*4882a593Smuzhiyun        if v.redirs:
726*4882a593Smuzhiyun            name += ['redirs', map(format_commands, v.redirs)]
727*4882a593Smuzhiyun        return name
728*4882a593Smuzhiyun    elif isinstance(v, RedirectList):
729*4882a593Smuzhiyun        name = ['RedirectList']
730*4882a593Smuzhiyun        if v.redirs:
731*4882a593Smuzhiyun            name += ['redirs', map(format_commands, v.redirs)]
732*4882a593Smuzhiyun        name += ['command', format_commands(v.cmd)]
733*4882a593Smuzhiyun        return name
734*4882a593Smuzhiyun    elif isinstance(v, IORedirect):
735*4882a593Smuzhiyun        return ' '.join(map(str, (v.io_number, v.op, v.filename)))
736*4882a593Smuzhiyun    elif isinstance(v, HereDocument):
737*4882a593Smuzhiyun        return ' '.join(map(str, (v.io_number, v.op, repr(v.name), repr(v.content))))
738*4882a593Smuzhiyun    elif isinstance(v, SubShell):
739*4882a593Smuzhiyun        return ['SubShell', map(format_commands, v.cmds)]
740*4882a593Smuzhiyun    else:
741*4882a593Smuzhiyun        return repr(v)
742*4882a593Smuzhiyun
743*4882a593Smuzhiyundef print_commands(cmds, output=sys.stdout):
744*4882a593Smuzhiyun    """Pretty print a command tree."""
745*4882a593Smuzhiyun    def print_tree(cmd, spaces, output):
746*4882a593Smuzhiyun        if isinstance(cmd, list):
747*4882a593Smuzhiyun            for c in cmd:
748*4882a593Smuzhiyun                print_tree(c, spaces + 3, output)
749*4882a593Smuzhiyun        else:
750*4882a593Smuzhiyun            print >>output, ' '*spaces + str(cmd)
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun    formatted = format_commands(cmds)
753*4882a593Smuzhiyun    print_tree(formatted, 0, output)
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun
756*4882a593Smuzhiyundef stringify_commands(cmds):
757*4882a593Smuzhiyun    """Serialize a command tree as a string.
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun    Returned string is not pretty and is currently used for unit tests only.
760*4882a593Smuzhiyun    """
761*4882a593Smuzhiyun    def stringify(value):
762*4882a593Smuzhiyun        output = []
763*4882a593Smuzhiyun        if isinstance(value, list):
764*4882a593Smuzhiyun            formatted = []
765*4882a593Smuzhiyun            for v in value:
766*4882a593Smuzhiyun                formatted.append(stringify(v))
767*4882a593Smuzhiyun            formatted = ' '.join(formatted)
768*4882a593Smuzhiyun            output.append(''.join(['<', formatted, '>']))
769*4882a593Smuzhiyun        else:
770*4882a593Smuzhiyun            output.append(value)
771*4882a593Smuzhiyun        return ' '.join(output)
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun    return stringify(format_commands(cmds))
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun
776*4882a593Smuzhiyundef visit_commands(cmds, callable):
777*4882a593Smuzhiyun    """Visit the command tree and execute callable on every Pipeline and
778*4882a593Smuzhiyun    SimpleCommand instances.
779*4882a593Smuzhiyun    """
780*4882a593Smuzhiyun    if isinstance(cmds, (tuple, list)):
781*4882a593Smuzhiyun        map(lambda c: visit_commands(c,callable), cmds)
782*4882a593Smuzhiyun    elif isinstance(cmds, (Pipeline, SimpleCommand)):
783*4882a593Smuzhiyun        callable(cmds)
784