Re: Java interface compatibility.

Artem Gr <[email protected]> Tue, 19 Apr 2005 12:04:12 +0400
Newsgroups gmane.comp.lang.nice.devel
Message-ID <[email protected]>
Attached is the cleaned up version of the patch.
( http://rafb.net/paste/results/LuOiNe27.html )
Before commiting this, I am going to work on testcases.

Daniel Bonniot mentioned the possibility to optimize away the instanceof
tests from the generated dispatch methods.
LuOiNe27.txt (text/plain, 6.7 KB)
Index: src/bossa/syntax/compilation.nice
===================================================================
RCS file: /cvsroot/nice/Nice/src/bossa/syntax/compilation.nice,v
retrieving revision 1.8
diff -u -r1.8 compilation.nice
--- src/bossa/syntax/compilation.nice	26 Mar 2005 15:33:02 -0000	1.8
+++ src/bossa/syntax/compilation.nice	18 Apr 2005 19:10:07 -0000
@@ -22,12 +22,10 @@
 	make("java.lang.Error").getDeclaredMethod("<init>",
 	[cast(gnu.bytecode.Type.string_type)]);
 
-public void compileNiceMethod(NiceMethod m, 
-		      Stack<Alternative> sortedAlternatives, 
-		      bossa.modules.Package module)
-{
-  gnu.expr.LambdaExp lexp = m.getLambda();
-    
+private void makeBody(NiceMethod m,
+                      gnu.expr.LambdaExp lexp,
+                      Stack<Alternative> sortedAlternatives){
+
   // parameters of the alternative function are the same in each case, 
   // so we compute them just once
   int arity = m.getArity();
@@ -39,15 +37,60 @@
       params[rank++] = new gnu.expr.ReferenceExp(param);
 
   gnu.expr.Expression body = dispatchNiceMethod
-      (sortedAlternatives.iterator(), 
-       m.javaReturnType(), m.javaReturnType().isVoid(), params);
+    (sortedAlternatives.iterator(), 
+     m.javaReturnType(), m.javaReturnType().isVoid(), params);
 
   if (m.isMain())
     body = beautifyUncaughtExceptions(body);
 
-  nice.tools.code.Gen.setMethodBody(lexp, m.getContract().compile(body));
+  body = m.getContract().compile(body);
+  nice.tools.code.Gen.setMethodBody(lexp, body);
 }
-  
+
+public void compileNiceMethod(NiceMethod m, 
+		      Stack<Alternative> sortedAlternatives, 
+		      bossa.modules.Package module)
+{
+  gnu.expr.LambdaExp lexp = m.getLambda();
+
+  makeBody( m, lexp, sortedAlternatives );
+
+  if(m.getArity() != 0){
+    ?NiceClass iface = getNiceClass(m.getArgTypes()[0]);
+    if(iface != null && iface.isInterface() && ! ( m instanceof MethodWithDefault )){
+
+      // If alternative method is implementing an interface,
+      // then generate a dispatch method as a class member,
+      // for Java interface invocations to find the implementation.
+
+      if(bossa.util.Debug.codeGeneration)
+        bossa.util.Debug.println("Generating Nice interface signature for " iface );
+      String name = m.getName().toString();
+      let argTypes = m.javaArgTypes();
+      let retType  = m.javaReturnType();
+      let fullName = m.getFullName();
+      gnu.expr.LambdaExp res = generateMethod
+        (name, argTypes, retType, m.getSymbols(), toplevel: true, member: true);
+      res.parameterCopies = cast(notNull(m.formalParameters()).getParameterCopies());
+      iface.addJavaMethod(res);
+
+      for(alt : sortedAlternatives){
+        ?NiceClass cl = declaringClass(alt);
+        if(cl == null) continue;
+        if(bossa.util.Debug.codeGeneration)
+          bossa.util.Debug.println("Generating Nice dispatch function (interface implementation) for " alt);
+
+        res = generateMethod
+          (name, argTypes, retType, m.getSymbols(), toplevel: true, member: true);
+        res.parameterCopies = cast(notNull(m.formalParameters()).getParameterCopies());
+        res.addBytecodeAttribute(new gnu.bytecode.MiscAttr("id", fullName.getBytes()));
+        makeBody( m, res, sortedAlternatives );
+        cl.addJavaMethod(res);
+      }
+    }
+  }
+}
+
 private gnu.expr.Expression dispatchNiceMethod(Iterator<Alternative> sortedAlternatives, 
 				     gnu.bytecode.Type returnType, 
 				     boolean voidReturn,
@@ -145,18 +188,24 @@
     }
 }
 
-private NiceClass declaringClass(JavaMethod m, Alternative alt)
+private ?NiceClass declaringClass(Alternative alt)
 {
   ?mlsub.typing.TypeConstructor firstArgument = alt.getPatterns()[0].getTC();
   let def = getTypeDefinition(firstArgument);
 
   if (def != null && def.getImplementation() instanceof NiceClass)
     return cast(def.getImplementation());
+  return null;
+}
+
+private NiceClass declaringClass(JavaMethod m, Alternative alt)
+{
+  let cl = declaringClass(alt); if(cl != null) return cl;
 
   // Explain that this cannot be done.
   String msg = m + " is a native method.\n";
 
-  if (firstArgument == null)
+  if (maybeNull(firstArgument) == null)
     msg += "It cannot be implemented without dispatch on the first argument";
   else
     msg += "It cannot be overriden because the first argument " +
Index: src/bossa/syntax/modifiers.nice
===================================================================
RCS file: /cvsroot/nice/Nice/src/bossa/syntax/modifiers.nice,v
retrieving revision 1.1
diff -u -r1.1 modifiers.nice
--- src/bossa/syntax/modifiers.nice	25 Nov 2004 19:28:18 -0000	1.1
+++ src/bossa/syntax/modifiers.nice	18 Apr 2005 19:10:07 -0000
@@ -125,6 +125,7 @@
    void makeInterface( )
    {
 	this.setModifier( INTERFACE );
+        this.setModifier( ABSTRACT );
    }
 
    boolean isInterface() = this.getModifier( INTERFACE );
@@ -151,7 +152,8 @@
      if( this.getModifier( VOLATILE ) )     buf.append(" volatile");
      if( this.getModifier( TRANSIENT ) )    buf.append(" transient");
      if( this.getModifier( NATIVE ) )       buf.append(" native");
-     if( this.getModifier( ABSTRACT ) )     buf.append(" abstract");
+     if( ! this.getModifier( INTERFACE ) )
+       if( this.getModifier( ABSTRACT ) )   buf.append(" abstract");
      return buf.toString();
   }
 }
