This commit is contained in:
Daniel Holle 2023-08-18 15:15:40 +02:00
parent 729e88bc6d
commit 5f1f698530
24 changed files with 104 additions and 110 deletions

View File

@ -304,6 +304,7 @@ formalParameterList
formalParameter
: variableModifier* typeType? variableDeclaratorId
| pattern // Pattern matching for Methods
;
lastFormalParameter

View File

@ -720,7 +720,7 @@ public class Codegen {
} else {
var name = "lambda$" + lambdaCounter++;
var parameters = new ArrayList<>(lambda.captures());
parameters.addAll(lambda.params().stream().map(param -> param.type() instanceof TargetGenericType ? new MethodParameter(TargetType.Object, param.name()) : param).toList());
parameters.addAll(lambda.params().stream().map(param -> param.pattern().type() instanceof TargetGenericType ? param.withType(TargetType.Object) : param).toList());
impl = new TargetMethod(0, name, lambda.block(), new TargetMethod.Signature(Set.of(), parameters, lambda.returnType() instanceof TargetGenericType ? TargetType.Object : lambda.returnType()), null);
generateMethod(impl);
@ -744,14 +744,16 @@ public class Codegen {
var params = new ArrayList<TargetType>();
params.add(new TargetRefType(clazz.qualifiedName()));
params.addAll(lambda.captures().stream().map(MethodParameter::type).toList());
params.addAll(lambda.captures().stream().map(mp -> mp.pattern().type()).toList());
var descriptor = TargetMethod.getDescriptor(lambda.type(), params.toArray(TargetType[]::new));
mv.visitVarInsn(ALOAD, 0);
for (var capture : lambda.captures())
mv.visitVarInsn(ALOAD, state.scope.get(capture.name()).index);
for (var capture : lambda.captures()) {
var pattern = (TargetTypePattern) capture.pattern();
mv.visitVarInsn(ALOAD, state.scope.get(pattern.name()).index);
}
mv.visitInvokeDynamicInsn("apply", descriptor, bootstrap, Type.getType(desugared), handle, Type.getType(TargetMethod.getDescriptor(impl.signature().returnType(), lambda.params().stream().map(MethodParameter::type).toArray(TargetType[]::new))));
mv.visitInvokeDynamicInsn("apply", descriptor, bootstrap, Type.getType(desugared), handle, Type.getType(TargetMethod.getDescriptor(impl.signature().returnType(), lambda.params().stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new))));
}
private void generate(State state, TargetExpression expr) {
@ -1287,8 +1289,12 @@ public class Codegen {
mv.visitCode();
var state = new State(null, mv, 1);
for (var param : constructor.parameters())
state.createVariable(param.name(), param.type());
for (var param : constructor.parameters()) {
var pattern = param.pattern();
if (pattern instanceof TargetTypePattern tp)
state.createVariable(tp.name(), tp.type());
else throw new NotImplementedException();
}
var stmts = constructor.block().statements();
generate(state, stmts.get(0));
@ -1315,8 +1321,12 @@ public class Codegen {
mv.visitCode();
var state = new State(method.signature().returnType(), mv, method.isStatic() ? 0 : 1);
for (var param : method.signature().parameters())
state.createVariable(param.name(), param.type());
for (var param : method.signature().parameters()) {
var pattern = param.pattern();
if (pattern instanceof TargetTypePattern tp)
state.createVariable(tp.name(), tp.type());
else throw new NotImplementedException();
}
generate(state, method.block());
if (method.signature().returnType() == null)
mv.visitInsn(RETURN);

View File

@ -168,7 +168,7 @@ public class JavaTXCompiler {
// werden
while (methodIt.hasNext()) {
Method m = methodIt.next();
ParameterList newParaList = new ParameterList(m.getParameterList().getFormalparalist().stream().map(fp -> new FormalParameter(fp.getName(), fp.getType().acceptTV(new TypeExchanger(gtvs)), fp.getOffset())).collect(Collectors.toCollection(ArrayList::new)), m.getParameterList().getOffset());
ParameterList newParaList = new ParameterList(m.getParameterList().getFormalparalist().stream().map(fp -> fp.withType(fp.getType().acceptTV(new TypeExchanger(gtvs)))).collect(Collectors.toCollection(ArrayList::new)), m.getParameterList().getOffset());
cl.getMethods().add(new Method(m.modifier, m.name, m.getReturnType().acceptTV(new TypeExchanger(gtvs)), newParaList, m.block,
// new GenericDeclarationList(newGenericsList,
// ((GenericDeclarationList)m.getGenerics()).getOffset()),

View File

@ -148,7 +148,7 @@ public class StatementGenerator {
}
public ParameterList convert(Java17Parser.FormalParameterListContext formalParameterListContext) {
List<FormalParameter> ret = new ArrayList<>();
List<Pattern> ret = new ArrayList<>();
List<Java17Parser.FormalParameterContext> fps = new ArrayList<>();
if (Objects.isNull(formalParameterListContext))
return new ParameterList(ret, new NullToken()); // Dann ist die Parameterliste leer
@ -161,6 +161,7 @@ public class StatementGenerator {
fps = formalParameterListContext.formalParameter();
for (Java17Parser.FormalParameterContext fp : fps) {
if (fp.pattern() != null) throw new NotImplementedException();
String paramName = SyntaxTreeGenerator.convert(fp.variableDeclaratorId());
RefTypeOrTPHOrWildcardOrGeneric type;
if (fp.typeType() != null) {
@ -1033,7 +1034,7 @@ public class StatementGenerator {
Java17Parser.LambdaParametersContext lambdaParams = expression.lambdaParameters();
ParameterList params;
if (lambdaParams.identifier().size() > 0) {
List<FormalParameter> parameterList = new ArrayList<>();
List<Pattern> parameterList = new ArrayList<>();
for (IdentifierContext identifier : lambdaParams.identifier()) {
Token offset = identifier.getStart();
parameterList.add(new FormalParameter(identifier.getText(), TypePlaceholder.fresh(offset), offset));
@ -1043,7 +1044,7 @@ public class StatementGenerator {
params = convert(lambdaParams.formalParameterList());
// }else if( lambdaParams.inferredFormalParameterList != null){
} else if (!Objects.isNull(lambdaParams.lambdaLVTIList())) {
List<FormalParameter> parameterList = new ArrayList<>();
List<Pattern> parameterList = new ArrayList<>();
for (LambdaLVTIParameterContext param : lambdaParams.lambdaLVTIList().lambdaLVTIParameter()) {
Token offset = param.getStart();
parameterList.add(new FormalParameter(param.identifier().getText(), TypePlaceholder.fresh(offset), offset));
@ -1055,8 +1056,9 @@ public class StatementGenerator {
HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> lambdaLocals = new HashMap<>();
lambdaLocals.putAll(localVars);
for (FormalParameter param : params.getFormalparalist()) {
lambdaLocals.put(param.getName(), param.getType());
for (Pattern param : params.getFormalparalist()) {
if (!(param instanceof FormalParameter fp)) throw new IllegalArgumentException();
lambdaLocals.put(fp.getName(), fp.getType());
}
StatementGenerator lambdaGenerator = new StatementGenerator(reg, generics, fields, lambdaLocals);

View File

@ -12,6 +12,8 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.Record;
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.Token;
@ -61,15 +63,6 @@ import de.dhbwstuttgart.parser.scope.GatherNames;
import de.dhbwstuttgart.parser.scope.GenericsRegistry;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.parser.scope.JavaClassRegistry;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.Constructor;
import de.dhbwstuttgart.syntaxtree.Field;
import de.dhbwstuttgart.syntaxtree.FormalParameter;
import de.dhbwstuttgart.syntaxtree.GenericDeclarationList;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.ParameterList;
import de.dhbwstuttgart.syntaxtree.Record;
import de.dhbwstuttgart.syntaxtree.SourceFile;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.statement.Assign;
import de.dhbwstuttgart.syntaxtree.statement.AssignLeftSide;
@ -256,7 +249,7 @@ public class SyntaxTreeGenerator {
List<Constructor> constructors = new ArrayList<>();
Boolean isInterface = false;
List<RefType> implementedInterfaces = new ArrayList<>();
List<FormalParameter> constructorParameters = new ArrayList<>();
List<Pattern> constructorParameters = new ArrayList<>();
List<Statement> constructorStatements = new ArrayList<>();
for (RecordComponentContext component : recordDeclaration.recordHeader().recordComponentList().recordComponent()) {
int fieldmodifiers = allmodifiers.get("private") + allmodifiers.get("final");

View File

@ -66,7 +66,7 @@ public abstract class AbstractASTWalker implements ASTVisitor {
@Override
public void visit(ParameterList formalParameters) {
Iterator<FormalParameter> it = formalParameters.getFormalparalist().iterator();
Iterator<Pattern> it = formalParameters.getFormalparalist().iterator();
if (it.hasNext()) {
while (it.hasNext()) {
it.next().accept(this);

View File

@ -20,4 +20,9 @@ public class ExpressionPattern extends Pattern {
public void accept(ASTVisitor visitor) {
visitor.visit(this);
}
@Override
public ExpressionPattern withType(RefTypeOrTPHOrWildcardOrGeneric type) {
return new ExpressionPattern(expression, getOffset());
}
}

View File

@ -19,4 +19,9 @@ public class FormalParameter extends Pattern {
public void accept(ASTVisitor visitor) {
visitor.visit(this);
}
@Override
public FormalParameter withType(RefTypeOrTPHOrWildcardOrGeneric type) {
return new FormalParameter(name, type, getOffset());
}
}

View File

@ -1,6 +1,7 @@
package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.syntaxtree.statement.Expression;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import org.antlr.v4.runtime.Token;
public class GuardedPattern extends Pattern {
@ -26,4 +27,9 @@ public class GuardedPattern extends Pattern {
public void accept(ASTVisitor visitor) {
visitor.visit(this);
}
@Override
public GuardedPattern withType(RefTypeOrTPHOrWildcardOrGeneric type) {
return new GuardedPattern(condition, nested, getOffset());
}
}

View File

@ -5,27 +5,27 @@ import org.antlr.v4.runtime.Token;
import java.util.Iterator;
import java.util.List;
public class ParameterList extends SyntaxTreeNode implements Iterable<FormalParameter> {
private List<FormalParameter> formalparameter;
public class ParameterList extends SyntaxTreeNode implements Iterable<Pattern> {
private List<Pattern> formalparameter;
public ParameterList(List<FormalParameter> params, Token offset) {
public ParameterList(List<Pattern> params, Token offset) {
super(offset);
this.formalparameter = params;
}
public FormalParameter getParameterAt(int i) {
public Pattern getParameterAt(int i) {
if (i >= formalparameter.size())
return null;
return formalparameter.get(i);
}
public List<FormalParameter> getFormalparalist() {
public List<Pattern> getFormalparalist() {
return formalparameter;
}
@Override
public Iterator<FormalParameter> iterator() {
public Iterator<Pattern> iterator() {
return formalparameter.iterator();
}

View File

@ -14,4 +14,6 @@ public abstract class Pattern extends SyntaxTreeNode {
public RefTypeOrTPHOrWildcardOrGeneric getType(){
return type;
}
public abstract Pattern withType(RefTypeOrTPHOrWildcardOrGeneric type);
}

View File

@ -163,7 +163,7 @@ public class ASTFactory {
RefTypeOrTPHOrWildcardOrGeneric returnType = createType(inClass);
Parameter[] jreParams = constructor.getParameters();
Type[] jreGenericParams = constructor.getGenericParameterTypes();
List<FormalParameter> params = new ArrayList<>();
List<Pattern> params = new ArrayList<>();
int i = 0;
for (Type jreParam : jreGenericParams) {
if (jreParam == null)
@ -197,7 +197,7 @@ public class ASTFactory {
returnType = createType(jreRetType);
Parameter[] jreParams = jreMethod.getParameters();
Type[] jreGenericParams = jreMethod.getGenericParameterTypes();
List<FormalParameter> params = new ArrayList<>();
List<Pattern> params = new ArrayList<>();
int i = 0;
for (Type jreParam : jreGenericParams) {
if (jreParam == null)

View File

@ -100,7 +100,7 @@ public class OutputGenerator implements ASTVisitor {
@Override
public void visit(ParameterList formalParameters) {
out.append("(");
Iterator<FormalParameter> genericIterator = formalParameters.getFormalparalist().iterator();
Iterator<Pattern> genericIterator = formalParameters.getFormalparalist().iterator();
if (genericIterator.hasNext()) {
while (genericIterator.hasNext()) {
genericIterator.next().accept(this);
@ -264,9 +264,9 @@ public class OutputGenerator implements ASTVisitor {
@Override
public void visit(InstanceOf instanceOf) {
instanceOf.lexpr.accept(this);
instanceOf.getExpression().accept(this);
out.append(" instanceof ");
instanceOf.rexpr.accept(this);
instanceOf.getPattern().accept(this);
}
@Override

View File

@ -3,6 +3,7 @@ package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.bytecode.FunNGenerator;
import de.dhbwstuttgart.environment.ByteArrayClassLoader;
import de.dhbwstuttgart.environment.IByteArrayClassLoader;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.Record;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
@ -12,6 +13,7 @@ import de.dhbwstuttgart.target.tree.*;
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import de.dhbwstuttgart.target.tree.expression.TargetExpression;
import de.dhbwstuttgart.target.tree.expression.TargetSwitch;
import de.dhbwstuttgart.target.tree.expression.TargetTypePattern;
import de.dhbwstuttgart.target.tree.type.*;
import de.dhbwstuttgart.typeinference.result.*;
@ -150,7 +152,10 @@ public class ASTToTargetAST {
}
private List<MethodParameter> convert(ParameterList input, GenerateGenerics generics) {
return input.getFormalparalist().stream().map(param -> new MethodParameter(convert(param.getType(), generics), param.getName())).toList();
return input.getFormalparalist().stream().map(param -> switch(param) {
case FormalParameter fpm -> new MethodParameter(new TargetTypePattern(convert(param.getType(), generics), fpm.getName()));
default -> throw new NotImplementedException();
}).toList();
}
private boolean hasGeneric(Set<TargetGeneric> generics, GenericRefType type) {

View File

@ -31,7 +31,10 @@ public class StatementToTargetExpression implements ASTVisitor {
@Override
public void visit(LambdaExpression lambdaExpression) {
var parameters = StreamSupport.stream(lambdaExpression.params.spliterator(), false).map(p -> new MethodParameter(converter.convert(p.getType()), p.getName())).toList();
var parameters = StreamSupport.stream(lambdaExpression.params.spliterator(), false)
.map(p -> (FormalParameter) p)
.map(p -> new MethodParameter(new TargetTypePattern(converter.convert(p.getType()), p.getName())))
.toList();
List<MethodParameter> captures = new ArrayList<>();
lambdaExpression.methodBody.accept(new TracingStatementVisitor() {
@ -59,7 +62,7 @@ public class StatementToTargetExpression implements ASTVisitor {
@Override
public void visit(LocalVar localVar) {
super.visit(localVar);
var capture = new MethodParameter(converter.convert(localVar.getType()), localVar.name);
var capture = new MethodParameter(new TargetTypePattern(converter.convert(localVar.getType()), localVar.name));
if (!hasLocalVar(localVar.name) && !parameters.contains(capture) && !captures.contains(capture))
captures.add(capture);
}
@ -106,7 +109,6 @@ public class StatementToTargetExpression implements ASTVisitor {
case BIGGEREQUAL -> new TargetBinaryOp.GreaterOrEqual(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
case EQUAL -> new TargetBinaryOp.Equal(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
case NOTEQUAL -> new TargetBinaryOp.NotEqual(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
case INSTOF -> new TargetBinaryOp.Instof(converter.convert(binary.getType()), converter.convert(binary.lexpr), converter.convert(binary.rexpr));
};
}

View File

@ -1,6 +1,14 @@
package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.target.tree.expression.TargetPattern;
import de.dhbwstuttgart.target.tree.expression.TargetTypePattern;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record MethodParameter(TargetType type, String name) {
public record MethodParameter(TargetPattern pattern) {
public MethodParameter(TargetType type, String name) {
this(new TargetTypePattern(type, name));
}
public MethodParameter withType(TargetType type) {
return new MethodParameter(pattern.withType(type));
}
}

View File

@ -10,7 +10,7 @@ import java.util.Set;
public record TargetConstructor(int access, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<MethodParameter> parameters, List<MethodParameter> txParameters, TargetBlock block, TargetBlock fieldInitializer) {
public String getDescriptor() {
return TargetMethod.getDescriptor(null, parameters.stream().map(MethodParameter::type).toArray(TargetType[]::new));
return TargetMethod.getDescriptor(null, parameters.stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new));
}
public String getSignature() {

View File

@ -32,7 +32,7 @@ public record TargetMethod(int access, String name, TargetBlock block, Signature
}
ret += "(";
for (var param : parameters) {
ret += param.type().toDescriptor();
ret += param.pattern().type().toDescriptor();
}
ret += ")";
if (returnType == null) ret += "V";
@ -41,7 +41,7 @@ public record TargetMethod(int access, String name, TargetBlock block, Signature
}
public String getDescriptor() {
return getDescriptor(signature.returnType, signature.parameters.stream().map(MethodParameter::type).toArray(TargetType[]::new));
return getDescriptor(signature.returnType, signature.parameters.stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new));
}
public String getSignature() {

View File

@ -5,4 +5,8 @@ import de.dhbwstuttgart.target.tree.type.TargetType;
import java.util.List;
public record TargetComplexPattern(TargetType type, String name, List<TargetPattern> subPatterns) implements TargetPattern {
@Override
public TargetComplexPattern withType(TargetType type) {
return new TargetComplexPattern(type, name, subPatterns);
}
}

View File

@ -1,4 +1,10 @@
package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record TargetGuard(TargetPattern inner, TargetExpression expression) implements TargetPattern {
@Override
public TargetGuard withType(TargetType type) {
return new TargetGuard(inner.withType(type), expression);
}
}

View File

@ -1,7 +1,11 @@
package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.TargetType;
public sealed interface TargetPattern extends TargetExpression permits TargetComplexPattern, TargetGuard, TargetTypePattern {
default String name() {
return null;
}
TargetPattern withType(TargetType type);
}

View File

@ -3,4 +3,8 @@ package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record TargetTypePattern(TargetType type, String name) implements TargetPattern {
@Override
public TargetTypePattern withType(TargetType type) {
return new TargetTypePattern(type, name);
}
}

View File

@ -9,13 +9,7 @@ import de.dhbwstuttgart.exceptions.TypeinferenceException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.FormalParameter;
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.ParameterList;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.TypeScope;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.factory.NameGenerator;
import de.dhbwstuttgart.syntaxtree.statement.ArgumentList;
@ -699,7 +693,7 @@ public class TYPEStmt implements StatementVisitor {
* Hier kriegt der Receiver ja den COnstraint TPH REceiver <. List<TPH A> Dann mus bei dem Parameter der COnstraint entstehen: TPH A <. String
*/
List<RefTypeOrTPHOrWildcardOrGeneric> params = new ArrayList<>();
for (FormalParameter fp : parameterList.getFormalparalist()) {
for (Pattern fp : parameterList.getFormalparalist()) {
params.add(fp.getType()); // info.checkGTV(fp.getType())); //PL 2018-06-22 GTV sollen in Argumenten erhalten bleiben
}
return params;

View File

@ -1,57 +0,0 @@
package constraintSimplify;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.statement.Block;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import org.junit.Test;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Optional;
public class FamilyOfGenerics {
@Test
public void generateBC() throws Exception {
/*
* SourceFile sf = generateAST(); PositionFinder.getPositionOfTPH(sf, null); TPHExtractor tphExtractor = new TPHExtractor(); List<ResultSet> results = new ArrayList<ResultSet>(); GeneratedGenericsFinder generatedGenericsFinder = new GeneratedGenericsFinder(sf, results);
*/
}
public static SourceFile generateAST() {
ArrayList<ClassOrInterface> classes = new ArrayList<>();
ArrayList<Field> fields = new ArrayList<>();
ArrayList<Method> methods = new ArrayList<>();
fields.add(generateField("fld1"));
String[] paramNames = { "a" };
methods.add(generateMethod("testMethode", paramNames));
classes.add(new ClassOrInterface(Modifier.PUBLIC, new JavaClassName("Test"), fields, Optional.empty(), methods, new ArrayList<>(), generateEmptyGenericDeclList(), new RefType(new JavaClassName("java.lang.Object"), new NullToken()), false, new ArrayList<>(), new ArrayList<>(), new NullToken()));
return new SourceFile("Test.jav", classes, new HashSet<>());
}
public static Method generateMethod(String methodName, String[] paramNames) {
ArrayList<FormalParameter> parameters = new ArrayList<>();
for (String str : paramNames) {
FormalParameter fp = new FormalParameter(str, TypePlaceholder.fresh(new NullToken()), new NullToken());
parameters.add(fp);
}
ParameterList parameterList = new ParameterList(parameters, new NullToken());
return new Method(Modifier.PUBLIC, methodName, TypePlaceholder.fresh(new NullToken()), parameterList, new Block(new ArrayList<>(), new NullToken()), generateEmptyGenericDeclList(), new NullToken());
}
public static GenericDeclarationList generateEmptyGenericDeclList() {
return new GenericDeclarationList(new ArrayList<>(), new NullToken());
}
public static Field generateField(String fieldName) {
return new Field(fieldName, TypePlaceholder.fresh(new NullToken()), Modifier.PUBLIC, new NullToken());
}
}