Skip to content

Commit

Permalink
added support for multiple inheritance
Browse files Browse the repository at this point in the history
git-svn-id: https://pyjamas.svn.sourceforge.net/svnroot/pyjamas/trunk@548 7a2bd370-bda8-463c-979e-2900ccfb811e
  • Loading branch information
lkcl committed Apr 18, 2009
1 parent 301f438 commit a89a623
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 29 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
@@ -1,6 +1,8 @@
Changes made to Pyjamas since 0.5p1
-----------------------------------

* Added Multiple Inheritance (thanks to Kees Boss)

* Add support for Google Gears (Database)

* Completed DisclosurePanel port
Expand Down
3 changes: 3 additions & 0 deletions CREDITS
Expand Up @@ -20,6 +20,7 @@ Stephan Diehl - stephan.diehl@gmx.net
John Lehman - j1o1h1n@gmail.com
Jürgen Kartnaller - <kartnaller@lovelysystems.com>
G Clinch
Kees Boss

Erik gets a special mention for the contribution of the "Showcase".

Expand All @@ -31,6 +32,8 @@ Bernd's work on the core python compiler has been absolutely invaluable.

G Clinch ported the DisclosurePanel from GWT

Kees Boss added multiple inheritance support

James - thank you for kick-starting this project.


Expand Down
93 changes: 93 additions & 0 deletions examples/libtest/ClassTest.py
Expand Up @@ -186,6 +186,37 @@ def testMetaClass(self):
self.assertEqual(instance.method(), 1)
self.assertEqual(instance.x, 5)

def testMultiSuperclass(self):
new_value = 'New value'
c = ExampleMultiSuperclassNoConstructor(new_value)
# Verify that the __init__ of ExampleMultiSuperclassParent1 is used
self.assertEqual(c.x, new_value)
# Verify that the ExampleMultiSuperclassParent2.y is there
self.assertEqual(c.y, ExampleMultiSuperclassParent2.y)
# Verify that the get_value() of ExampleMultiSuperclassParent1 is used
self.assertEqual(c.get_value(), new_value)

c = ExampleMultiSuperclassExplicitConstructor(new_value)
# Verify that the ExampleMultiSuperclassParent1.x is there
self.assertEqual(c.x, ExampleMultiSuperclassParent1.x)
# Verify that the ExampleMultiSuperclassParent2.y is there
self.assertEqual(c.y, ExampleMultiSuperclassParent2.y)
# Verify that the __init__ of ExampleMultiSuperclassExplicitConstructor is used
self.assertEqual(c.z, new_value)
# Verify that the get_value() of ExampleMultiSuperclassExplicitConstructor is used
self.assertEqual(c.get_value(), new_value)
# Verify that the combination of the variables is correct
self.assertEqual(c.get_values(), ':'.join([ExampleMultiSuperclassParent1.x, ExampleMultiSuperclassParent2.y, new_value]))

def testMultiDoubleInherit(self):
i = DoubleInherit(1,2,3)
self.assertEqual(i.get_x(), 1)
self.assertEqual(i.get_y(), 2)
self.assertEqual(i.get_z(), 3)

MultiInherit2.set_x(i, 5)
self.assertEqual(MultiInherit1.get_x(i), 5)

# testMetaClass
def method(self):
return 1
Expand Down Expand Up @@ -269,5 +300,67 @@ def __init__(self):
# def someMethod(self):
# return 'abc'

class ObjectClass(object):
pass

class ExampleMultiSuperclassParent1:
x = 'Initial X'

def __init__(self, x):
self.x = x
def get_value(self):
return self.x

class ExampleMultiSuperclassParent2:
y = 'Initial Y'

def __init__(self, y):
self.y = y
def get_value(self):
return self.y

class ExampleMultiSuperclassNoConstructor(ExampleMultiSuperclassParent1, ExampleMultiSuperclassParent2):
z = 'Initial Z'

class ExampleMultiSuperclassExplicitConstructor(ExampleMultiSuperclassParent1, ExampleMultiSuperclassParent2):
z = 'Initial Z'

def __init__(self, z):
self.z = z
def get_value(self):
return self.z
def get_values(self):
return ':'.join([self.x, self.y, self.z])


class MultiBase:
def __init__(self, x):
self.x = x

def get_x(self):
return self.x

def set_x(self,x ):
self.x = x

class MultiInherit1(MultiBase):
def __init__(self, x, y):
self.y = y
MultiBase.__init__(self, x) # yes it gets called twice

def get_y(self):
return self.y

class MultiInherit2(MultiBase):
def __init__(self, x, z):
self.z = z
MultiBase.__init__(self, x) # yes it gets called twice

def get_z(self):
return self.z

