diff options
| author | Michael Williamson <mike@zwobble.org> | 2016-04-02 00:29:32 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2016-04-02 00:29:32 +0100 |
| commit | 7fbbbf62b303ee819017844ff8058b764465e246 (patch) | |
| tree | 4c1966008c3972856d6d7de812000fe9e2d1b0c8 /src | |
| parent | 65503a9acc04d27d7118cd7fc9077aad5e3179a4 (diff) | |
Defer generation overrides until necessary, don't mangle C# names
Diffstat (limited to 'src')
10 files changed, 172 insertions, 88 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/MethodNode.java b/src/main/java/org/zwobble/couscous/ast/MethodNode.java index 024541f..8863619 100644 --- a/src/main/java/org/zwobble/couscous/ast/MethodNode.java +++ b/src/main/java/org/zwobble/couscous/ast/MethodNode.java @@ -31,7 +31,9 @@ public class MethodNode implements Node { private Type returnType = Types.VOID; private final ImmutableList.Builder<StatementNode> body = ImmutableList.builder(); - + private final ImmutableList.Builder<MethodSignature> overrides = + ImmutableList.builder(); + public Builder(String name) { this.name = name; } @@ -83,7 +85,8 @@ public class MethodNode implements Node { name, arguments.build(), returnType, - isAbstract ? Optional.empty() : Optional.of(body.build())); + isAbstract ? Optional.empty() : Optional.of(body.build()), + overrides.build()); } } @@ -93,9 +96,10 @@ public class MethodNode implements Node { String name, List<FormalArgumentNode> arguments, Type returnType, - Optional<List<StatementNode>> body) + Optional<List<StatementNode>> body, + List<MethodSignature> overrides) { - return new MethodNode(annotations, isStatic, name, arguments, returnType, body); + return new MethodNode(annotations, isStatic, name, arguments, returnType, body, overrides); } private final List<AnnotationNode> annotations; @@ -104,14 +108,16 @@ public class MethodNode implements Node { private final List<FormalArgumentNode> arguments; private final Type returnType; private final Optional<List<StatementNode>> body; - + private final List<MethodSignature> overrides; + private MethodNode( List<AnnotationNode> annotations, boolean isStatic, String name, List<FormalArgumentNode> arguments, Type returnType, - Optional<List<StatementNode>> body) + Optional<List<StatementNode>> body, + List<MethodSignature> overrides) { this.annotations = annotations; this.isStatic = isStatic; @@ -119,6 +125,7 @@ public class MethodNode implements Node { this.arguments = arguments; this.returnType = returnType; this.body = body; + this.overrides = overrides; } public List<AnnotationNode> getAnnotations() { @@ -145,6 +152,10 @@ public class MethodNode implements Node { return body; } + public List<MethodSignature> getOverrides() { + return overrides; + } + public boolean isAbstract() { return !body.isPresent(); } @@ -157,7 +168,7 @@ public class MethodNode implements Node { } public MethodNode mapBody(Function<List<StatementNode>, List<StatementNode>> function) { - return new MethodNode(annotations, isStatic, name, arguments, returnType, body.map(function)); + return new MethodNode(annotations, isStatic, name, arguments, returnType, body.map(function), overrides); } @Override @@ -172,19 +183,8 @@ public class MethodNode implements Node { transformer.transformMethodName(signature()), transformer.transformFormalArguments(arguments), transformer.transform(returnType), - body.map(transformer::transformStatements)); - } - - @Override - public String toString() { - return "MethodNode(" + - "annotations=" + annotations + - ", isStatic=" + isStatic + - ", name=" + name + - ", arguments=" + arguments + - ", returnType=" + returnType + - ", body=" + body + - ')'; + body.map(transformer::transformStatements), + eagerMap(overrides, transformer::transform)); } @Override @@ -199,7 +199,8 @@ public class MethodNode implements Node { if (!name.equals(that.name)) return false; if (!arguments.equals(that.arguments)) return false; if (!returnType.equals(that.returnType)) return false; - return body.equals(that.body); + if (!body.equals(that.body)) return false; + return overrides.equals(that.overrides); } @@ -211,6 +212,21 @@ public class MethodNode implements Node { result = 31 * result + arguments.hashCode(); result = 31 * result + returnType.hashCode(); result = 31 * result + body.hashCode(); + result = 31 * result + overrides.hashCode(); return result; } + + @Override + public String toString() { + return "MethodNode(" + + "annotations=" + annotations + + ", isStatic=" + isStatic + + ", name=" + name + + ", arguments=" + arguments + + ", returnType=" + returnType + + ", body=" + body + + ", overrides=" + overrides + + ')'; + } + } diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpCodeGenerator.java b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpCodeGenerator.java index 8bd8b11..00de205 100644 --- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpCodeGenerator.java +++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpCodeGenerator.java @@ -17,6 +17,8 @@ import static org.zwobble.couscous.util.Casts.tryCast; import static org.zwobble.couscous.util.ExtraLists.eagerMap; public class CsharpCodeGenerator { + public static final Naming NAMING = Naming.noMangling(); + private final static Map<ScalarType, ScalarType> PRIMITIVES = ImmutableMap.<ScalarType, ScalarType>builder() .put(Types.INT, ScalarType.of("int")) .put(Types.STRING, ScalarType.of("string")) @@ -29,7 +31,7 @@ public class CsharpCodeGenerator { private final NodeTransformer nodeTransformer; public static Node generateCode(Node node, String namespace) { - return new CsharpCodeGenerator(Naming.signaturesContainSimpleNames(), namespace).generateCode(node); + return new CsharpCodeGenerator(NAMING, namespace).generateCode(node); } private CsharpCodeGenerator(Naming naming, String namespace) { diff --git a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java index a6922e4..73e6ced 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java +++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java @@ -6,15 +6,17 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; import org.zwobble.couscous.ast.*; import org.zwobble.couscous.ast.structure.NodeStructure; -import org.zwobble.couscous.types.ScalarType; -import org.zwobble.couscous.types.Type; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; import org.zwobble.couscous.ast.visitors.NodeMapperWithDefault; import org.zwobble.couscous.ast.visitors.StatementNodeMapper; import org.zwobble.couscous.backends.naming.Names; import org.zwobble.couscous.backends.python.ast.*; +import org.zwobble.couscous.types.ScalarType; +import org.zwobble.couscous.types.Type; import org.zwobble.couscous.types.Types; -import org.zwobble.couscous.values.*; +import org.zwobble.couscous.values.InternalCouscousValue; +import org.zwobble.couscous.values.PrimitiveValue; +import org.zwobble.couscous.values.TypeValue; import java.util.*; import java.util.stream.Collectors; @@ -23,8 +25,14 @@ import java.util.stream.Stream; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Iterators.singletonIterator; -import static org.zwobble.couscous.backends.python.ast.PythonListNode.pythonList; -import static org.zwobble.couscous.types.Types.erasure; +import static java.util.Collections.emptyList; +import static org.zwobble.couscous.ast.ExpressionStatementNode.expressionStatement; +import static org.zwobble.couscous.ast.FormalArgumentNode.formalArg; +import static org.zwobble.couscous.ast.ReturnNode.returns; +import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference; +import static org.zwobble.couscous.ast.TypeCoercionNode.typeCoercion; +import static org.zwobble.couscous.ast.VariableDeclaration.var; +import static org.zwobble.couscous.ast.VariableReferenceNode.reference; import static org.zwobble.couscous.backends.python.ast.PythonAssignmentNode.pythonAssignment; import static org.zwobble.couscous.backends.python.ast.PythonAttributeAccessNode.pythonAttributeAccess; import static org.zwobble.couscous.backends.python.ast.PythonBooleanLiteralNode.pythonBooleanLiteral; @@ -36,15 +44,17 @@ import static org.zwobble.couscous.backends.python.ast.PythonIfStatementNode.pyt import static org.zwobble.couscous.backends.python.ast.PythonImportAliasNode.pythonImportAlias; import static org.zwobble.couscous.backends.python.ast.PythonImportNode.pythonImport; import static org.zwobble.couscous.backends.python.ast.PythonIntegerLiteralNode.pythonIntegerLiteral; +import static org.zwobble.couscous.backends.python.ast.PythonListNode.pythonList; import static org.zwobble.couscous.backends.python.ast.PythonModuleNode.pythonModule; import static org.zwobble.couscous.backends.python.ast.PythonReturnNode.pythonReturn; import static org.zwobble.couscous.backends.python.ast.PythonStringLiteralNode.pythonStringLiteral; import static org.zwobble.couscous.backends.python.ast.PythonVariableReferenceNode.pythonVariableReference; import static org.zwobble.couscous.backends.python.ast.PythonWhileNode.pythonWhile; import static org.zwobble.couscous.backends.python.ast.visitors.PythonExpressionStatement.pythonExpressionStatement; +import static org.zwobble.couscous.types.Types.erasure; import static org.zwobble.couscous.util.Casts.tryCast; -import static org.zwobble.couscous.util.ExtraLists.eagerMap; -import static org.zwobble.couscous.util.ExtraLists.list; +import static org.zwobble.couscous.util.ExtraIterables.*; +import static org.zwobble.couscous.util.ExtraLists.*; public class PythonCodeGenerator { public static PythonModuleNode generateCode(TypeNode typeNode) { @@ -63,9 +73,9 @@ public class PythonCodeGenerator { .map(node -> generateStatements(node.getStaticConstructor())) .orElse(list()); - Iterable<PythonFunctionDefinitionNode> pythonMethods = transform( + Iterable<PythonFunctionDefinitionNode> pythonMethods = lazyFlatMap( filter(typeNode.getMethods(), method -> !method.isAbstract()), - PythonCodeGenerator::generateFunction); + method -> generateMethods(typeNode.getName(), method)); PythonClassNode pythonClass = pythonClass( typeNode.getName().getSimpleName(), @@ -171,6 +181,40 @@ public class PythonCodeGenerator { return pythonFunctionDefinition("__init__", ImmutableList.copyOf(argumentNames), new PythonBlock(pythonBody)); } + private static Iterable<PythonFunctionDefinitionNode> generateMethods(ScalarType type, MethodNode method) { + return lazyMap( + lazyCons(method, generateOverrideMethods(type, method)), + PythonCodeGenerator::generateFunction); + } + + private static Iterable<MethodNode> generateOverrideMethods(ScalarType type, MethodNode methodNode) { + return transform( + methodNode.getOverrides(), + override -> { + List<FormalArgumentNode> arguments = eagerMapWithIndex( + override.getArguments(), + (argument, index) -> formalArg(var(null, "arg" + index, argument))); + MethodCallNode call = MethodCallNode.methodCall( + thisReference(type), + methodNode.getName(), + eagerMap(arguments, argument -> reference(argument)), + methodNode.signature()); + + StatementNode body = override.getReturnType().equals(Types.VOID) + ? expressionStatement(call) + : returns(typeCoercion(call, override.getReturnType())); + + return MethodNode.method( + methodNode.getAnnotations(), + methodNode.isStatic(), + methodNode.getName(), + arguments, + override.getReturnType(), + Optional.of(list(body)), + emptyList()); + }); + } + private static PythonFunctionDefinitionNode generateFunction(MethodNode method) { Iterable<String> explicitArgumentNames = transform(method.getArguments(), argument -> argument.getName()); Iterable<String> argumentNames = Iterables.concat( diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java index fc93345..9055746 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java @@ -40,6 +40,7 @@ import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference; import static org.zwobble.couscous.ast.TypeCoercionNode.typeCoercion; import static org.zwobble.couscous.ast.VariableReferenceNode.reference; import static org.zwobble.couscous.frontends.java.FreeVariables.findFreeVariables; +import static org.zwobble.couscous.frontends.java.JavaMethods.signature; import static org.zwobble.couscous.frontends.java.JavaTypes.*; import static org.zwobble.couscous.types.Types.erasure; import static org.zwobble.couscous.util.Casts.tryCast; @@ -155,14 +156,13 @@ public class JavaReader { functionalInterfaceMethod.getName(), lambda.getFormalArguments(), typeOf(functionalInterfaceMethod.getReturnType()), - Optional.of(lambda.getBody())); - - Iterable<MethodNode> overrides = generateOverrideMethods(name, functionalInterfaceMethod, scope, method); + Optional.of(lambda.getBody()), + overrides(functionalInterfaceMethod)); return new AnonymousClass( superTypesAndSelf(functionalInterfaceMethod.getDeclaringClass()), list(), - ExtraLists.cons(method, overrides)); + list(method)); } private List<StatementNode> replaceCaptureReferences( @@ -397,45 +397,14 @@ public class JavaReader { methodName, formalArguments, returnType.get(), - body); + body, + overrides(method.resolveBinding())); builder.addMethod(methodNode); - - Iterable<MethodNode> overrideMethods = generateOverrideMethods(type, method.resolveBinding(), scope, methodNode); - - for (MethodNode overrideMethod : overrideMethods) { - builder.addMethod(overrideMethod); - } } } - private Iterable<MethodNode> generateOverrideMethods(ScalarType type, IMethodBinding method, Scope scope, MethodNode methodNode) { - return transform( - filter( - overrides(method), - override -> !override.equals(methodNode.signature())), - override -> { - List<FormalArgumentNode> arguments = eagerMapWithIndex(override.getArguments(), (argument, index) -> scope.formalArgument("arg" + index, argument)); - MethodCallNode call = MethodCallNode.methodCall( - thisReference(type), - methodNode.getName(), - eagerMap(arguments, argument -> reference(argument)), - methodNode.signature()); - - StatementNode body = override.getReturnType().equals(Types.VOID) - ? expressionStatement(call) - : returns(typeCoercion(call, override.getReturnType())); - - return MethodNode.method( - methodNode.getAnnotations(), - methodNode.isStatic(), - methodNode.getName(), - arguments, - override.getReturnType(), - Optional.of(list(body))); - }); - } - - private Iterable<MethodSignature> overrides(IMethodBinding methodBinding) { + private List<MethodSignature> overrides(IMethodBinding methodBinding) { + MethodSignature overrideSignature = signature(methodBinding); ITypeBinding declaringClass = methodBinding.getDeclaringClass(); // TODO: remove duplication with JavaTypes @@ -444,6 +413,7 @@ public class JavaReader { .stream() .flatMap(type -> asList(type.getDeclaredMethods()).stream().filter(superMethod -> methodBinding.overrides(superMethod))) .map(JavaMethods::signature) + .filter(signature -> !overrideSignature.equals(signature)) .collect(Collectors.toList()); } diff --git a/src/main/java/org/zwobble/couscous/interpreter/types/UserDefinedInterpreterType.java b/src/main/java/org/zwobble/couscous/interpreter/types/UserDefinedInterpreterType.java index c26fb32..b8c007b 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/types/UserDefinedInterpreterType.java +++ b/src/main/java/org/zwobble/couscous/interpreter/types/UserDefinedInterpreterType.java @@ -19,10 +19,10 @@ import java.util.Set; import static com.google.common.collect.Iterables.filter; import static org.zwobble.couscous.types.ParameterizedType.parameterizedType; import static org.zwobble.couscous.util.Casts.tryCast; -import static org.zwobble.couscous.util.ExtraLists.eagerMap; -import static org.zwobble.couscous.util.ExtraLists.list; -import static org.zwobble.couscous.util.ExtraMaps.map; -import static org.zwobble.couscous.util.ExtraMaps.toMapWithKeys; +import static org.zwobble.couscous.util.ExtraIterables.lazyFlatMap; +import static org.zwobble.couscous.util.ExtraIterables.lazyMap; +import static org.zwobble.couscous.util.ExtraLists.*; +import static org.zwobble.couscous.util.ExtraMaps.*; public class UserDefinedInterpreterType implements InterpreterType { private final TypeNode type; @@ -34,9 +34,14 @@ public class UserDefinedInterpreterType implements InterpreterType { this.fields = tryCast(ClassNode.class, type) .map(classNode -> toMapWithKeys(classNode.getFields(), FieldDeclarationNode::getName)) .orElse(map()); - this.methods = toMapWithKeys( - filter(type.getMethods(), method -> !method.isAbstract()), - method -> method.signature().generic()); + + Iterable<MethodNode> concreteMethods = filter(type.getMethods(), method -> !method.isAbstract()); + + Iterable<Map.Entry<MethodSignature, MethodNode>> entries = lazyFlatMap(concreteMethods, method -> { + List<MethodSignature> signatures = cons(method.signature(), method.getOverrides()); + return lazyMap(signatures, signature -> entry(signature.generic(), method)); + }); + this.methods = toMap(entries); } @Override diff --git a/src/main/java/org/zwobble/couscous/util/ExtraIterables.java b/src/main/java/org/zwobble/couscous/util/ExtraIterables.java index 1fd9fca..cd9b3df 100644 --- a/src/main/java/org/zwobble/couscous/util/ExtraIterables.java +++ b/src/main/java/org/zwobble/couscous/util/ExtraIterables.java @@ -1,7 +1,14 @@ package org.zwobble.couscous.util; +import com.google.common.collect.Iterables; + import java.util.Iterator; import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import static org.zwobble.couscous.util.ExtraLists.list; public class ExtraIterables { private ExtraIterables() {} @@ -69,4 +76,44 @@ public class ExtraIterables { } }; } + + public static <T> Iterable<T> lazyCons(T head, Iterable<T> tails) { + return Iterables.concat(list(head), tails); + } + + public static <T, R> Iterable<R> lazyMap(Iterable<T> iterable, Function<T, R> function) { + return new Iterable<R>() { + @Override + public Iterator<R> iterator() { + return map(iterable.iterator(), function); + } + }; + } + + private static <T, R> Iterator<R> map(Iterator<T> iterator, Function<T, R> function) { + return new Iterator<R>() { + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public R next() { + return function.apply(iterator.next()); + } + }; + } + + public static <T, R> Iterable<R> lazyFlatMap(Iterable<T> iterable, Function<T, Iterable<R>> function) { + return new Iterable<R>() { + @Override + public Iterator<R> iterator() { + return stream(iterable).flatMap(element -> stream(function.apply(element))).iterator(); + } + }; + } + + public static <T> Stream<T> stream(Iterable<T> iterable) { + return StreamSupport.stream(iterable.spliterator(), false); + } } diff --git a/src/main/resources/csharp/runtime/java/lang/Integer.cs b/src/main/resources/csharp/runtime/java/lang/Integer.cs index 8a107b5..6ed87db 100644 --- a/src/main/resources/csharp/runtime/java/lang/Integer.cs +++ b/src/main/resources/csharp/runtime/java/lang/Integer.cs @@ -6,7 +6,7 @@ namespace Couscous.java.lang { _value = value; } - internal override bool equals__Object__boolean(Object other) { + internal override bool equals(Object other) { var integer = other as Integer; return integer != null && integer._value == _value; } diff --git a/src/main/resources/csharp/runtime/java/lang/Object.cs b/src/main/resources/csharp/runtime/java/lang/Object.cs index 2b75c65..14a8f44 100644 --- a/src/main/resources/csharp/runtime/java/lang/Object.cs +++ b/src/main/resources/csharp/runtime/java/lang/Object.cs @@ -1,6 +1,6 @@ namespace Couscous.java.lang { internal class Object { - internal virtual bool equals__Object__boolean(Object other) { + internal virtual bool equals(Object other) { return System.Object.ReferenceEquals(this, other); } diff --git a/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpMethodRunner.java b/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpMethodRunner.java index 2003a4b..aeeac47 100644 --- a/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpMethodRunner.java +++ b/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpMethodRunner.java @@ -7,13 +7,13 @@ import org.zwobble.couscous.Backend; import org.zwobble.couscous.ast.LiteralNode; import org.zwobble.couscous.ast.MethodSignature; import org.zwobble.couscous.ast.TypeNode; -import org.zwobble.couscous.types.ScalarType; -import org.zwobble.couscous.types.Type; -import org.zwobble.couscous.backends.naming.Names; import org.zwobble.couscous.backends.csharp.CsharpBackend; +import org.zwobble.couscous.backends.csharp.CsharpCodeGenerator; import org.zwobble.couscous.backends.csharp.CsharpSerializer; import org.zwobble.couscous.tests.MethodRunner; import org.zwobble.couscous.tests.backends.Processes; +import org.zwobble.couscous.types.ScalarType; +import org.zwobble.couscous.types.Type; import org.zwobble.couscous.types.Types; import org.zwobble.couscous.util.ExtraLists; import org.zwobble.couscous.values.PrimitiveValue; @@ -63,7 +63,7 @@ public class CsharpMethodRunner implements MethodRunner { methodName, eagerMap(arguments, argument -> argument.getType()), returnType); - String csharpMethodName = Names.toUniqueName(signature); + String csharpMethodName = CsharpCodeGenerator.NAMING.methodName(signature); String value = CsharpSerializer.serialize( staticMethodCall( ScalarType.of(NAMESPACE + "." + className.getQualifiedName()), diff --git a/src/test/java/org/zwobble/couscous/tests/frontends/java/InnerTypeReadingTests.java b/src/test/java/org/zwobble/couscous/tests/frontends/java/InnerTypeReadingTests.java index f3e054d..e7585ec 100644 --- a/src/test/java/org/zwobble/couscous/tests/frontends/java/InnerTypeReadingTests.java +++ b/src/test/java/org/zwobble/couscous/tests/frontends/java/InnerTypeReadingTests.java @@ -11,22 +11,22 @@ public class InnerTypeReadingTests { public void lambdaWithNoArgumentsAndExpressionBodyIsReadAsAnonymousClassCreation() { assertEquals( readTypes(generateMethodSource("void", - "java.util.function.Supplier<Integer> supplier = new java.util.function.Supplier<Integer>() {\n" + - " public Integer get() {\n" + + "java.util.function.IntSupplier supplier = new java.util.function.IntSupplier() {\n" + + " public int getAsInt() {\n" + " return 42;\n" + " }\n" + "};")), readTypes(generateMethodSource("void", - "java.util.function.Supplier<Integer> supplier = () -> 42;"))); + "java.util.function.IntSupplier supplier = () -> 42;"))); } @Test public void lambdaWithNoArgumentsAndBlockBodyIsReadAsAnonymousClassCreation() { assertEquals( readTypes(generateMethodSource("void", - "java.util.function.Supplier<Integer> supplier = () -> 42;")), + "java.util.function.IntSupplier supplier = () -> 42;")), readTypes(generateMethodSource("void", - "java.util.function.Supplier<Integer> supplier = () -> { return 42; };"))); + "java.util.function.IntSupplier supplier = () -> { return 42; };"))); } @Test |
