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)
|