def _TestlistComp(self, p_node, id0): # type: (PNode, Id_t) -> expr_t """ testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) """ assert p_node.typ == grammar_nt.testlist_comp children = p_node.children n = len(children) if n > 1 and children[1].typ == grammar_nt.comp_for: elt = self.Expr(children[0]) comp = self._CompFor(children[1]) if id0 == Id.Op_LParen: return expr.GeneratorExp(elt, [comp]) if id0 == Id.Op_LBracket: return expr.ListComp(elt, [comp]) raise AssertionError() if id0 == Id.Op_LParen: if len(children) == 1: # parenthesized expression like (x+1) or (x) return self.Expr(children[0]) # (1,) (1, 2) etc. if children[1].tok.id == Id.Arith_Comma: return self._Tuple(children) raise NotImplementedError('testlist_comp') if id0 == Id.Op_LBracket: elts = [] # type: List[expr_t] for i in xrange(0, n, 2): # skip commas elts.append(self.Expr(children[i])) return expr.List(elts, expr_context_e.Store) # unused expr_context_e raise AssertionError(Id_str(id0))
def atom(self, children): # type: (List[PNode]) -> expr_t """Handles alternatives of 'atom' where there is more than one child.""" id_ = children[0].tok.id if id_ == Id.Op_LParen: # atom: '(' [yield_expr|testlist_comp] ')' | ... return self.Expr(children[1]) if id_ == Id.Op_LBracket: # atom: ... | '[' [testlist_comp] ']' | ... if len(children) == 2: # [] return expr.List([], expr_context_e.Store) # unused expr_context_e p_list = children[1].children # what's between [ and ] # [x for x in y] if len(p_list) == 2 and p_list[1].typ == grammar_nt.sync_comp_for: elt = self.Expr(p_list[0]) # TODO: transform 'for', 'if', etc. return expr.ListComp(elt, []) # [1, 2, 3] n = len(p_list) elts = [] for i in xrange(0, n, 2): # skip commas p_node = p_list[i] elts.append(self.Expr(p_node)) return expr.List(elts, expr_context_e.Store) # unused expr_context_e raise NotImplementedError
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.return_expr: # return_expr: testlist end_stmt return self.Expr(children[0]) if typ == grammar_nt.place_list: return self._AssocBinary(children) if typ == grammar_nt.place: # place: NAME place_trailer* if len(pnode.children) == 1: return self.Expr(pnode.children[0]) # TODO: Called _Trailer but don't handle ( )? # only [] . -> :: ? raise NotImplementedError # # 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)* [','] # We need tuples for Python's 'var a, b = x' and 'for (a, b in x) {' 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.test_nocond: # test_nocond: or_test | lambdef_nocond assert len(children) == 1 return self.Expr(children[0]) if typ == grammar_nt.argument: # argument: ( test [comp_for] | # test '=' test | # '**' test | # '*' test ) if len(pnode.children) == 1: return self.Expr(children[0]) # TODO: raise NotImplementedError if typ == grammar_nt.subscript: # subscript: test | [test] ':' [test] [sliceop] if len(pnode.children) == 1: return self.Expr(children[0]) # TODO: raise NotImplementedError if typ == grammar_nt.testlist_comp: # testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) if children[1].typ == grammar_nt.comp_for: elt = self.Expr(children[0]) comp = self._CompFor(children[1]) return expr.ListComp(elt, [comp]) # (1,) (1, 2) etc. if children[1].tok.id == Id.Arith_Comma: return self._Tuple(children) raise NotImplementedError('testlist_comp') elif typ == grammar_nt.exprlist: # exprlist: (expr|star_expr) (',' (expr|star_expr))* [','] if len(children) == 1: return self.Expr(children[0]) # used in for loop, genexpr. # TODO: This sould be placelist? for x, *y ? raise NotImplementedError('exprlist') # # 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.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]) op, e = children 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 # # Oil Lexer Modes # elif typ == grammar_nt.array_literal: left_tok = children[0].tok # Approximation for now. tokens = [ pnode.tok for pnode in children[1:-1] if pnode.tok.id == Id.Lit_Chars ] items = [expr.Const(t) for t in tokens] # type: List[expr_t] return expr.ArrayLiteral(left_tok, items) elif typ == grammar_nt.sh_array_literal: left_tok = children[0].tok # HACK: When typ is Id.Expr_CastedDummy, the 'tok' field ('opaque') # actually has a list of words! typ1 = children[1].typ assert typ1 == Id.Expr_CastedDummy.enum_id, typ1 array_words = cast('List[word_t]', children[1].tok) return sh_array_literal(left_tok, array_words) 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) from core.meta import IdInstance raise NotImplementedError(IdInstance(typ))