1111from ast import Subscript
1212from ast import Attribute
1313from ast import FunctionDef
14+ from ast import BinOp
1415
1516from ast import parse
1617from ast import NodeVisitor
@@ -76,7 +77,8 @@ def __init__(self, module=None, module_path=None):
7677 self ._instances = dict () ## instance name : class name
7778 self ._decorator_properties = dict ()
7879 self ._decorator_class_props = dict ()
79-
80+ self ._function_return_types = dict ()
81+ self ._return_type = None
8082 self ._module = module
8183 self ._module_path = module_path
8284 assert os .path .isdir ( module_path )
@@ -87,6 +89,7 @@ def save_module(self):
8789 classes = self ._classes ,
8890 inline_classes = self ._inline_classes ,
8991 decorator_class_props = self ._decorator_class_props ,
92+ function_return_types = self ._function_return_types ,
9093 )
9194 pickle .dump ( a , open (os .path .join (self ._module_path , self ._module + '.module' ), 'wb' ) )
9295
@@ -102,6 +105,7 @@ def visit_ImportFrom(self, node):
102105 self ._classes .update ( a ['classes' ] )
103106 self ._inline_classes .update ( a ['inline_classes' ] )
104107 self ._decorator_class_props .update ( a ['decorator_class_props' ] )
108+ self ._function_return_types .update ( a ['function_return_types' ] )
105109
106110 def visit_Assert (self , node ):
107111 ## hijacking "assert isinstance(a,A)" as a type system ##
@@ -239,13 +243,27 @@ def visit_Num(self, node):
239243
240244 def visit_Return (self , node ):
241245 if node .value :
242- return writer .write ('return %s' % self .visit (node .value ))
243- return writer .write ('return undefined' )
246+ if isinstance (node .value , Call ) and isinstance (node .value .func , Name ) and node .value .func .id in self ._classes :
247+ self ._return_type = node .value .func .id
248+ elif isinstance (node .value , Name ) and node .value .id == 'self' and 'self' in self ._instances :
249+ self ._return_type = self ._instances ['self' ]
250+
251+ writer .write ('return %s' % self .visit (node .value ))
252+
253+ else :
254+ raise RuntimeError
244255
245256 def visit_BinOp (self , node ):
257+ node .operator_overloading = 'undefined'
246258 left = self .visit (node .left )
247259 op = self .visit (node .op )
248260 right = self .visit (node .right )
261+ if isinstance (node .left , Name ) and node .left .id in self ._instances :
262+ klass = self ._instances [ node .left .id ]
263+ if op == '*' and '__mul__' in self ._classes [klass ]:
264+ node .operator_overloading = '__%s___mul__' % klass
265+ assert node .operator_overloading
266+ return '''JS('__%s___mul__( [%s, %s] )')''' % (klass , left , right )
249267 return '%s %s %s' % (left , op , right )
250268
251269 def visit_Eq (self , node ):
@@ -385,18 +403,25 @@ def visit_Assign(self, node):
385403 writer .write (code )
386404
387405 elif isinstance (target , Name ):
406+ node_value = self .visit ( node .value ) ## node.value may have extra attributes after being visited
388407
389408 if isinstance (node .value , Call ) and hasattr (node .value .func , 'id' ) and node .value .func .id in self ._classes :
390409 self ._instances [ target .id ] = node .value .func .id ## keep track of instances
410+ elif isinstance (node .value , Call ) and isinstance (node .value .func , Name ) and node .value .func .id in self ._function_return_types :
411+ self ._instances [ target .id ] = self ._function_return_types [ node .value .func .id ]
391412 elif target .id in self ._instances :
392- self ._instances .pop ( target .id )
413+ self ._instances .pop ( target .id ) ## TODO is this correct?
393414
394- if isinstance (node .value , Name ):
415+ if isinstance (node .value , Name ): ## if this is a simple copy: "a = b" and "b" is known to be of some class
395416 name = self .visit (node .value )
396417 if name in self ._instances : self ._instances [ target .id ] = self ._instances [ name ]
397418 writer .write ('%s = %s' % (target .id , name ))
398- else :
399- writer .write ('%s = %s' % (target .id , self .visit (node .value )))
419+ elif isinstance (node .value , BinOp ) and hasattr (node .value , 'operator_overloading' ) and node .value .operator_overloading in self ._function_return_types :
420+ self ._instances [ target .id ] = self ._function_return_types [ node .value .operator_overloading ]
421+ writer .write ('%s = %s' % (target .id , node_value ))
422+
423+ else : ## blind assignment
424+ writer .write ('%s = %s' % (target .id , node_value ))
400425
401426 else : # it's a Tuple
402427 id = self .identifier
@@ -545,6 +570,7 @@ def visit_FunctionDef(self, node):
545570 expr = expr % (node .args .kwarg , node .args .kwarg )
546571 writer .write (expr )
547572
573+ self ._return_type = None
548574 #map(self.visit, node.body)
549575 for child in node .body :
550576 # simple test to drop triple quote comments
@@ -557,6 +583,12 @@ def visit_FunctionDef(self, node):
557583 else :
558584 self .visit (child )
559585
586+ if self ._return_type :
587+ #if hasattr(node, 'original_name'):
588+ # self._function_return_types[ node.original_name ] = self._return_type
589+ #else:
590+ self ._function_return_types [ node .name ] = self ._return_type
591+
560592 writer .pull ()
561593
562594 # apply decorators
0 commit comments