Skip to content

Commit

Permalink
js backend: support functor style classes that define __call__ specia…
Browse files Browse the repository at this point in the history
…l method.

this is supported by checking if the class has a __call__ method, and if it has,
then move the def of __call__ into the constructor, bind it to this,
copy attributes and __proto__ from this, and then return __call__.
  • Loading branch information
hartsantler committed Sep 19, 2015
1 parent 90611c4 commit 4bfb360
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 6 deletions.
16 changes: 14 additions & 2 deletions regtests/class/__call__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
"""custom callable"""
from runtime import *

class A:
def __init__(self):
self.x = 5

def __call__(self):
print self.x
return 'XXX'

def foo(self):
return self.x


def main():
print 'testing __call__'
a = A()
TestError(a.x == 5)
TestError( a()=='XXX' )
assert a.x == 5
assert a() == 'XXX'
assert a.__call__() == 'XXX'
assert a.foo() == 5
print 'ok'

main()
23 changes: 19 additions & 4 deletions src/intermediateform.md
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,7 @@ class PythonToPythonJS(NodeVisitorBase):
method_names = [] ## write back in order (required by GLSL)
methods = {} ## same named functions get squashed in here (like getter/setters)
methods_all = [] ## all methods of class

__call__ = None
class_vars = []
post_class_write = [
'%s.prototype.__class__ = %s' %(name, name),
Expand All @@ -1107,9 +1107,6 @@ class PythonToPythonJS(NodeVisitorBase):
node._post_class_write = post_class_write
for item in node.body:
if isinstance(item, FunctionDef):
method_names.append(item.name)
methods[ item.name ] = item
methods_all.append( item )
## only remove `self` if it is the first argument,
## python actually allows `self` to be any name (whatever the first argument is named)
## but that is very bad style, and basically never used.
Expand All @@ -1128,6 +1125,13 @@ class PythonToPythonJS(NodeVisitorBase):
if n.id == 'self':
n.id = 'this'

if item.name == '__call__':
__call__ = item
else:
method_names.append(item.name)
methods[ item.name ] = item
methods_all.append( item )

elif isinstance(item, ast.Expr) and isinstance(item.value, Str): ## skip doc strings
pass
elif isinstance(item, ast.ClassDef):
Expand All @@ -1144,6 +1148,7 @@ class PythonToPythonJS(NodeVisitorBase):
else:
class_vars.append( item )


init = methods.get( '__init__', None)
if init:
args = [self.visit(arg) for arg in init.args.args]
Expand Down Expand Up @@ -1187,6 +1192,16 @@ class PythonToPythonJS(NodeVisitorBase):
writer.write('inline("this.__$UID$__ = __$UID$__ ++")')


if __call__:
writer.write('var(__callbound__)')
writer.write('@bind(__callbound__, this)')
line = self.visit(__call__)
if line: writer.write( line )
writer.write('inline("for (var _ in this) {__callbound__[_]=this[_];}")')
writer.write('__callbound__.__proto__ = this.__proto__')
writer.write('__callbound__.__call__ = __callbound__')
writer.write('return __callbound__')

writer.pull()

if post_class_write:
Expand Down

0 comments on commit 4bfb360

Please sign in to comment.