예제 #1
0
    def _ReadCompoundWord(self,
                          eof_type=Id.Undefined_Tok,
                          lex_mode=LexMode.OUTER,
                          empty_ok=True):
        """
    Precondition: Looking at the first token of the first word part
    Postcondition: Looking at the token after, e.g. space or operator
    """
        #print('_ReadCompoundWord', lex_mode)
        word = ast.CompoundWord()

        num_parts = 0
        done = False
        while not done:
            allow_done = empty_ok or num_parts != 0
            self._Peek()
            #print('CW',self.cur_token)
            if allow_done and self.token_type == eof_type:
                done = True  # e.g. for ${}

            # Keywords like "for" are treated like literals
            elif self.token_kind in (Kind.Lit, Kind.KW, Kind.Assign,
                                     Kind.ControlFlow, Kind.BoolUnary,
                                     Kind.BoolBinary):
                if self.token_type == Id.Lit_EscapedChar:
                    part = ast.EscapedLiteralPart(self.cur_token)
                else:
                    part = ast.LiteralPart(self.cur_token)
                    #part.xspans.append(self.cur_token.span_id)

                word.parts.append(part)

                if self.token_type == Id.Lit_VarLike:
                    #print('@', self.lexer.LookAhead())
                    #print('@', self.cursor)
                    #print('@', self.cur_token)

                    t = self.lexer.LookAhead(LexMode.OUTER)
                    if t.id == Id.Op_LParen:
                        self.lexer.PushHint(Id.Op_RParen,
                                            Id.Right_ArrayLiteral)
                        part2 = self._ReadArrayLiteralPart()
                        if not part2:
                            self.AddErrorContext(
                                '_ReadArrayLiteralPart failed')
                            return False
                        word.parts.append(part2)

            elif self.token_kind == Kind.VSub:
                part = ast.SimpleVarSub(self.cur_token)
                word.parts.append(part)

            elif self.token_kind == Kind.Left:
                #print('_ReadLeftParts')
                part = self._ReadLeftParts()
                if not part:
                    return None
                word.parts.append(part)

            # NOT done yet, will advance below
            elif self.token_kind == Kind.Right:
                # Still part of the word; will be done on the next iter.
                if self.token_type == Id.Right_DoubleQuote:
                    pass
                elif self.token_type == Id.Right_CommandSub:
                    pass
                elif self.token_type == Id.Right_Subshell:
                    # LEXER HACK for (case x in x) ;; esac )
                    assert self.next_lex_mode is None  # Rewind before it's used
                    if self.lexer.MaybeUnreadOne():
                        self.lexer.PushHint(Id.Op_RParen, Id.Right_Subshell)
                        self._Next(lex_mode)
                    done = True
                else:
                    done = True

            elif self.token_kind == Kind.Ignored:
                done = True

            else:
                # LEXER HACK for unbalanced case clause.  'case foo in esac' is valid,
                # so to test for ESAC, we can read ) before getting a chance to
                # PushHint(Id.Op_RParen, Id.Right_CasePat).  So here we unread one
                # token and do it again.

                # We get Id.Op_RParen at top level:      case x in x) ;; esac
                # We get Id.Eof_RParen inside ComSub:  $(case x in x) ;; esac )
                if self.token_type in (Id.Op_RParen, Id.Eof_RParen):
                    assert self.next_lex_mode is None  # Rewind before it's used
                    if self.lexer.MaybeUnreadOne():
                        if self.token_type == Id.Eof_RParen:
                            # Redo translation
                            self.lexer.PushHint(Id.Op_RParen, Id.Eof_RParen)
                        self._Next(lex_mode)

                done = True  # anything we don't recognize means we're done

            if not done:
                self._Next(lex_mode)
            num_parts += 1
        return word
예제 #2
0
    def _ReadDoubleQuotedPart(self, eof_type=Id.Undefined_Tok, here_doc=False):
        """
    Args:
      eof_type: for stopping at }, Id.Lit_RBrace
      here_doc: Whether we are reading in a here doc context

    Also ${foo%%a b c}  # treat this as double quoted.  until you hit
    """
        quoted_part = ast.DoubleQuotedPart()
        left_spid = -1
        right_spid = -1  # gets set later

        if self.cur_token is not None:  # None in here doc case
            left_spid = self.cur_token.span_id

        done = False
        while not done:
            self._Next(LexMode.DQ)
            self._Peek()
            #print(self.cur_token)

            if self.token_type == eof_type:  # e.g. stop at }
                done = True
                continue

            elif self.token_kind == Kind.Lit:
                if self.token_type == Id.Lit_EscapedChar:
                    part = ast.EscapedLiteralPart(self.cur_token)
                else:
                    part = ast.LiteralPart(self.cur_token)
                quoted_part.parts.append(part)

            elif self.token_kind == Kind.Left:
                part = self._ReadDoubleQuotedLeftParts()
                if not part:
                    return None
                quoted_part.parts.append(part)

            elif self.token_kind == Kind.VSub:
                part = ast.SimpleVarSub(self.cur_token)
                quoted_part.parts.append(part)

            elif self.token_kind == Kind.Right:
                assert self.token_type == Id.Right_DoubleQuote
                if here_doc:
                    # Turn Id.Right_DoubleQuote into a literal part
                    quoted_part.parts.append(ast.LiteralPart(self.cur_token))
                else:
                    done = True  # assume Id.Right_DoubleQuote
                    right_spid = self.cur_token.span_id

            elif self.token_kind == Kind.Eof:
                if here_doc:  # here docs will have an EOF in their token stream
                    done = True
                else:
                    self.AddErrorContext(
                        'Unexpected EOF in double-quoted string')
                    return False

            else:
                raise AssertionError(self.cur_token)

        quoted_part.spids.extend((left_spid, right_spid))
        return quoted_part