Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<String, Integer> 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";

}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -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;
}
}
8 changes: 8 additions & 0 deletions src/main/java/il/ac/technion/cs/fling/namers/NaiveNamer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Variable, Integer> astChildrenCounter = new HashMap<>();
private final Map<Component, Integer> notationsChildrenCounter = new HashMap<>();
Expand Down Expand Up @@ -168,6 +171,11 @@ public static String getNameFromBase(final String baseName, final Map<String, In
final int position = usedNames.put(baseName, usedNames.get(baseName) + 1);
return baseName + position;
}
public static String unreservedName(final String name) {
if (!SourceVersion.isKeyword(name))
return name;
return unreservedName(name + "_");
}
@Override public String headVariableClassName(final Variable variable) {
return variable.name();
}
Expand Down