예제 #1
0
    def _Atom(self, children):
        # type: (List[PNode]) -> expr_t
        """Handles alternatives of 'atom' where there is more than one child."""

        tok = children[0].tok
        id_ = tok.id
        n = len(children)

        if id_ == Id.Op_LParen:
            # atom: '(' [yield_expr|testlist_comp] ')' | ...
            if n == 2:  # () is a tuple
                assert children[1].tok.id == Id.Op_RParen, children[1]
                return expr.Tuple([], expr_context_e.Store)

            return self._TestlistComp(children[1], id_)

        if id_ == Id.Op_LBracket:
            # atom: ... | '[' [testlist_comp] ']' | ...

            if n == 2:  # []
                assert children[1].tok.id == Id.Op_RBracket, children[1]
                return expr.List([],
                                 expr_context_e.Store)  # unused expr_context_e

            return self._TestlistComp(children[1], id_)

        if id_ == Id.Op_LBrace:
            # atom: ... | '{' [Op_Newline] [dict] '}'
            i = 1
            if children[i].tok.id == Id.Op_Newline:
                i += 1
            return self._Dict(children[i])

        if id_ == Id.Arith_Slash:
            r = self._Regex(children[1])
            flags = []  # type: List[Token]
            # TODO: Parse translation preference.
            trans_pref = None  # type: Token
            return expr.RegexLiteral(children[0].tok, r, flags, trans_pref)

        if id_ == Id.Expr_Func:
            # STUB.  This should really be a Func, not Lambda.
            return expr.Lambda([], expr.Implicit())

        raise NotImplementedError(Id_str(id_))
예제 #2
0
파일: expr_to_ast.py 프로젝트: grahamc/oil
  def Expr(self, pnode):
    # type: (PNode) -> expr_t
    """Transform expressions (as opposed to statements)."""
    typ = pnode.typ
    tok = pnode.tok
    children = pnode.children

    if ISNONTERMINAL(typ):

      #
      # Oil Entry Points / Additions
      #

      if typ == grammar_nt.oil_expr:  # for if/while
        # oil_expr: '(' testlist ')'
        return self.Expr(children[1])

      if typ == grammar_nt.command_expr:
        # return_expr: testlist end_stmt
        return self.Expr(children[0])

      #
      # Python-like Expressions / Operators
      #

      if typ == grammar_nt.atom:
        if len(children) == 1:
          return self.Expr(children[0])
        return self._Atom(children)

      if typ == grammar_nt.testlist:
        # testlist: test (',' test)* [',']
        return self._Tuple(children)

      if typ == grammar_nt.test:
        # test: or_test ['if' or_test 'else' test] | lambdef
        if len(children) == 1:
          return self.Expr(children[0])

        # TODO: Handle lambdef

        test = self.Expr(children[2])
        body = self.Expr(children[0])
        orelse = self.Expr(children[4])
        return expr.IfExp(test, body, orelse)

      if typ == grammar_nt.lambdef:
        # lambdef: '|' [name_type_list] '|' test

        n = len(children)
        if n == 4:
          params = self._NameTypeList(children[1])
        else:
          params = []

        body = self.Expr(children[n-1])
        return expr.Lambda(params, body)

      #
      # Operators with Precedence
      #

      if typ == grammar_nt.or_test:
        # or_test: and_test ('or' and_test)*
        return self._AssocBinary(children)

      if typ == grammar_nt.and_test:
        # and_test: not_test ('and' not_test)*
        return self._AssocBinary(children)

      if typ == grammar_nt.not_test:
        # not_test: 'not' not_test | comparison
        if len(children) == 1:
          return self.Expr(children[0])

        op_tok = children[0].tok  # not
        return expr.Unary(op_tok, self.Expr(children[1]))

      elif typ == grammar_nt.comparison:
        if len(children) == 1:
          return self.Expr(children[0])

        return self._CompareChain(children)

      elif typ == grammar_nt.range_expr:
        n = len(children)
        if n == 1:
          return self.Expr(children[0])

        if n == 3:
          return expr.Range(
              self.Expr(children[0]),
              self.Expr(children[2])
          )

        raise AssertionError(n)

      elif typ == grammar_nt.expr:
        # expr: xor_expr ('|' xor_expr)*
        return self._AssocBinary(children)

      if typ == grammar_nt.xor_expr:
        # xor_expr: and_expr ('xor' and_expr)*
        return self._AssocBinary(children)

      if typ == grammar_nt.and_expr:  # a & b
        # and_expr: shift_expr ('&' shift_expr)*
        return self._AssocBinary(children)

      elif typ == grammar_nt.shift_expr:
        # shift_expr: arith_expr (('<<'|'>>') arith_expr)*
        return self._AssocBinary(children)

      elif typ == grammar_nt.arith_expr:
        # arith_expr: term (('+'|'-') term)*
        return self._AssocBinary(children)

      elif typ == grammar_nt.term:
        # term: factor (('*'|'/'|'div'|'mod') factor)*
        return self._AssocBinary(children)

      elif typ == grammar_nt.factor:
        # factor: ('+'|'-'|'~') factor | power
        # the power would have already been reduced
        if len(children) == 1:
          return self.Expr(children[0])

        assert len(children) == 2
        op = children[0]
        e = children[1]

        assert isinstance(op.tok, Token)
        return expr.Unary(op.tok, self.Expr(e))

      elif typ == grammar_nt.power:
        # power: atom trailer* ['^' factor]

        node = self.Expr(children[0])
        if len(children) == 1:  # No trailers
          return node

        n = len(children)
        i = 1
        while i < n and ISNONTERMINAL(children[i].typ):
          node = self._Trailer(node, children[i])
          i += 1

        if i != n:  # ['^' factor]
          op_tok = children[i].tok
          assert op_tok.id == Id.Arith_Caret, op_tok
          factor = self.Expr(children[i+1])
          node = expr.Binary(op_tok, node, factor)

        return node

      elif typ == grammar_nt.array_literal:
        left_tok = children[0].tok

        items = [self._ArrayItem(p) for p in children[1:-1]]
        return expr.ArrayLiteral(left_tok, items)

      elif typ == grammar_nt.oil_expr_sub:
        return self.Expr(children[0])

      #
      # Oil Lexer Modes
      #

      elif typ == grammar_nt.sh_array_literal:
        return cast(sh_array_literal, children[1].tok)

      elif typ == grammar_nt.sh_command_sub:
        return cast(command_sub, children[1].tok)

      elif typ == grammar_nt.braced_var_sub:
        return cast(braced_var_sub, children[1].tok)

      elif typ == grammar_nt.dq_string:
        return cast(double_quoted, children[1].tok)

      elif typ == grammar_nt.sq_string:
        return cast(single_quoted, children[1].tok)

      elif typ == grammar_nt.simple_var_sub:
        return simple_var_sub(children[0].tok)

      else:
        nt_name = self.number2symbol[typ]
        raise AssertionError(
            "PNode type %d (%s) wasn't handled" % (typ, nt_name))

    else:  # Terminals should have a token
      id_ = tok.id

      if id_ == Id.Expr_Name:
        return expr.Var(tok)

      if id_ in (
          Id.Expr_DecInt, Id.Expr_BinInt, Id.Expr_OctInt, Id.Expr_HexInt,
          Id.Expr_Float):
        return expr.Const(tok)

      if id_ in (Id.Expr_Null, Id.Expr_True, Id.Expr_False):
        return expr.Const(tok)

      raise NotImplementedError(Id_str(id_))