class DoubleInherit(MultiInherit1, MultiInherit2):
def __init__(self, x, y, z):
MultiInherit1.__init__(self, x, y) # MultiBase __init__ called once
MultiInherit2.__init__(self, x, z) # MultiBase __init__ called twice

9 changes: 7 additions & 2 deletions library/_pyjs.js
@@ -1,10 +1,15 @@
function pyjs_extend(klass, base) {
function klass_object_inherit() {}
klass_object_inherit.prototype = base.prototype;
if (klass.prototype.__class__ == null) {
klass_object_inherit.prototype = base.prototype;
} else {
klass_object_inherit.prototype = klass.prototype;
}
klass_object = new klass_object_inherit();
for (var i in base.prototype.__class__) {
v = base.prototype.__class__[i];
if (typeof v == "function" && (v.class_method || v.static_method || v.unbound_method))
if ( (typeof v == "function" && (v.class_method || v.static_method || v.unbound_method))
|| (typeof v == "string"))
{
klass_object[i] = v;
}
Expand Down
58 changes: 31 additions & 27 deletions pyjs/pyjs.py
Expand Up @@ -763,28 +763,30 @@ class by name. Static, class, and unbound methods are copied


if len(node.bases) == 0:
base_class = "pyjslib.__Object"
elif len(node.bases) == 1:
if isinstance(node.bases[0], ast.Name):
if self.imported_classes.has_key(node.bases[0].name):
base_class_ = self.imported_classes[node.bases[0].name] + '.__' + node.bases[0].name
base_class = self.imported_classes[node.bases[0].name] + '.' + node.bases[0].name
base_classes = [("object", "pyjslib.__Object", "pyjslib.__Object")]
elif len(node.bases) >= 1:
base_classes = []
for node_base in node.bases:
if isinstance(node_base, ast.Name):
node_base_name = node_base.name
if self.imported_classes.has_key(node_base.name):
base_class_ = self.imported_classes[node_base.name] + '.__' + node_base.name
base_class = self.imported_classes[node_base.name] + '.' + node_base.name
else:
base_class_ = self.modpfx() + "__" + node_base.name
base_class = self.modpfx() + node_base.name
elif isinstance(node_base, ast.Getattr):
# the bases are not in scope of the class so do not
# pass our class to self._name
node_base_name = node_base.attrname
base_class_ = self._name(node_base.expr, None) + \
".__" + node_base.attrname
base_class = self._name(node_base.expr, None) + \
"." + node_base.attrname
else:
base_class_ = self.modpfx() + "__" + node.bases[0].name
base_class = self.modpfx() + node.bases[0].name
elif isinstance(node.bases[0], ast.Getattr):
# the bases are not in scope of the class so do not
# pass our class to self._name
base_class_ = self._name(node.bases[0].expr, None) + \
".__" + node.bases[0].attrname
base_class = self._name(node.bases[0].expr, None) + \
"." + node.bases[0].attrname
else:
raise TranslationError("unsupported type (in _class)", node.bases[0])

current_klass.set_base(base_class)
else:
raise TranslationError("more than one base (in _class)", node)
raise TranslationError("unsupported type (in _class)", node_base)
base_classes.append((node_base_name, base_class, base_class_))
current_klass.set_base(base_classes[0][1])

print >>self.output, UU+class_name_ + " = function () {"
# call superconstructor
Expand Down Expand Up @@ -818,15 +820,17 @@ class by name. Static, class, and unbound methods are copied
print >>self.output, " "+UU+class_name_+".__was_initialized__ = true;"
cls_obj = UU+class_name_ + '.prototype.__class__'

base_classes.reverse()
if class_name == "pyjslib.__Object":
print >>self.output, " "+cls_obj+" = {};"
else:
if base_class and base_class not in ("object", "pyjslib.__Object"):
print >>self.output, " if(!"+UU+base_class_+".__was_initialized__)"
print >>self.output, " "+UU+base_class_+".__initialize__();"
print >>self.output, " pyjs_extend(" + UU+class_name_ + ", "+UU+base_class_+");"
else:
print >>self.output, " pyjs_extend(" + UU+class_name_ + ", "+UU+"pyjslib.__Object);"
for node_base_name, node_base_class, node_base_class_ in base_classes:
if node_base_name == 'object':
print >>self.output, " pyjs_extend(" + UU+class_name_ + ", "+UU+"pyjslib.__Object);"
else:
print >>self.output, " if(!"+UU+node_base_class_+".__was_initialized__)"
print >>self.output, " "+UU+node_base_class_+".__initialize__();"
print >>self.output, " pyjs_extend(" + UU+class_name_ + ", "+UU+node_base_class_+");"

print >>self.output, " "+cls_obj+".__new__ = "+UU+class_name+";"
print >>self.output, " "+cls_obj+".__name__ = '"+UU+node.name+"';"
Expand Down

0 comments on commit a89a623

Please sign in to comment.