diff options
Diffstat (limited to 'src/main/java/org')
| -rw-r--r-- | src/main/java/org/zwobble/couscous/frontends/java/JavaFrontend.java | 112 | ||||
| -rw-r--r-- | src/main/java/org/zwobble/couscous/frontends/java/JavaParser.java | 31 |
2 files changed, 143 insertions, 0 deletions
diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaFrontend.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaFrontend.java new file mode 100644 index 0000000..53525ce --- /dev/null +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaFrontend.java @@ -0,0 +1,112 @@ +package org.zwobble.couscous.frontends.java; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.BooleanLiteral; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.NumberLiteral; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.Statement; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.ast.ClassNodeBuilder; +import org.zwobble.couscous.ast.ExpressionNode; +import org.zwobble.couscous.ast.LiteralNode; +import org.zwobble.couscous.ast.ReturnNode; +import org.zwobble.couscous.ast.StatementNode; + +import lombok.SneakyThrows; +import lombok.val; + +public class JavaFrontend { + + public static List<ClassNode> readSourceDirectory(Path directoryPath) throws IOException { + val parser = new JavaParser(); + + return findJavaFiles(directoryPath) + .map(javaFile -> readClassFromFile(parser, javaFile)) + .collect(Collectors.toList()); + } + + @SneakyThrows + private static ClassNode readClassFromFile(JavaParser parser, Path path) { + val ast = parser.parseCompilationUnit(path); + val name = generateClassName(ast); + + val classBuilder = new ClassNodeBuilder(name); + + val type = (TypeDeclaration)ast.types().get(0); + + for (val method : type.getMethods()) { + classBuilder.method( + method.getName().getIdentifier(), + true, + builder -> { + for (Object statement : method.getBody().statements()) { + builder.statement(readStatement((Statement)statement)); + } + return builder; + }); + } + + return classBuilder + .build(); + } + + private static StatementNode readStatement(Statement statement) { + switch (statement.getNodeType()) { + case ASTNode.RETURN_STATEMENT: + return readReturnStatement((ReturnStatement)statement); + default: + throw new RuntimeException("Unsupported statement: " + statement.getClass()); + } + } + + private static StatementNode readReturnStatement(ReturnStatement statement) { + return new ReturnNode(readExpression(statement.getExpression())); + } + + private static ExpressionNode readExpression(Expression expression) { + switch (expression.getNodeType()) { + case ASTNode.BOOLEAN_LITERAL: + return readBooleanLiteral((BooleanLiteral)expression); + case ASTNode.NUMBER_LITERAL: + return readNumberLiteral((NumberLiteral)expression); + case ASTNode.STRING_LITERAL: + return readStringLiteral((StringLiteral)expression); + default: + throw new RuntimeException("Unsupported expression: " + expression.getClass()); + } + } + + private static ExpressionNode readBooleanLiteral(BooleanLiteral expression) { + return LiteralNode.literal(expression.booleanValue()); + } + + private static LiteralNode readNumberLiteral(NumberLiteral expression) { + return LiteralNode.literal(Integer.parseInt(expression.getToken())); + } + + private static ExpressionNode readStringLiteral(StringLiteral expression) { + return LiteralNode.literal(expression.getLiteralValue()); + } + + private static String generateClassName(CompilationUnit ast) { + val type = (TypeDeclaration)ast.types().get(0); + return ast.getPackage().getName().getFullyQualifiedName() + "." + type.getName().getFullyQualifiedName(); + } + + private static Stream<Path> findJavaFiles(Path directoryPath) throws IOException { + return Files.walk(directoryPath) + .filter(path -> path.toFile().isFile() && path.toString().endsWith(".java")); + } + +} diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaParser.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaParser.java new file mode 100644 index 0000000..5be2487 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaParser.java @@ -0,0 +1,31 @@ +package org.zwobble.couscous.frontends.java; + +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.CompilationUnit; + +import com.google.common.base.Charsets; + +import lombok.SneakyThrows; +import lombok.val; + +public class JavaParser { + private final ASTParser parser; + + public JavaParser() { + parser = ASTParser.newParser(AST.JLS8); + parser.setResolveBindings(true); + } + + @SneakyThrows + public CompilationUnit parseCompilationUnit(Path path) { + val javaFileBytes = Files.readAllBytes(path); + val javaFileChars = Charsets.UTF_8.decode(ByteBuffer.wrap(javaFileBytes)); + parser.setSource(javaFileChars.array()); + return (CompilationUnit)parser.createAST(null); + } +} |