Index: src/gnu/bytecode/Method.java
===================================================================
RCS file: /cvsroot/nice/Nice/src/gnu/bytecode/Method.java,v
retrieving revision 1.9
diff -u -r1.9 Method.java
--- src/gnu/bytecode/Method.java	2 Mar 2004 20:21:11 -0000	1.9
+++ src/gnu/bytecode/Method.java	18 Apr 2005 19:10:08 -0000
@@ -241,7 +241,7 @@
        throws java.io.IOException
   {
     
-    if (code == null)
+    if (code == null && !isAbstract())
       throw new Error("Method "+this+" has no code");
       //return;
 
Index: src/gnu/expr/LambdaExp.java
===================================================================
RCS file: /cvsroot/nice/Nice/src/gnu/expr/LambdaExp.java,v
retrieving revision 1.30
diff -u -r1.30 LambdaExp.java
--- src/gnu/expr/LambdaExp.java	20 Feb 2005 22:09:39 -0000	1.30
+++ src/gnu/expr/LambdaExp.java	18 Apr 2005 19:10:12 -0000
@@ -1525,13 +1525,17 @@
 		    decl.var = null;
 		  }
 	      }
-	    comp.method.initCode();
-	    allocChildClasses(comp);
-	    allocParameters(comp);
-	    enterFunction(comp);
-
-	    compileBody(comp);
-	    compileEnd(comp);
+            if (comp.curClass.isInterface() && comp.method.isAbstract()){
+              // Interface method. Skip code generation.
+            }else{
+              comp.method.initCode();
+              allocChildClasses(comp);
+              allocParameters(comp);
+              enterFunction(comp);
+
+              compileBody(comp);
+              compileEnd(comp);
+            }
 	  }
       }