def _SplitSimpleCommandPrefix(self, words): """ Second pass of SimpleCommand parsing: look for assignment words. """ prefix_bindings = [] suffix_words = [] done_prefix = False for w in words: if done_prefix: suffix_words.append(w) continue left_spid = word.LeftMostSpanForWord(w) kov = word.LooksLikeAssignment(w) if kov: k, op, v = kov t = word.TildeDetect(v) if t: # t is an unevaluated word with TildeSubPart prefix_bindings.append((k, op, t, left_spid)) else: prefix_bindings.append((k, op, v, left_spid)) # v is unevaluated word else: done_prefix = True suffix_words.append(w) return prefix_bindings, suffix_words
def ParseRedirect(self): """ Problem: You don't know which kind of redir_node to instantiate before this? You could stuff them all in one node, and then have a switch() on the type. You need different types. """ if not self._Peek(): return None assert self.c_kind == Kind.Redir, self.cur_word left_spid = self.cur_word.token.span_id # For now only supporting single digit descriptor first_char = self.cur_word.token.val[0] if first_char.isdigit(): fd = int(first_char) else: fd = -1 if self.c_id in (Id.Redir_DLess, Id.Redir_DLessDash): # here doc node = ast.HereDoc() node.op_id = self.c_id node.arg_word = None # not read yet node.fd = fd node.was_filled = False node.spids.append(left_spid) self._Next() if not self._Peek(): return None # "If any character in word is quoted, the delimiter shall be formed by # performing quote removal on word, and the here-document lines shall not # be expanded. Otherwise, the delimiter shall be the word itself." # NOTE: \EOF counts, or even E\OF ok, node.here_end, quoted = word.StaticEval(self.cur_word) if not ok: self._BadWord('Error evaluating here doc delimiter: %s', self.cur_word) return None node.do_expansion = not quoted self._Next() else: node = ast.Redirect() node.op_id = self.c_id node.fd = fd node.spids.append(left_spid) self._Next() if not self._Peek(): return None if self.c_kind != Kind.Word: self.AddErrorContext( 'Expected word after redirect operator', word=self.cur_word) return None new_word = word.TildeDetect(self.cur_word) node.arg_word = new_word or self.cur_word self._Next() return node
def assertStyle(test, expected_style, word_str): w = _assertReadWord(test, word_str) new_word = word.TildeDetect(w) if new_word is not None: w = new_word actual = osh2oil._GetRhsStyle(w) test.assertEqual(expected_style, actual)
def _TildeDetectAll(self, words): new_words = [] for w in words: t = word.TildeDetect(w) if t: new_words.append(t) else: new_words.append(w) return new_words
def _MakeAssignment(self, assign_kw, suffix_words): bindings = [] for i, w in enumerate(suffix_words): if i == 0: continue # skip over local, export, etc. left_spid = word.LeftMostSpanForWord(w) kv = word.LooksLikeAssignment(w) if kv: k, v = kv t = word.TildeDetect(v) if t: # t is an unevaluated word with TildeSubPart pair = (k, t, left_spid) else: pair = (k, v, left_spid) # v is unevaluated word else: # In aboriginal in variables/sources: export_if_blank does export "$1". # We should allow that. ok, value, quoted = word.StaticEval(w) if not ok or quoted: self.AddErrorContext( 'Variable names must be constant strings, got %s', w, word=w) return None pair = (value, None, left_spid) # No value is equivalent to '' bindings.append(pair) pairs = [] for lhs, rhs, spid in bindings: p = ast.assign_pair(ast.LeftVar(lhs), rhs) p.spids.append(spid) pairs.append(p) node = ast.Assignment(assign_kw, pairs) return node
def _MakeAssignment(self, assign_kw, suffix_words): # First parse flags, e.g. -r -x -a -A. None of the flags have arguments. flags = [] n = len(suffix_words) i = 1 while i < n: w = suffix_words[i] ok, static_val, quoted = word.StaticEval(w) if not ok or quoted: break # can't statically evaluate if static_val.startswith('-'): flags.append(static_val) else: break # not a flag, rest are args i += 1 # Now parse bindings or variable names assignments = [] while i < n: w = suffix_words[i] left_spid = word.LeftMostSpanForWord(w) kov = word.LooksLikeAssignment(w) if kov: k, op, v = kov t = word.TildeDetect(v) if t: # t is an unevaluated word with TildeSubPart a = (k, op, t, left_spid) else: a = (k, op, v, left_spid) # v is unevaluated word else: # In aboriginal in variables/sources: export_if_blank does export "$1". # We should allow that. # Parse this differently then? # dynamic-export? # It sets global variables. ok, static_val, quoted = word.StaticEval(w) if not ok or quoted: self.AddErrorContext( 'Variable names must be constant strings, got %s', w, word=w) return None # No value is equivalent to '' m = VAR_NAME_RE.match(static_val) if not m: self.AddErrorContext('Invalid variable name %r', static_val, word=w) return None a = (static_val, assign_op_e.Equal, None, left_spid) assignments.append(a) i += 1 # TODO: Also make with LhsIndexedName pairs = [] for lhs, op, rhs, spid in assignments: p = ast.assign_pair(ast.LhsName(lhs), op, rhs) p.spids.append(spid) pairs.append(p) node = ast.Assignment(assign_kw, flags, pairs) return node