diff options
Diffstat (limited to 'src/main')
13 files changed, 146 insertions, 43 deletions
diff --git a/src/main/java/org/zwobble/couscous/Backend.java b/src/main/java/org/zwobble/couscous/Backend.java index 4415593..1c68701 100644 --- a/src/main/java/org/zwobble/couscous/Backend.java +++ b/src/main/java/org/zwobble/couscous/Backend.java @@ -1,10 +1,10 @@ package org.zwobble.couscous; +import org.zwobble.couscous.ast.TypeNode; + import java.io.IOException; import java.util.List; -import org.zwobble.couscous.ast.ClassNode; - public interface Backend { - void compile(List<ClassNode> classes) throws IOException; + void compile(List<TypeNode> classes) throws IOException; } diff --git a/src/main/java/org/zwobble/couscous/CouscousCompiler.java b/src/main/java/org/zwobble/couscous/CouscousCompiler.java index 9c909ac..4822d97 100644 --- a/src/main/java/org/zwobble/couscous/CouscousCompiler.java +++ b/src/main/java/org/zwobble/couscous/CouscousCompiler.java @@ -1,12 +1,12 @@ package org.zwobble.couscous; +import org.zwobble.couscous.ast.TypeNode; +import org.zwobble.couscous.frontends.java.JavaFrontend; + import java.io.IOException; import java.nio.file.Path; import java.util.List; -import org.zwobble.couscous.ast.ClassNode; -import org.zwobble.couscous.frontends.java.JavaFrontend; - public class CouscousCompiler { private final JavaFrontend frontend; private final Backend backend; @@ -17,7 +17,7 @@ public class CouscousCompiler { } public void compileDirectory(List<Path> sourcePaths, Path path) throws IOException { - List<ClassNode> classes = frontend.readSourceDirectory(sourcePaths, path); + List<TypeNode> classes = frontend.readSourceDirectory(sourcePaths, path); backend.compile(classes); } diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNode.java b/src/main/java/org/zwobble/couscous/ast/ClassNode.java index 0aaa8c1..5d6d5e2 100644 --- a/src/main/java/org/zwobble/couscous/ast/ClassNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ClassNode.java @@ -6,7 +6,7 @@ import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.List; import java.util.Set; -public class ClassNode implements Node { +public class ClassNode implements TypeNode { public static ClassNodeBuilder builder(TypeName name) { return new ClassNodeBuilder(name); } @@ -45,11 +45,13 @@ public class ClassNode implements Node { this.constructor = constructor; methods = methodNodes; } - + + @Override public TypeName getName() { return name; } + @Override public Set<TypeName> getSuperTypes() { return superTypes; } @@ -65,7 +67,8 @@ public class ClassNode implements Node { public ConstructorNode getConstructor() { return constructor; } - + + @Override public List<MethodNode> getMethods() { return methods; } diff --git a/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java b/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java new file mode 100644 index 0000000..09d2d3a --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java @@ -0,0 +1,81 @@ +package org.zwobble.couscous.ast; + +import org.zwobble.couscous.ast.visitors.NodeMapper; + +import java.util.List; +import java.util.Set; + +public class InterfaceNode implements TypeNode { + public static InterfaceNode declareInterface( + TypeName name, + Set<TypeName> superTypes, + List<MethodNode> methods) + { + return new InterfaceNode(name, superTypes, methods); + } + + private final TypeName name; + private final Set<TypeName> superTypes; + private final List<MethodNode> methods; + + private InterfaceNode( + TypeName name, + Set<TypeName> superTypes, + List<MethodNode> methodNodes) + { + this.name = name; + this.superTypes = superTypes; + methods = methodNodes; + } + + @Override + public TypeName getName() { + return name; + } + + @Override + public Set<TypeName> getSuperTypes() { + return superTypes; + } + + @Override + public List<MethodNode> getMethods() { + return methods; + } + + @Override + public <T> T accept(NodeMapper<T> visitor) { + // TODO: implement this + return null; + } + + @Override + public String toString() { + return "InterfaceNode(" + + "name=" + name + + ", superTypes=" + superTypes + + ", methods=" + methods + + ')'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + InterfaceNode that = (InterfaceNode) o; + + if (!name.equals(that.name)) return false; + if (!superTypes.equals(that.superTypes)) return false; + return methods.equals(that.methods); + + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + superTypes.hashCode(); + result = 31 * result + methods.hashCode(); + return result; + } +} diff --git a/src/main/java/org/zwobble/couscous/ast/TypeNode.java b/src/main/java/org/zwobble/couscous/ast/TypeNode.java new file mode 100644 index 0000000..9946267 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/TypeNode.java @@ -0,0 +1,10 @@ +package org.zwobble.couscous.ast; + +import java.util.List; +import java.util.Set; + +public interface TypeNode extends Node { + TypeName getName(); + Set<TypeName> getSuperTypes(); + List<MethodNode> getMethods(); +} diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpBackend.java b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpBackend.java index 4ae7704..e98a526 100644 --- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpBackend.java +++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpBackend.java @@ -4,7 +4,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.io.Resources; import org.zwobble.couscous.Backend; -import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.ast.TypeNode; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -30,7 +30,7 @@ public class CsharpBackend implements Backend { } @Override - public void compile(List<ClassNode> classes) throws IOException { + public void compile(List<TypeNode> classes) throws IOException { Files.write( directoryPath.resolve("Program.cs"), Iterables.concat( @@ -50,7 +50,7 @@ public class CsharpBackend implements Backend { } } - private String compileClass(ClassNode classNode) { + private String compileClass(TypeNode classNode) { return CsharpSerializer.serialize(CsharpCodeGenerator.generateCode(classNode, namespace)); } } diff --git a/src/main/java/org/zwobble/couscous/backends/python/PythonBackend.java b/src/main/java/org/zwobble/couscous/backends/python/PythonBackend.java index 731faeb..096bddd 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/PythonBackend.java +++ b/src/main/java/org/zwobble/couscous/backends/python/PythonBackend.java @@ -3,7 +3,7 @@ package org.zwobble.couscous.backends.python; import com.google.common.collect.ImmutableList; import com.google.common.io.Resources; import org.zwobble.couscous.Backend; -import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.ast.TypeNode; import java.io.File; import java.io.IOException; @@ -33,8 +33,8 @@ public class PythonBackend implements Backend { } @Override - public void compile(List<ClassNode> classes) throws IOException { - for (ClassNode classNode : classes) { + public void compile(List<TypeNode> classes) throws IOException { + for (TypeNode classNode : classes) { compileClass(classNode); } for (String runtimeFile : RUNTIME_FILES) { @@ -53,7 +53,7 @@ public class PythonBackend implements Backend { return moduleName.replace(".", File.separator) + ".py"; } - private void compileClass(ClassNode classNode) throws IOException { + private void compileClass(TypeNode classNode) throws IOException { writeModule( classNode.getName().getQualifiedName(), serialize(generateCode(classNode))); 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 ef1aca2..2aafcca 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java +++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java @@ -38,22 +38,24 @@ import static org.zwobble.couscous.backends.python.ast.PythonWhileNode.pythonWhi import static org.zwobble.couscous.util.ExtraLists.list; public class PythonCodeGenerator { - public static PythonModuleNode generateCode(ClassNode classNode) { - Iterator<PythonImportNode> imports = generateImports(classNode).iterator(); + public static PythonModuleNode generateCode(TypeNode typeNode) { + ClassNode classNode = (ClassNode) typeNode; + + Iterator<PythonImportNode> imports = generateImports(typeNode).iterator(); PythonImportNode internalsImport = pythonImport( - importPathToRoot(classNode), + importPathToRoot(typeNode), list(pythonImportAlias("_couscous"))); PythonFunctionDefinitionNode constructor = generateConstructor(classNode.getConstructor()); Iterable<PythonFunctionDefinitionNode> pythonMethods = transform( - classNode.getMethods(), + typeNode.getMethods(), PythonCodeGenerator::generateFunction); PythonClassNode pythonClass = pythonClass( - classNode.getSimpleName(), + typeNode.getName().getSimpleName(), ImmutableList.copyOf(Iterables.concat(list(constructor), pythonMethods))); List<PythonStatementNode> staticConstructor = @@ -66,18 +68,18 @@ public class PythonCodeGenerator { staticConstructor.iterator()))); } - private static Stream<PythonImportNode> generateImports(ClassNode classNode) { + private static Stream<PythonImportNode> generateImports(TypeNode classNode) { Set<TypeName> classes = findReferencedClasses(classNode); return classes.stream() .filter(name -> !name.equals(InternalCouscousValue.REF)) .map(name -> pythonImport(importPathToRoot(classNode) + name.getQualifiedName(), list(pythonImportAlias(name.getSimpleName())))); } - private static String importPathToRoot(ClassNode classNode) { + private static String importPathToRoot(TypeNode classNode) { return Strings.repeat(".", packageDepth(classNode) + 1); } - private static int packageDepth(ClassNode classNode) { + private static int packageDepth(TypeNode classNode) { int depth = 0; final java.lang.String qualifiedName = classNode.getName().getQualifiedName(); for (int index = 0; index < qualifiedName.length(); index++) { @@ -88,7 +90,7 @@ public class PythonCodeGenerator { return depth; } - private static Set<TypeName> findReferencedClasses(ClassNode classNode) { + private static Set<TypeName> findReferencedClasses(TypeNode classNode) { return NodeStructure.descendantNodes(classNode) .flatMap(node -> node.accept(new NodeMapperWithDefault<Stream<TypeName>>(Stream.empty()) { @Override diff --git a/src/main/java/org/zwobble/couscous/cli/CouscousCli.java b/src/main/java/org/zwobble/couscous/cli/CouscousCli.java index 561b3f5..8d4fce1 100644 --- a/src/main/java/org/zwobble/couscous/cli/CouscousCli.java +++ b/src/main/java/org/zwobble/couscous/cli/CouscousCli.java @@ -3,6 +3,7 @@ package org.zwobble.couscous.cli; import org.apache.commons.cli.*; import org.zwobble.couscous.Backend; import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.ast.TypeNode; import org.zwobble.couscous.backends.python.PythonBackend; import org.zwobble.couscous.frontends.java.JavaFrontend; @@ -25,7 +26,7 @@ public class CouscousCli { CommandLine arguments = parseArguments(rawArguments); JavaFrontend frontend = new JavaFrontend(); - List<ClassNode> classNodes = eagerFlatMap( + List<TypeNode> classNodes = eagerFlatMap( arguments.getArgList(), path -> { try { diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaFrontend.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaFrontend.java index 5ab2678..51df264 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaFrontend.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaFrontend.java @@ -1,10 +1,7 @@ package org.zwobble.couscous.frontends.java; import com.google.common.collect.Multimaps; -import org.zwobble.couscous.ast.ClassNode; -import org.zwobble.couscous.ast.Node; -import org.zwobble.couscous.ast.VariableDeclaration; -import org.zwobble.couscous.ast.VariableNode; +import org.zwobble.couscous.ast.*; import java.io.IOException; import java.nio.file.Files; @@ -20,8 +17,8 @@ import static org.zwobble.couscous.util.ExtraLists.flatMap; import static org.zwobble.couscous.util.ExtraStreams.toStream; public class JavaFrontend { - public List<ClassNode> readSourceDirectory(List<Path> sourcePaths, Path directoryPath) throws IOException { - List<ClassNode> classNodes = flatMap( + public List<TypeNode> readSourceDirectory(List<Path> sourcePaths, Path directoryPath) throws IOException { + List<TypeNode> classNodes = flatMap( findJavaFiles(directoryPath), javaFile -> JavaReader.readClassFromFile(sourcePaths, javaFile)); ensureDeclarationsAreUnique(classNodes); @@ -33,7 +30,7 @@ public class JavaFrontend { .filter(path -> path.toFile().isFile() && path.toString().endsWith(".java")); } - private void ensureDeclarationsAreUnique(List<ClassNode> classNodes) { + private void ensureDeclarationsAreUnique(List<TypeNode> classNodes) { List<VariableDeclaration> declarations = eagerFlatMap(classNodes, this::findDeclarations); Multimaps.index(declarations, VariableDeclaration::getId) .asMap() 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 c85b4fb..6e7f3fc 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java @@ -37,7 +37,7 @@ import static org.zwobble.couscous.frontends.java.JavaTypes.*; import static org.zwobble.couscous.util.ExtraLists.*; public class JavaReader { - public static List<ClassNode> readClassFromFile(List<Path> sourcePaths, Path sourcePath) throws IOException { + public static List<TypeNode> readClassFromFile(List<Path> sourcePaths, Path sourcePath) throws IOException { CompilationUnit ast = new JavaParser().parseCompilationUnit(sourcePaths, sourcePath); ImmutableList<IProblem> errors = ImmutableList.copyOf(filter(asList(ast.getProblems()), problem -> problem.isError())); @@ -58,7 +58,7 @@ public class JavaReader { error.getMessage(); } - private final ImmutableList.Builder<ClassNode> classes; + private final ImmutableList.Builder<TypeNode> classes; private int anonymousClassCount = 0; private JavaReader() { diff --git a/src/main/java/org/zwobble/couscous/interpreter/JavaProject.java b/src/main/java/org/zwobble/couscous/interpreter/JavaProject.java index bcb4db6..8038ce1 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/JavaProject.java +++ b/src/main/java/org/zwobble/couscous/interpreter/JavaProject.java @@ -3,6 +3,7 @@ package org.zwobble.couscous.interpreter; import java.util.List; import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.ast.TypeNode; import org.zwobble.couscous.interpreter.values.BoxedIntegerInterpreterValue; import org.zwobble.couscous.interpreter.values.ConcreteType; import org.zwobble.couscous.interpreter.values.InternalCouscousInterpreterValue; @@ -20,7 +21,7 @@ public class JavaProject { .addClass(BoxedIntegerInterpreterValue.TYPE); } - public static Project of(List<ClassNode> classNodes) { + public static Project of(List<TypeNode> classNodes) { Iterable<ConcreteType> concreteTypes = Iterables.transform(classNodes, ConcreteType::fromNode); return builder() .addClasses(concreteTypes) diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java b/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java index cf48d3c..98036f1 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java +++ b/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java @@ -91,13 +91,21 @@ public class ConcreteType { } } - public static ConcreteType fromNode(ClassNode classNode) { + public static ConcreteType fromNode(TypeNode typeNode) { + ClassNode classNode = (ClassNode)typeNode; Map<String, FieldDeclarationNode> fields = classNode.getFields().stream() .collect(toMap( field -> field.getName(), field -> field)); - MethodValue constructor = new MethodValue(getArgumentTypes(classNode.getConstructor().getArguments()), (environment, arguments) -> Executor.callMethod(environment, classNode.getConstructor(), Optional.of(arguments.getReceiver()), arguments.getPositionalArguments())); - Map<MethodSignature, MethodValue> methods = classNode.getMethods() + MethodValue constructor = new MethodValue( + getArgumentTypes(classNode.getConstructor().getArguments()), + (environment, arguments) -> Executor.callMethod( + environment, + classNode.getConstructor(), + Optional.of(arguments.getReceiver()), + arguments.getPositionalArguments())); + + Map<MethodSignature, MethodValue> methods = typeNode.getMethods() .stream() .filter(method -> !method.isStatic()) .collect(toMap(method -> method.signature(), method -> { @@ -106,7 +114,7 @@ public class ConcreteType { return Executor.callMethod(environment, method, Optional.of(arguments.getReceiver()), arguments.getPositionalArguments()); }); })); - Map<MethodSignature, StaticMethodValue> staticMethods = classNode.getMethods() + Map<MethodSignature, StaticMethodValue> staticMethods = typeNode.getMethods() .stream() .filter(method -> method.isStatic()) .collect(toMap(method -> method.signature(), method -> { @@ -116,8 +124,8 @@ public class ConcreteType { }); })); return new ConcreteType( - classNode.getName(), - classNode.getSuperTypes(), + typeNode.getName(), + typeNode.getSuperTypes(), fields, classNode.getStaticConstructor(), constructor, |
