diff --git a/src/main/java/il/ac/technion/cs/fling/adapters/JavaASTVisitorAdapter.java b/src/main/java/il/ac/technion/cs/fling/adapters/JavaASTVisitorAdapter.java index 075619f9..f25c6394 100644 --- a/src/main/java/il/ac/technion/cs/fling/adapters/JavaASTVisitorAdapter.java +++ b/src/main/java/il/ac/technion/cs/fling/adapters/JavaASTVisitorAdapter.java @@ -1,117 +1,117 @@ package il.ac.technion.cs.fling.adapters; -import static java.util.stream.Collectors.joining; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; + import il.ac.technion.cs.fling.internal.compiler.Namer; -import il.ac.technion.cs.fling.internal.compiler.ast.nodes.ASTCompilationUnitNode; -import il.ac.technion.cs.fling.internal.compiler.ast.nodes.AbstractClassNode; -import il.ac.technion.cs.fling.internal.compiler.ast.nodes.ClassNode; -import il.ac.technion.cs.fling.internal.compiler.ast.nodes.ConcreteClassNode; -import il.ac.technion.cs.fling.internal.compiler.ast.nodes.FieldNode; +import il.ac.technion.cs.fling.internal.compiler.ast.nodes.*; import il.ac.technion.cs.fling.internal.grammar.rules.Variable; import il.ac.technion.cs.fling.internal.grammar.sententials.quantifiers.JavaCompatibleQuantifier; import il.ac.technion.cs.fling.namers.NaiveNamer; -/** Java adapter printing AST visitor class given AST type definitions. + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static java.lang.String.format; +import static java.util.stream.Collectors.joining; + +/** + * Java adapter printing AST visitor class given AST type definitions. * - * @author Ori Roth */ -@SuppressWarnings("static-method") public class JavaASTVisitorAdapter { + * @author Ori Roth + */ +@SuppressWarnings("static-method") +public class JavaASTVisitorAdapter { private final String astClassName; private final Namer namer; private final String packageName; + public JavaASTVisitorAdapter(final String packageName, final String astClassName, final Namer namer) { this.packageName = packageName; this.astClassName = astClassName; this.namer = namer; } + public String printASTVisitorClass(final ASTCompilationUnitNode compilationUnit) { - return String.format("public static class %s{%s%s}", // - VISITOR_CLASS_NAME, // - compilationUnit.classes.stream() // - .map(this::printVisitMethod) // - .collect(joining()), // - compilationUnit.classes.stream() // - .filter(ClassNode::isConcrete) // - .map(ClassNode::asConcrete) // - .map(this::printWhileVisitingMethod) // - .collect(joining())); + return format("public interface %s{%s}", // + VISITOR_CLASS_NAME, // + compilationUnit.classes.stream() // + .map(this::printVisitMethod) // + .collect(joining())); } + public String printVisitMethod(final AbstractClassNode clazz) { final Variable source = clazz.source; final String parameterName = getNodeParameterName(source); - return String.format("public final void visit(%s %s){%s}", // - getASTVariableClassName(source), // - parameterName, // - printVisitMethodBody(clazz, parameterName)); + return format("default void visit(%s %s){%s}", // + getASTVariableClassName(source), // + parameterName, // + printVisitMethodBody(clazz, parameterName)); } + public String printVisitMethod(final ClassNode clazz) { return clazz.isAbstract() ? // - printVisitMethod(clazz.asAbstract()) : // - printVisitMethod(clazz.asConcrete()); + printVisitMethod(clazz.asAbstract()) : // + printVisitMethod(clazz.asConcrete()); } + public String printVisitMethod(final ConcreteClassNode clazz) { final Variable source = clazz.source; final String parameterName = getNodeParameterName(source); - return String.format("public final void visit(%s %s){%s}", // - getASTVariableClassName(source), // - parameterName, // - printVisitMethodBody(clazz, parameterName)); - } - public String printWhileVisitingMethod(final ConcreteClassNode clazz) { - final Variable source = clazz.source; - final String parameterName = getNodeParameterName(source); - return String.format("public void whileVisiting(%s %s)throws %s{}", // - getASTVariableClassName(source), // - parameterName, // - Exception.class.getCanonicalName()); + return format("default void visit(%s %s){%s}", // + getASTVariableClassName(source), // + parameterName, // + printVisitMethodBody(clazz, parameterName)); } + private String getASTVariableClassName(final Variable variable) { - return String.format("%s.%s.%s", // - packageName, // - astClassName, // - namer.getASTClassName(variable)); + return format("%s.%s.%s", // + packageName, // + astClassName, // + namer.getASTClassName(variable)); } + private String getNodeParameterName(final Variable variable) { return NaiveNamer.lowerCamelCase(variable.name()); } + private String printVisitMethodBody(final AbstractClassNode clazz, final String parameterName) { return clazz.children.stream() // - .map(child -> String.format("if(%s instanceof %s)%s", // - parameterName, // - getASTVariableClassName(child.source), // - variableVisitingStatement(child.source, parameterName))) // - .collect(joining("else ")); + .map(child -> format("if(%s instanceof %s)%s", // + parameterName, // + getASTVariableClassName(child.source), // + variableVisitingStatement(child.source, parameterName))) // + .collect(joining("else ")); } + private String printVisitMethodBody(final ConcreteClassNode clazz, final String parameterName) { final StringBuilder $ = new StringBuilder(); final Map usedNames = new LinkedHashMap<>(); - $.append(String.format("try{this.whileVisiting(%s);}catch(%s __){__.printStackTrace();}", // - parameterName, // - Exception.class.getCanonicalName())); clazz.fields.stream() // - .map(FieldNode::source) // - .forEach(source -> { - assert !source.isQuantifier() || source.getClass() - .isAnnotationPresent(JavaCompatibleQuantifier.class) : "BNF uses a non-Java-compatible notation"; - }); + .map(FieldNode::source) // + .forEach(source -> { + assert !source.isQuantifier() || source.getClass() + .isAnnotationPresent(JavaCompatibleQuantifier.class) : "BNF uses a non-Java-compatible notation"; + }); clazz.fields.stream() // - .map(FieldNode::getInferredFieldFragments) // - .flatMap(List::stream) // - .map(field -> field.visitingStatement(// - this::variableVisitingStatement, // - String.format("%s.%s", // - parameterName, // - field.parameterName), // - () -> NaiveNamer.getNameFromBase("_x_", usedNames))) - .filter(Objects::nonNull) // - .forEach($::append); + .map(FieldNode::getInferredFieldFragments) // + .flatMap(List::stream) // + .map(field -> field.visitingStatement(// + this::variableVisitingStatement, // + format("%s.%s", // + parameterName, // + field.parameterName), // + () -> NaiveNamer.getNameFromBase("_x_", usedNames))) + .filter(Objects::nonNull) // + .forEach($::append); return $.toString(); } + private String variableVisitingStatement(final Variable variable, final String access) { - return String.format("{visit((%s)%s);}", // - getASTVariableClassName(variable), // - access); + return format("{visit((%s)%s);}", // + getASTVariableClassName(variable), // + access); } + private static final String VISITOR_CLASS_NAME = "Visitor"; + } diff --git a/src/main/java/il/ac/technion/cs/fling/internal/grammar/types/ClassParameter.java b/src/main/java/il/ac/technion/cs/fling/internal/grammar/types/ClassParameter.java index 409f3010..f4fa42da 100644 --- a/src/main/java/il/ac/technion/cs/fling/internal/grammar/types/ClassParameter.java +++ b/src/main/java/il/ac/technion/cs/fling/internal/grammar/types/ClassParameter.java @@ -1,6 +1,8 @@ package il.ac.technion.cs.fling.internal.grammar.types; + +import static il.ac.technion.cs.fling.namers.NaiveNamer.lowerCamelCase; +import static il.ac.technion.cs.fling.namers.NaiveNamer.unreservedName; import static java.util.Objects.requireNonNull; -import il.ac.technion.cs.fling.namers.NaiveNamer; // TODO allow primitive types. public class ClassParameter implements StringTypeParameter { public final Class parameterClass; @@ -11,7 +13,9 @@ public ClassParameter(final Class parameterClass) { return parameterClass.getCanonicalName(); } @Override public String baseParameterName() { - return unPrimitiveTypeSimple(NaiveNamer.lowerCamelCase(parameterClass.getSimpleName())); + if (parameterClass.isPrimitive()) + return parameterClass.getSimpleName().substring(0, 1); + return unreservedName(lowerCamelCase(parameterClass.getSimpleName())); } @Override public int hashCode() { return parameterClass.hashCode(); @@ -39,16 +43,4 @@ public static String unPrimitiveType(final String typeName) { void.class.getName().equals(typeName) ? Void.class.getCanonicalName() : // typeName; } - public static String unPrimitiveTypeSimple(final String typeName) { - return byte.class.getName().equals(typeName) ? "b" : // - short.class.getName().equals(typeName) ? "s" : // - int.class.getName().equals(typeName) ? "i" : // - long.class.getName().equals(typeName) ? "l" : // - float.class.getName().equals(typeName) ? "f" : // - double.class.getName().equals(typeName) ? "d" : // - boolean.class.getName().equals(typeName) ? "b" : // - char.class.getName().equals(typeName) ? "c" : // - void.class.getName().equals(typeName) ? "v" : // - typeName; - } } diff --git a/src/main/java/il/ac/technion/cs/fling/namers/NaiveNamer.java b/src/main/java/il/ac/technion/cs/fling/namers/NaiveNamer.java index a85b3b76..e33e438c 100644 --- a/src/main/java/il/ac/technion/cs/fling/namers/NaiveNamer.java +++ b/src/main/java/il/ac/technion/cs/fling/namers/NaiveNamer.java @@ -23,6 +23,9 @@ import il.ac.technion.cs.fling.internal.grammar.rules.Component; import il.ac.technion.cs.fling.internal.grammar.rules.Constants; import il.ac.technion.cs.fling.internal.grammar.rules.Variable; + +import javax.lang.model.SourceVersion; + public class NaiveNamer implements Namer { private final Map astChildrenCounter = new HashMap<>(); private final Map notationsChildrenCounter = new HashMap<>(); @@ -168,6 +171,11 @@ public static String getNameFromBase(final String baseName, final Map