1 | """
|
2 | visitor.py - base class for all our tree traversals.
|
3 |
|
4 | It validates many nodes, i.e. presenting a subset of the MyPy AST to
|
5 | subclasses.
|
6 | """
|
7 | import mypy
|
8 | from mypy.visitor import ExpressionVisitor, StatementVisitor
|
9 | from mypy.nodes import (Expression, Statement, ExpressionStmt, StrExpr,
|
10 | CallExpr, YieldExpr, NameExpr, MemberExpr, Argument,
|
11 | ClassDef, FuncDef, IfStmt, PassStmt, ListComprehension)
|
12 | from mypy.types import Type
|
13 |
|
14 | from mycpp.crash import catch_errors
|
15 | from mycpp import util
|
16 | from mycpp.util import SplitPyName, log
|
17 |
|
18 | from typing import (overload, Any, Union, Optional, List, Dict, Tuple, TextIO)
|
19 |
|
20 | NAME_CONFLICTS = ('stdin', 'stdout', 'stderr')
|
21 |
|
22 |
|
23 | class SimpleVisitor(ExpressionVisitor[None], StatementVisitor[None]):
|
24 | """
|
25 | A simple AST visitor that accepts every node in the AST. Derrived classes
|
26 | can override the visit methods that are relevant to them.
|
27 | """
|
28 |
|
29 | def __init__(self) -> None:
|
30 | self.module_path: Optional[str] = None
|
31 |
|
32 | self.current_class_name: Optional[util.SymbolPath] = None
|
33 | self.current_method_name: Optional[str] = None
|
34 |
|
35 | # So we can report multiple at once
|
36 | # module path, line number, message
|
37 | self.errors_keep_going: List[Tuple[str, int, str]] = []
|
38 |
|
39 | self.at_global_scope = True
|
40 | self.indent = 0
|
41 | self.f: Optional[TextIO] = None
|
42 |
|
43 | def SetOutputFile(self, f: TextIO) -> None:
|
44 | self.f = f
|
45 |
|
46 | def log(self, msg: str, *args: Any) -> None:
|
47 | """Log to STDERR"""
|
48 | ind_str = self.indent * ' '
|
49 | log(ind_str + msg, *args)
|
50 |
|
51 | def write(self, msg: str, *args: Any) -> None:
|
52 | if args:
|
53 | msg = msg % args
|
54 | assert self.f is not None
|
55 | self.f.write(msg)
|
56 |
|
57 | def write_ind(self, msg: str, *args: Any) -> None:
|
58 | ind_str = self.indent * ' '
|
59 | self.write(ind_str + msg, *args)
|
60 |
|
61 | #
|
62 | # COPIED from mypyc IRBuilder
|
63 | #
|
64 |
|
65 | @overload
|
66 | def accept(self, node: Expression) -> None:
|
67 | ...
|
68 |
|
69 | @overload
|
70 | def accept(self, node: Statement) -> None:
|
71 | ...
|
72 |
|
73 | def accept(self, node: Union[Statement, Expression]) -> None:
|
74 | with catch_errors(self.module_path, node.line):
|
75 | if isinstance(node, Expression):
|
76 | node.accept(self)
|
77 | else:
|
78 | node.accept(self)
|
79 |
|
80 | #
|
81 | # Error API
|
82 | #
|
83 |
|
84 | def report_error(self, node: Union[Statement, Expression, Argument],
|
85 | msg: str) -> None:
|
86 | err = (self.module_path, node.line, msg)
|
87 | self.errors_keep_going.append(err)
|
88 |
|
89 | def not_translated(self, node: Union[Statement, Expression],
|
90 | name: str) -> None:
|
91 | self.report_error(node, '%s not translated' % name)
|
92 |
|
93 | def not_python2(self, node: Union[Statement, Expression],
|
94 | name: str) -> None:
|
95 | self.report_error(node, "%s: shouldn't get here in Python 2" % name)
|
96 |
|
97 | def oils_visit_mypy_file(self, o: 'mypy.nodes.MypyFile') -> None:
|
98 | for node in o.defs:
|
99 | self.accept(node)
|
100 |
|
101 | def visit_mypy_file(self, o: 'mypy.nodes.MypyFile') -> None:
|
102 | if util.ShouldSkipPyFile(o):
|
103 | return
|
104 |
|
105 | self.module_path = o.path
|
106 |
|
107 | self.oils_visit_mypy_file(o)
|
108 |
|
109 | # Now show errors for each file
|
110 | for path, line_num, msg in self.errors_keep_going:
|
111 | self.log('%s:%s %s', path, line_num, msg)
|
112 |
|
113 | def oils_visit_for_stmt(self, o: 'mypy.nodes.ForStmt',
|
114 | func_name: Optional[str]) -> None:
|
115 | self.accept(o.index) # index var expression
|
116 | self.accept(o.expr)
|
117 | self.accept(o.body)
|
118 | if o.else_body:
|
119 | raise AssertionError("can't translate for-else")
|
120 |
|
121 | def visit_for_stmt(self, o: 'mypy.nodes.ForStmt') -> None:
|
122 |
|
123 | func_name = None # does the loop look like 'for x in func():' ?
|
124 | if (isinstance(o.expr, CallExpr) and
|
125 | isinstance(o.expr.callee, NameExpr)):
|
126 | func_name = o.expr.callee.name
|
127 |
|
128 | # In addition to func_name, can we also pass
|
129 | # iterated_over
|
130 | # enumerate() reversed() iteritems() is o.expr[0]
|
131 | # otherwise it's o.expr
|
132 | # And then you get the type, and if it's typing.Iterator, then the
|
133 | # virtual pass can set self.yield_eager_for
|
134 |
|
135 | self.oils_visit_for_stmt(o, func_name)
|
136 |
|
137 | # TODO: validate and destructure the different kinds of loops
|
138 | #
|
139 | # xrange() - 1 index
|
140 | # xrange negative
|
141 | # enumerate() - 2 indices
|
142 | # reversed() - container - 1 index
|
143 | # iteritems() - dict, 2 indices
|
144 | #
|
145 | # - over list
|
146 | # - over dict - list comprehensions would need this too
|
147 | # - over iterator
|
148 | #
|
149 | # LHS
|
150 | # - NameExpr
|
151 | # - TupleExpr
|
152 | #
|
153 | # More destructuring:
|
154 | #
|
155 | # item_type - is it a Tuple?
|
156 | # enumerate - o.inferred_item_type[1]
|
157 | # otherwise (xrange, reversed, iteritems) - o.inferred_item_type
|
158 | #
|
159 | # elif isinstance(item_type, TupleType): # for x, y in pairs
|
160 | # if over_dict:
|
161 | # ...
|
162 | # else # it's a List
|
163 | # if isinstance(o.index, TupleExpr):
|
164 | # ...
|
165 | # self._write_tuple_unpacking(temp_name, o.index.items, item_type.items)
|
166 | #
|
167 | # We need to detect this
|
168 | # And then also detect it for list comprehensions
|
169 |
|
170 | # Two different tests:
|
171 | # for loop test
|
172 | # if isinstance(o.index, TupleExpr):
|
173 |
|
174 | def visit_with_stmt(self, o: 'mypy.nodes.WithStmt') -> None:
|
175 | assert len(o.expr) == 1, o.expr
|
176 | expr = o.expr[0]
|
177 | assert isinstance(expr, CallExpr), expr
|
178 | self.accept(expr)
|
179 | self.accept(o.body)
|
180 |
|
181 | def oils_visit_func_def(self, o: 'mypy.nodes.FuncDef') -> None:
|
182 | """Only the functions we care about in Oils."""
|
183 | for arg in o.arguments:
|
184 | if arg.initializer:
|
185 | self.accept(arg.initializer)
|
186 |
|
187 | self.accept(o.body)
|
188 |
|
189 | def visit_func_def(self, o: 'mypy.nodes.FuncDef') -> None:
|
190 | # This could be a free function or a method
|
191 | # __init__ __exit__ and other methods call this, with self.current_class_name set
|
192 |
|
193 | # If an assignment statement is not in a function or method, then it's at global scope
|
194 |
|
195 | self.at_global_scope = False
|
196 | self.oils_visit_func_def(o)
|
197 | self.at_global_scope = True
|
198 |
|
199 | #
|
200 | # Classes
|
201 | #
|
202 |
|
203 | def oils_visit_constructor(self, o: ClassDef, stmt: FuncDef,
|
204 | base_class_sym: util.SymbolPath) -> None:
|
205 | self.accept(stmt)
|
206 |
|
207 | def oils_visit_dunder_exit(self, o: ClassDef, stmt: FuncDef,
|
208 | base_class_sym: util.SymbolPath) -> None:
|
209 | self.accept(stmt)
|
210 |
|
211 | def oils_visit_method(self, o: ClassDef, stmt: FuncDef,
|
212 | base_class_sym: util.SymbolPath) -> None:
|
213 | self.accept(stmt)
|
214 |
|
215 | def oils_visit_class_members(self, o: ClassDef,
|
216 | base_class_sym: util.SymbolPath) -> None:
|
217 | """Hook for writing member vars."""
|
218 | # Do nothing by default.
|
219 | pass
|
220 |
|
221 | def oils_visit_class_def(
|
222 | self, o: 'mypy.nodes.ClassDef',
|
223 | base_class_sym: Optional[util.SymbolPath]) -> None:
|
224 |
|
225 | for stmt in o.defs.body:
|
226 | # Skip class docstrings
|
227 | if (isinstance(stmt, ExpressionStmt) and
|
228 | isinstance(stmt.expr, StrExpr)):
|
229 | continue
|
230 |
|
231 | # Skip empty classes
|
232 | if isinstance(stmt, PassStmt):
|
233 | continue
|
234 |
|
235 | if isinstance(stmt, FuncDef):
|
236 | method_name = stmt.name
|
237 |
|
238 | # Don't translate
|
239 | if method_name in ('__enter__', '__repr__'):
|
240 | continue
|
241 |
|
242 | if method_name == '__init__': # Don't translate
|
243 | self.current_method_name = stmt.name
|
244 | self.oils_visit_constructor(o, stmt, base_class_sym)
|
245 | self.current_method_name = None
|
246 | continue
|
247 |
|
248 | if method_name == '__exit__': # Don't translate
|
249 | self.current_method_name = stmt.name
|
250 | self.oils_visit_dunder_exit(o, stmt, base_class_sym)
|
251 | self.current_method_name = None
|
252 | continue
|
253 |
|
254 | self.current_method_name = stmt.name
|
255 | self.oils_visit_method(o, stmt, base_class_sym)
|
256 | self.current_method_name = None
|
257 | continue
|
258 |
|
259 | # if 0: is allowed
|
260 | if isinstance(stmt, IfStmt):
|
261 | self.accept(stmt)
|
262 | continue
|
263 |
|
264 | self.report_error(
|
265 | o, 'Classes may only have method definitions, got %s' % stmt)
|
266 |
|
267 | self.oils_visit_class_members(o, base_class_sym)
|
268 |
|
269 | def visit_class_def(self, o: 'mypy.nodes.ClassDef') -> None:
|
270 | base_class_sym = None # single inheritance only
|
271 | if len(o.base_type_exprs) > 1:
|
272 | self.report_error(o, 'too many base types: %s' % o.base_type_exprs)
|
273 | return
|
274 |
|
275 | for b in o.base_type_exprs:
|
276 | if isinstance(b, NameExpr):
|
277 | if b.name != 'object' and b.name != 'Exception':
|
278 | base_class_sym = SplitPyName(b.fullname)
|
279 | elif isinstance(b, MemberExpr): # vm._Executor -> vm::_Executor
|
280 | assert isinstance(b.expr, NameExpr), b
|
281 | base_class_sym = SplitPyName(b.expr.fullname) + (b.name, )
|
282 | else:
|
283 | # shouldn't happen
|
284 | raise AssertionError(b)
|
285 |
|
286 | self.current_class_name = SplitPyName(o.fullname)
|
287 | self.oils_visit_class_def(o, base_class_sym)
|
288 | self.current_class_name = None
|
289 |
|
290 | # Statements
|
291 |
|
292 | def oils_visit_assignment_stmt(self, o: 'mypy.nodes.AssignmentStmt',
|
293 | lval: Expression, rval: Expression) -> None:
|
294 | self.accept(lval)
|
295 | self.accept(rval)
|
296 |
|
297 | def visit_assignment_stmt(self, o: 'mypy.nodes.AssignmentStmt') -> None:
|
298 | # We never use this idiom: x = y = 42
|
299 | assert len(o.lvalues) == 1, o.lvalues
|
300 | lval = o.lvalues[0]
|
301 |
|
302 | # Metadata we'll never use
|
303 | if isinstance(lval, NameExpr):
|
304 | if lval.name == '__all__':
|
305 | return
|
306 |
|
307 | # Special case for
|
308 | if isinstance(o.rvalue, ListComprehension):
|
309 | self.visit_assign_to_listcomp(o, lval)
|
310 | return
|
311 |
|
312 | # TODO: virtual pass might want this
|
313 | # However it depends on TYPES. Right now the visitor doesn't depend on types
|
314 | # if (isinstance(rval_type, Instance) and
|
315 | # rval_type.type.fullname == 'typing.Iterator'):
|
316 | # self._AssignToGenerator(o, lval, rval_type)
|
317 | # return
|
318 | # Key reason it needs to be in the virtual pass is that signatures
|
319 | # must change to allow an out param.
|
320 |
|
321 | self.oils_visit_assignment_stmt(o, lval, o.rvalue)
|
322 |
|
323 | def visit_operator_assignment_stmt(
|
324 | self, o: 'mypy.nodes.OperatorAssignmentStmt') -> None:
|
325 | self.accept(o.lvalue)
|
326 | self.accept(o.rvalue)
|
327 |
|
328 | def visit_block(self, block: 'mypy.nodes.Block') -> None:
|
329 | for stmt in block.body:
|
330 | self.accept(stmt)
|
331 |
|
332 | def oils_visit_expression_stmt(self,
|
333 | o: 'mypy.nodes.ExpressionStmt') -> None:
|
334 | self.accept(o.expr)
|
335 |
|
336 | def visit_expression_stmt(self, o: 'mypy.nodes.ExpressionStmt') -> None:
|
337 | # Ignore all docstrings: module, class, and function body
|
338 | if isinstance(o.expr, StrExpr):
|
339 | return
|
340 |
|
341 | # Either f() or obj.method()
|
342 | assert isinstance(o.expr, (CallExpr, YieldExpr)), o.expr
|
343 |
|
344 | self.oils_visit_expression_stmt(o)
|
345 |
|
346 | def visit_while_stmt(self, o: 'mypy.nodes.WhileStmt') -> None:
|
347 | self.accept(o.expr)
|
348 | self.accept(o.body)
|
349 |
|
350 | def visit_return_stmt(self, o: 'mypy.nodes.ReturnStmt') -> None:
|
351 | if o.expr:
|
352 | self.accept(o.expr)
|
353 |
|
354 | def visit_if_stmt(self, o: 'mypy.nodes.IfStmt') -> None:
|
355 | if util.ShouldVisitIfExpr(o):
|
356 | for expr in o.expr:
|
357 | self.accept(expr)
|
358 |
|
359 | if util.ShouldVisitIfBody(o):
|
360 | for body in o.body:
|
361 | self.accept(body)
|
362 |
|
363 | if util.ShouldVisitElseBody(o):
|
364 | self.accept(o.else_body)
|
365 |
|
366 | def visit_raise_stmt(self, o: 'mypy.nodes.RaiseStmt') -> None:
|
367 | if o.expr:
|
368 | self.accept(o.expr)
|
369 |
|
370 | def visit_try_stmt(self, o: 'mypy.nodes.TryStmt') -> None:
|
371 | self.accept(o.body)
|
372 | for handler in o.handlers:
|
373 | self.accept(handler)
|
374 |
|
375 | def visit_del_stmt(self, o: 'mypy.nodes.DelStmt') -> None:
|
376 | self.accept(o.expr)
|
377 |
|
378 | # Expressions
|
379 |
|
380 | def visit_generator_expr(self, o: 'mypy.nodes.GeneratorExpr') -> None:
|
381 | raise AssertionError()
|
382 |
|
383 | self.accept(o.left_expr)
|
384 |
|
385 | for expr in o.indices:
|
386 | self.accept(expr)
|
387 |
|
388 | for expr in o.sequences:
|
389 | self.accept(expr)
|
390 |
|
391 | for l in o.condlists:
|
392 | for expr in l:
|
393 | self.accept(expr)
|
394 |
|
395 | def visit_list_comprehension(self,
|
396 | o: 'mypy.nodes.ListComprehension') -> None:
|
397 | # old code
|
398 | #self.accept(o.generator)
|
399 | self.report_error(o,
|
400 | 'List comprehension must be assigned to a temp var')
|
401 |
|
402 | def oils_visit_assign_to_listcomp(self, lval: NameExpr,
|
403 | left_expr: Expression,
|
404 | index_expr: Expression, seq: Expression,
|
405 | cond: Expression) -> None:
|
406 | self.accept(lval)
|
407 | self.accept(left_expr)
|
408 | self.accept(index_expr)
|
409 | self.accept(seq)
|
410 | if cond is not None:
|
411 | self.accept(cond)
|
412 |
|
413 | def visit_assign_to_listcomp(self, o: 'mypy.nodes.AssignmentStmt',
|
414 | lval: NameExpr) -> None:
|
415 | gen = o.rvalue.generator # GeneratorExpr
|
416 |
|
417 | if (len(gen.indices) != 1 or len(gen.sequences) != 1 or
|
418 | len(gen.condlists) != 1):
|
419 | self.report_error(o, 'List comprehensions can only have one loop')
|
420 |
|
421 | index_expr = gen.indices[0]
|
422 | seq = gen.sequences[0]
|
423 | condlist = gen.condlists[0]
|
424 |
|
425 | if len(condlist) == 0:
|
426 | cond: Optional[Expression] = None
|
427 | elif len(condlist) == 1:
|
428 | cond = condlist[0]
|
429 | else:
|
430 | self.report_error(
|
431 | o, 'List comprehensions may have at most one condition')
|
432 |
|
433 | self.oils_visit_assign_to_listcomp(lval, gen.left_expr, index_expr,
|
434 | seq, cond)
|
435 |
|
436 | def visit_yield_expr(self, o: 'mypy.nodes.YieldExpr') -> None:
|
437 | self.accept(o.expr)
|
438 |
|
439 | def visit_op_expr(self, o: 'mypy.nodes.OpExpr') -> None:
|
440 | self.accept(o.left)
|
441 | self.accept(o.right)
|
442 |
|
443 | def visit_comparison_expr(self, o: 'mypy.nodes.ComparisonExpr') -> None:
|
444 | for operand in o.operands:
|
445 | self.accept(operand)
|
446 |
|
447 | def visit_unary_expr(self, o: 'mypy.nodes.UnaryExpr') -> None:
|
448 | # e.g. -42 or 'not x'
|
449 | self.accept(o.expr)
|
450 |
|
451 | def visit_list_expr(self, o: 'mypy.nodes.ListExpr') -> None:
|
452 | for item in o.items:
|
453 | self.accept(item)
|
454 |
|
455 | def visit_dict_expr(self, o: 'mypy.nodes.DictExpr') -> None:
|
456 | for k, v in o.items:
|
457 | self.accept(k)
|
458 | self.accept(v)
|
459 |
|
460 | def visit_tuple_expr(self, o: 'mypy.nodes.TupleExpr') -> None:
|
461 | for item in o.items:
|
462 | self.accept(item)
|
463 |
|
464 | def visit_index_expr(self, o: 'mypy.nodes.IndexExpr') -> None:
|
465 | self.accept(o.base)
|
466 | self.accept(o.index)
|
467 |
|
468 | def visit_slice_expr(self, o: 'mypy.nodes.SliceExpr') -> None:
|
469 | if o.begin_index:
|
470 | self.accept(o.begin_index)
|
471 |
|
472 | if o.end_index:
|
473 | self.accept(o.end_index)
|
474 |
|
475 | if o.stride:
|
476 | self.accept(o.stride)
|
477 |
|
478 | def visit_conditional_expr(self, o: 'mypy.nodes.ConditionalExpr') -> None:
|
479 | self.accept(o.cond)
|
480 | self.accept(o.if_expr)
|
481 | self.accept(o.else_expr)
|
482 |
|
483 | def oils_visit_log_call(self, fmt: StrExpr,
|
484 | args: List[Expression]) -> None:
|
485 | self.accept(fmt)
|
486 | for arg in args:
|
487 | self.accept(arg)
|
488 |
|
489 | def oils_visit_probe_call(self, o: 'mypy.nodes.CallExpr') -> None:
|
490 | self.accept(o.callee)
|
491 | for arg in o.args:
|
492 | self.accept(arg)
|
493 |
|
494 | def oils_visit_call_expr(self, o: 'mypy.nodes.CallExpr') -> None:
|
495 | self.accept(o.callee)
|
496 | for arg in o.args:
|
497 | self.accept(arg)
|
498 |
|
499 | def visit_call_expr(self, o: 'mypy.nodes.CallExpr') -> None:
|
500 | # Oils invariant: check that it'fs () or obj.method()
|
501 | assert isinstance(o.callee, (NameExpr, MemberExpr)), o.callee
|
502 |
|
503 | if isinstance(o.callee, NameExpr):
|
504 | callee_name = o.callee.name
|
505 |
|
506 | if callee_name == 'isinstance':
|
507 | self.report_error(o, 'isinstance() not allowed')
|
508 | return
|
509 |
|
510 | if callee_name == 'log':
|
511 | # Special printf-style varargs:
|
512 | #
|
513 | # log('foo %s', x)
|
514 | # =>
|
515 | # log(StrFormat('foo %s', x))
|
516 |
|
517 | args = o.args
|
518 | assert len(args) > 0, o
|
519 | assert isinstance(args[0], StrExpr), args[0]
|
520 | fmt = args[0]
|
521 |
|
522 | self.oils_visit_log_call(fmt, args[1:])
|
523 | return
|
524 |
|
525 | if callee_name == 'probe':
|
526 | # DTRACE_PROBE()
|
527 | self.oils_visit_probe_call(o)
|
528 | return
|
529 |
|
530 | self.oils_visit_call_expr(o)
|
531 |
|
532 | #
|
533 | # Leaf Statements and Expressions that do nothing
|
534 | #
|
535 |
|
536 | def visit_int_expr(self, o: 'mypy.nodes.IntExpr') -> None:
|
537 | pass
|
538 |
|
539 | def visit_float_expr(self, o: 'mypy.nodes.FloatExpr') -> None:
|
540 | pass
|
541 |
|
542 | def visit_str_expr(self, o: 'mypy.nodes.StrExpr') -> None:
|
543 | pass
|
544 |
|
545 | def visit_break_stmt(self, o: 'mypy.nodes.BreakStmt') -> None:
|
546 | pass
|
547 |
|
548 | def visit_continue_stmt(self, o: 'mypy.nodes.ContinueStmt') -> None:
|
549 | pass
|
550 |
|
551 | def visit_pass_stmt(self, o: 'mypy.nodes.PassStmt') -> None:
|
552 | pass
|
553 |
|
554 | def visit_import(self, o: 'mypy.nodes.Import') -> None:
|
555 | pass
|
556 |
|
557 | def visit_import_from(self, o: 'mypy.nodes.ImportFrom') -> None:
|
558 | pass
|
559 |
|
560 | def oils_visit_name_expr(self, o: 'mypy.nodes.NameExpr') -> None:
|
561 | pass
|
562 |
|
563 | def visit_name_expr(self, o: 'mypy.nodes.NameExpr') -> None:
|
564 | if o.name in NAME_CONFLICTS:
|
565 | self.report_error(
|
566 | o,
|
567 | "The name %r conflicts with C macros on some platforms; choose a different name"
|
568 | % o.name)
|
569 | return
|
570 |
|
571 | self.oils_visit_name_expr(o)
|
572 |
|
573 | def oils_visit_member_expr(self, o: 'mypy.nodes.MemberExpr') -> None:
|
574 | self.accept(o.expr)
|
575 |
|
576 | def visit_member_expr(self, o: 'mypy.nodes.MemberExpr') -> None:
|
577 | if o.name in NAME_CONFLICTS:
|
578 | self.report_error(
|
579 | o,
|
580 | "The name %r conflicts with C macros on some platforms; choose a different name"
|
581 | % o.name)
|
582 | return
|
583 |
|
584 | self.oils_visit_member_expr(o)
|
585 |
|
586 | #
|
587 | # Not doing anything with these?
|
588 | #
|
589 |
|
590 | def visit_cast_expr(self, o: 'mypy.nodes.CastExpr') -> None:
|
591 | # I think casts are handle in AssignmentStmt
|
592 | pass
|
593 |
|
594 | def visit_type_application(self, o: 'mypy.nodes.TypeApplication') -> None:
|
595 | # what is this?
|
596 | pass
|
597 |
|
598 | def visit_type_var_expr(self, o: 'mypy.nodes.TypeVarExpr') -> None:
|
599 | pass
|
600 |
|
601 | def visit_type_alias_expr(self, o: 'mypy.nodes.TypeAliasExpr') -> None:
|
602 | pass
|
603 |
|
604 | def visit_reveal_expr(self, o: 'mypy.nodes.RevealExpr') -> None:
|
605 | pass
|
606 |
|
607 | def visit_var(self, o: 'mypy.nodes.Var') -> None:
|
608 | # Is this a Python 3 class member?
|
609 | pass
|
610 |
|
611 | def visit_assert_stmt(self, o: 'mypy.nodes.AssertStmt') -> None:
|
612 | # no-op on purpose
|
613 | pass
|
614 |
|
615 | #
|
616 | # Not part of the mycpp dialect
|
617 | #
|
618 |
|
619 | def visit_lambda_expr(self, o: 'mypy.nodes.LambdaExpr') -> None:
|
620 | self.not_translated(o, 'lambda')
|
621 |
|
622 | def visit_set_comprehension(self,
|
623 | o: 'mypy.nodes.SetComprehension') -> None:
|
624 | self.not_translated(o, 'set comp')
|
625 |
|
626 | def visit_dictionary_comprehension(
|
627 | self, o: 'mypy.nodes.DictionaryComprehension') -> None:
|
628 | self.not_translated(o, 'dict comp')
|
629 |
|
630 | def visit_global_decl(self, o: 'mypy.nodes.GlobalDecl') -> None:
|
631 | self.not_translated(o, 'global')
|
632 |
|
633 | def visit_nonlocal_decl(self, o: 'mypy.nodes.NonlocalDecl') -> None:
|
634 | self.not_translated(o, 'nonlocal')
|
635 |
|
636 | def visit_exec_stmt(self, o: 'mypy.nodes.ExecStmt') -> None:
|
637 | self.report_error(o, 'exec not allowed')
|
638 |
|
639 | # Error
|
640 | def visit_print_stmt(self, o: 'mypy.nodes.PrintStmt') -> None:
|
641 | self.report_error(
|
642 | o,
|
643 | 'File should start with "from __future__ import print_function"')
|
644 |
|
645 | # UNHANDLED
|
646 |
|
647 | def visit_import_all(self, o: 'mypy.nodes.ImportAll') -> None:
|
648 | self.not_translated(o, 'ImportAll')
|
649 |
|
650 | def visit_overloaded_func_def(self,
|
651 | o: 'mypy.nodes.OverloadedFuncDef') -> None:
|
652 | self.not_python2(o, 'overloaded func')
|
653 |
|
654 | def visit_bytes_expr(self, o: 'mypy.nodes.BytesExpr') -> None:
|
655 | self.not_python2(o, 'bytes expr')
|
656 |
|
657 | def visit_unicode_expr(self, o: 'mypy.nodes.UnicodeExpr') -> None:
|
658 | self.not_translated(o, 'unicode expr')
|
659 |
|
660 | def visit_complex_expr(self, o: 'mypy.nodes.ComplexExpr') -> None:
|
661 | self.not_translated(o, 'complex expr')
|
662 |
|
663 | def visit_set_expr(self, o: 'mypy.nodes.SetExpr') -> None:
|
664 | self.not_translated(o, 'set expr')
|
665 |
|
666 | def visit_ellipsis(self, o: 'mypy.nodes.EllipsisExpr') -> None:
|
667 | # is this in .pyi files only?
|
668 | self.not_translated(o, 'ellipsis')
|
669 |
|
670 | def visit_yield_from_expr(self, o: 'mypy.nodes.YieldFromExpr') -> None:
|
671 | self.not_python2(o, 'yield from')
|
672 |
|
673 | def visit_star_expr(self, o: 'mypy.nodes.StarExpr') -> None:
|
674 | # mycpp/examples/invalid_python.py doesn't hit this?
|
675 | self.not_translated(o, 'star expr')
|
676 |
|
677 | def visit_super_expr(self, o: 'mypy.nodes.SuperExpr') -> None:
|
678 | self.not_translated(o, 'super expr')
|
679 |
|
680 | def visit_assignment_expr(self, o: 'mypy.nodes.AssignmentExpr') -> None:
|
681 | # I think this is a := b
|
682 | self.not_translated(o, 'assign expr')
|
683 |
|
684 | def visit_decorator(self, o: 'mypy.nodes.Decorator') -> None:
|
685 | self.not_translated(o, 'decorator')
|
686 |
|
687 | def visit_backquote_expr(self, o: 'mypy.nodes.BackquoteExpr') -> None:
|
688 | self.not_translated(o, 'backquote')
|
689 |
|
690 | def visit_namedtuple_expr(self, o: 'mypy.nodes.NamedTupleExpr') -> None:
|
691 | self.not_translated(o, 'namedtuple')
|
692 |
|
693 | def visit_enum_call_expr(self, o: 'mypy.nodes.EnumCallExpr') -> None:
|
694 | self.not_translated(o, 'enum')
|
695 |
|
696 | def visit_typeddict_expr(self, o: 'mypy.nodes.TypedDictExpr') -> None:
|
697 | self.not_translated(o, 'typed dict')
|
698 |
|
699 | def visit_newtype_expr(self, o: 'mypy.nodes.NewTypeExpr') -> None:
|
700 | self.not_translated(o, 'newtype')
|
701 |
|
702 | def visit__promote_expr(self, o: 'mypy.nodes.PromoteExpr') -> None:
|
703 | self.not_translated(o, 'promote')
|
704 |
|
705 | def visit_await_expr(self, o: 'mypy.nodes.AwaitExpr') -> None:
|
706 | self.not_translated(o, 'await')
|
707 |
|
708 | def visit_temp_node(self, o: 'mypy.nodes.TempNode') -> None:
|
709 | self.not_translated(o, 'temp')
|
710 |
|
711 |
|
712 | class TypedVisitor(SimpleVisitor):
|
713 | """Base class for visitors that need type info."""
|
714 |
|
715 | def __init__(self, types: Dict[Expression, Type]) -> None:
|
716 | SimpleVisitor.__init__(self)
|
717 | self.types = types
|
718 |
|
719 | def oils_visit_op_expr(self, o: 'mypy.nodes.OpExpr') -> None:
|
720 | self.accept(o.left)
|
721 | self.accept(o.right)
|
722 |
|
723 | def oils_visit_format_expr(self, left: Expression,
|
724 | right: Expression) -> None:
|
725 | """ mystr % x mystr % (x, y) """
|
726 | self.accept(left)
|
727 | self.accept(right)
|
728 |
|
729 | def visit_op_expr(self, o: 'mypy.nodes.OpExpr') -> None:
|
730 | if o.op == '%' and util.IsStr(self.types[o.left]):
|
731 | # 'x = %r' % x
|
732 | self.oils_visit_format_expr(o.left, o.right)
|
733 | return
|
734 |
|
735 | # Any other expression
|
736 | self.oils_visit_op_expr(o)
|