| 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.get(o.expr), o.name)
|
| 98 |
|
| 99 | self.accept(o.expr)
|