def EvalWordToString(self, word, do_fnmatch=False, decay=False): """ Used for redirect arg, ControlFlow arg, ArithWord, BoolWord, etc. do_fnmatch is true for case $pat and RHS of [[ == ]]. pat="*.py" case $x in $pat) echo 'matches glob pattern' ;; "$pat") echo 'equal to glob string' ;; // must be glob escaped esac """ strs = [] for part in word.parts: for part_val in self.part_ev._EvalWordPart(part, quoted=False): # TODO: if decay, then allow string part. e.g. for here word or here # doc with "$@". if part_val.tag != part_value_e.StringPartValue: # Example: echo f > "$@". TODO: Add proper context. e_die("Expected string, got %s", part) if do_fnmatch: if part_val.do_glob: strs.append(part_val.s) else: strs.append(glob_.GlobEscape(part_val.s)) else: strs.append(part_val.s) return runtime.Str(''.join(strs))
def EvalWordToString(self, word, do_fnmatch=False, do_ere=False): """ Args: word: CompoundWord Used for redirect arg, ControlFlow arg, ArithWord, BoolWord, etc. do_fnmatch is true for case $pat and RHS of [[ == ]]. pat="*.py" case $x in $pat) echo 'matches glob pattern' ;; "$pat") echo 'equal to glob string' ;; # must be glob escaped esac TODO: Raise AssertionError if it has ExtGlobPart. """ if word.tag == word_e.EmptyWord: return runtime.Str('') part_vals = [] for p in word.parts: self._EvalWordPart(p, part_vals, quoted=False) strs = [] for part_val in part_vals: if part_val.tag == part_value_e.StringPartValue: # [[ foo == */"*".py ]] or case *.py) ... esac if do_fnmatch and not part_val.do_split_glob: s = glob_.GlobEscape(part_val.s) elif do_ere and not part_val.do_split_glob: s = glob_.ExtendedRegexEscape(part_val.s) else: s = part_val.s else: if self.exec_opts.strict_array: # Examples: echo f > "$@"; local foo="$@" # TODO: This attributes too coarsely, to the word rather than the # parts. Problem: the word is a TREE of parts, but we only have a # flat list of part_vals. The only case where we really get arrays # is "$@", "${a[@]}", "${a[@]//pat/replace}", etc. e_die( "This word should evaluate to a string, but part of it was an " "array", word=word) # TODO: Maybe add detail like this. #e_die('RHS of assignment should only have strings. ' # 'To assign arrays, use b=( "${a[@]}" )') else: # It appears to not respect IFS s = ' '.join(s for s in part_val.strs if s is not None) strs.append(s) return runtime.Str(''.join(strs))
def EvalWordToString(self, word, do_fnmatch=False, decay=False): """ Used for redirect arg, ControlFlow arg, ArithWord, BoolWord, etc. do_fnmatch is true for case $pat and RHS of [[ == ]]. pat="*.py" case $x in $pat) echo 'matches glob pattern' ;; "$pat") echo 'equal to glob string' ;; // must be glob escaped esac """ part_vals = [] for part in word.parts: self._EvalWordPart(part, part_vals, quoted=False) strs = [] for part_val in part_vals: # TODO: if decay, then allow string part. e.g. for here word or here # doc with "$@". if part_val.tag == part_value_e.StringPartValue: # [[ foo == */"*".py ]] or case *.py) ... esac if do_fnmatch and not part_val.do_split_glob: s = glob_.GlobEscape(part_val.s) else: s = part_val.s else: if self.exec_opts.strict_array: # Examples: echo f > "$@"; local foo="$@" e_die("Expected string, got %s", part_val, word=word) # TODO: Maybe add detail like this. #e_die('RHS of assignment should only have strings. ' # 'To assign arrays, using b=( "${a[@]}" )') else: # It appears to not respect IFS s = ' '.join(part_val.strs) strs.append(s) return runtime.Str(''.join(strs))
def _JoinElideEscape(frag_arrays, elide_empty, glob_escape): """Join parts without globbing or eliding. Returns: arg_value[] """ args = [] #log('_JoinElideEscape frag_arrays %s', frag_arrays) for frag_array in frag_arrays: if glob_escape: #log('frag_array: %s', frag_array) escaped_frags = [] any_glob = False for frag in frag_array: if frag.do_glob: # *.py should be literal escaped_frags.append(frag.s) any_glob = True else: # "*.py" should be glob-escaped to \*.py escaped_frags.append(glob_.GlobEscape(frag.s)) arg_str = ''.join(escaped_frags) #log('ARG STR %s', arg_str) if any_glob: arg = runtime.GlobArg(arg_str) else: # e.g. 'foo'"${var}" shouldn't be globbed # TODO: combine with below: arg = runtime.ConstArg(''.join(frag.s for frag in frag_array)) else: arg = runtime.ConstArg(''.join(frag.s for frag in frag_array)) # Elide $a$b, but not $a"$b" or $a'' if (elide_empty and not arg.s and all(frag.do_elide for frag in frag_array)): #log('eliding frag_array %s', frag_array) continue args.append(arg) return args
def _EvalWordFrame(self, frame, argv): all_empty = True all_split_glob = True any_split_glob = False #log('--- frame %s', frame) for s, do_split_glob in frame: #log('-- %r %r', s, do_split_glob) if s: all_empty = False if do_split_glob: any_split_glob = True else: all_split_glob = False # Elision of ${empty}${empty} but not $empty"$empty" or $empty"" if all_empty and all_split_glob: return # If every frag is quoted, e.g. "$a$b" or any part in "${a[@]}"x, then # don't do word splitting or globbing. if not any_split_glob: a = ''.join(s for s, _ in frame) argv.append(a) return will_glob = not self.exec_opts.noglob # Array of strings, some of which are BOTH IFS-escaped and GLOB escaped! frags = [] for frag, do_split_glob in frame: #log('frag %r do_split_glob %s', frag, do_split_glob) # If it was quoted, then if do_split_glob: # We're going to both split and glob. So we want to backslash # escape twice? # Suppose we get a literal \. # \ -> \\ # \\ -> \\\\ # Splitting takes \\\\ -> \\ # Globbing takes \\ to \ if it doesn't match if will_glob: frag = _BackslashEscape(frag) frag = _BackslashEscape(frag) else: if will_glob: frag = glob_.GlobEscape(frag) #log('GLOB ESCAPED %r', p2) frag = self.splitter.Escape(frag) #log('IFS ESCAPED %r', p2) frags.append(frag) flat = ''.join(frags) #log('flat: %r', flat) args = self.splitter.SplitForWordEval(flat) # space=' '; argv $space"". We have a quoted part, but we CANNOT elide. # Add it back and don't bother globbing. if not args and not all_split_glob: argv.append('') return #log('split args: %r', args) for a in args: # TODO: Expand() should take out parameter. results = self.globber.Expand(a) argv.extend(results)