def TildeDetectAssign(w): # type: (compound_word) -> None """MUTATES its argument.""" parts = w.parts n = len(parts) parts.append(None) # sentinel do_expand = True for i in xrange(n): cur = parts[i] # Replace with tilde sub if do_expand and LiteralId(cur) == Id.Lit_TildeLike: next_part = parts[i + 1] if next_part: is_tilde = (LiteralId(next_part) == Id.Lit_Colon or (LiteralId(next_part) == Id.Lit_Chars and cast(Token, next_part).val.startswith('/'))) else: is_tilde = True # you can expand :~ if is_tilde: parts[i] = word_part.TildeSub(cast(Token, cur)) # For next iteration do_expand = LiteralId(cur) == Id.Lit_Colon parts.pop() # remove sentinel
def TildeDetect(UP_w): # type: (word_t) -> Optional[compound_word] """Detect tilde expansion in a word. It might begin with Literal that needs to be turned into a TildeSub. (It depends on whether the second token begins with slash). If so, it return a new word. Otherwise return None. NOTE: - The regex for Lit_TildeLike could be expanded. Right now it's conservative, like Lit_Chars without the /. - It's possible to write this in a mutating style, since only the first token is changed. But note that we CANNOT know this during lexing. """ # NOTE: BracedTree, Empty, etc. can't be tilde expanded if UP_w.tag_() != word_e.Compound: return None w = cast(compound_word, UP_w) assert w.parts, w UP_part0 = w.parts[0] if _LiteralId(UP_part0) != Id.Lit_TildeLike: return None tok0 = cast(Token, UP_part0) if len(w.parts) == 1: # can't be zero tilde_part = word_part.TildeSub(tok0) return compound_word([tilde_part]) UP_part1 = w.parts[1] # NOTE: We could inspect the raw tokens. if _LiteralId(UP_part1) == Id.Lit_Chars: tok = cast(Token, UP_part1) if tok.val.startswith('/'): tilde_part_ = word_part.TildeSub(tok0) # type: word_part_t parts = [tilde_part_] parts.extend(w.parts[1:]) return compound_word(parts) # It could be something like '~foo:bar', which doesn't have a slash. return None
def TildeDetect(w): # type: (word_t) -> Optional[word_t] """Detect tilde expansion in a word. It might begin with Literal that needs to be turned into a TildeSub. (It depends on whether the second token begins with slash). If so, it return a new word. Otherwise return None. NOTE: - The regex for Lit_TildeLike could be expanded. Right now it's conservative, like Lit_Chars without the /. - It's possible to write this in a mutating style, since only the first token is changed. But note that we CANNOT know this during lexing. """ # NOTE: BracedTree, Empty, etc. can't be tilde expanded if not isinstance(w, word__Compound): return None assert w.parts, w part0 = w.parts[0] if _LiteralId(part0) != Id.Lit_TildeLike: return None assert isinstance(part0, word_part__Literal) # for MyPy if len(w.parts) == 1: # can't be zero tilde_part = word_part.TildeSub(part0.token) return word.Compound([tilde_part]) part1 = w.parts[1] # NOTE: We could inspect the raw tokens. if _LiteralId(part1) == Id.Lit_Chars: assert isinstance(part1, word_part__Literal) # for MyPy if part1.token.val.startswith('/'): tilde_part_ = word_part.TildeSub(part0.token) # type: word_part_t return word.Compound([tilde_part_] + w.parts[1:]) # It could be something like '~foo:bar', which doesn't have a slash. return None
def TildeDetect(UP_w): # type: (word_t) -> Optional[compound_word] """Detect tilde expansion in a word. It might begin with Literal that needs to be turned into a TildeSub. (It depends on whether the second token begins with slash). If so, it return a new word. Otherwise return None. NOTE: - The regex for Lit_TildeLike could be expanded. Right now it's conservative, like Lit_Chars without the /. - It's possible to write this in a mutating style, since only the first token is changed. But note that we CANNOT know this during lexing. """ # NOTE: BracedTree, Empty, etc. can't be tilde expanded if UP_w.tag_() != word_e.Compound: return None w = cast(compound_word, UP_w) if len(w.parts) == 0: # ${a-} has no parts return None part0 = w.parts[0] if LiteralId(part0) != Id.Lit_TildeLike: return None tok0 = cast(Token, part0) new_parts = [word_part.TildeSub(tok0)] # type: List[word_part_t] if len(w.parts) == 1: # can't be zero return compound_word(new_parts) part1 = w.parts[1] id_ = LiteralId(part1) # Lit_Slash is for ${x-~/foo} if id_ == Id.Lit_Slash: # we handled ${x//~/} delimiter earlier, new_parts.extend(w.parts[1:]) return compound_word(new_parts) # Lit_Chars is for ~/foo, if id_ == Id.Lit_Chars and cast(Token, part1).val.startswith('/'): new_parts.extend(w.parts[1:]) return compound_word(new_parts) # It could be something like '~foo:bar', which doesn't have a slash. return None