| 1 | """
 | 
| 2 | ir_pass.py - Translate (eventually) the mypy AST into our own IR.
 | 
| 3 | """
 | 
| 4 | from typing import Dict
 | 
| 5 | 
 | 
| 6 | import mypy
 | 
| 7 | from mypy.nodes import Expression, NameExpr
 | 
| 8 | from mypy.types import Type
 | 
| 9 | 
 | 
| 10 | from mycpp.util import split_py_name
 | 
| 11 | from mycpp.visitor import SimpleVisitor, T
 | 
| 12 | from mycpp import util
 | 
| 13 | from mycpp import pass_state
 | 
| 14 | 
 | 
| 15 | 
 | 
| 16 | class UnsupportedException(Exception):
 | 
| 17 |     pass
 | 
| 18 | 
 | 
| 19 | 
 | 
| 20 | class Build(SimpleVisitor):
 | 
| 21 | 
 | 
| 22 |     def __init__(self, types: Dict[Expression, Type]):
 | 
| 23 | 
 | 
| 24 |         self.types = types
 | 
| 25 |         self.dot_exprs = {}
 | 
| 26 | 
 | 
| 27 |         self.imported_names = set()  # MemberExpr -> module::Foo() or self->foo
 | 
| 28 |         # HACK for conditional import inside mylib.PYTHON
 | 
| 29 |         # in core/shell.py
 | 
| 30 |         self.imported_names.add('help_meta')
 | 
| 31 | 
 | 
| 32 |     # Statements
 | 
| 33 | 
 | 
| 34 |     def visit_import(self, o: 'mypy.nodes.Import') -> T:
 | 
| 35 |         for name, as_name in o.ids:
 | 
| 36 |             if as_name is not None:
 | 
| 37 |                 # import time as time_
 | 
| 38 |                 self.imported_names.add(as_name)
 | 
| 39 |             else:
 | 
| 40 |                 # import libc
 | 
| 41 |                 self.imported_names.add(name)
 | 
| 42 | 
 | 
| 43 |     def visit_import_from(self, o: 'mypy.nodes.ImportFrom') -> T:
 | 
| 44 |         """
 | 
| 45 |         Write C++ namespace aliases and 'using' for imports.
 | 
| 46 |         We need them in the 'decl' phase for default arguments like
 | 
| 47 |         runtime_asdl::scope_e -> scope_e
 | 
| 48 |         """
 | 
| 49 |         # For MemberExpr . -> module::func() or this->field.  Also needed in
 | 
| 50 |         # the decl phase for default arg values.
 | 
| 51 |         for name, alias in o.names:
 | 
| 52 |             if alias:
 | 
| 53 |                 self.imported_names.add(alias)
 | 
| 54 |             else:
 | 
| 55 |                 self.imported_names.add(name)
 | 
| 56 | 
 | 
| 57 |     # Expressions
 | 
| 58 | 
 | 
| 59 |     def visit_member_expr(self, o: 'mypy.nodes.MemberExpr') -> T:
 | 
| 60 |         # Why do we not get some of the types?  e.g. hnode.Record in asdl/runtime
 | 
| 61 |         # But this might suffice for the "Str_v" and "value_v" refactoring.
 | 
| 62 |         # We want to rewrite w.parts not to w->parts, but to w.parts() (method call)
 | 
| 63 | 
 | 
| 64 |         is_small_str = False
 | 
| 65 |         if util.SMALL_STR:
 | 
| 66 |             lhs_type = self.types.get(o.expr)
 | 
| 67 |             if util.IsStr(lhs_type):
 | 
| 68 |                 is_small_str = True
 | 
| 69 |             else:
 | 
| 70 |                 #self.log('NOT a string %s %s', o.expr, o.name)
 | 
| 71 |                 pass
 | 
| 72 |             """
 | 
| 73 |             if lhs_type is not None and isinstance(lhs_type, Instance):
 | 
| 74 |                 self.log('lhs_type %s expr %s name %s',
 | 
| 75 |                          lhs_type.type.fullname, o.expr, o.name)
 | 
| 76 | 
 | 
| 77 |              """
 | 
| 78 | 
 | 
| 79 |         is_asdl = o.name == 'CreateNull'  # hack for MyType.CreateNull(alloc_lists=True)
 | 
| 80 |         is_module = (isinstance(o.expr, NameExpr) and
 | 
| 81 |                      o.expr.name in self.imported_names)
 | 
| 82 | 
 | 
| 83 |         # This is an approximate hack that assumes that locals don't shadow
 | 
| 84 |         # imported names.  Might be a problem with names like 'word'?
 | 
| 85 |         if is_small_str:
 | 
| 86 |             self.dot_exprs[o] = pass_state.StackObjectMember(
 | 
| 87 |                 o.expr, self.types[o.expr], o.name)
 | 
| 88 |         elif is_asdl:
 | 
| 89 |             self.dot_exprs[o] = pass_state.StaticObjectMember(
 | 
| 90 |                 self.types[o].ret_type.type.fullname, o.name)
 | 
| 91 |         elif is_module:
 | 
| 92 |             self.dot_exprs[o] = pass_state.ModuleMember(
 | 
| 93 |                 split_py_name(o.expr.fullname or o.expr.name), o.name)
 | 
| 94 | 
 | 
| 95 |         else:
 | 
| 96 |             self.dot_exprs[o] = pass_state.HeapObjectMember(
 | 
| 97 |                 o.expr, self.types[o.expr], o.name)
 | 
| 98 | 
 | 
| 99 |         self.accept(o.expr)
 |