/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.object.dsl.processor;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import com.oracle.truffle.api.object.Layout;
import com.oracle.truffle.object.dsl.processor.model.LayoutModel;
import com.oracle.truffle.object.dsl.processor.model.NameUtils;
import com.oracle.truffle.object.dsl.processor.model.PropertyModel;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
public class LayoutGenerator {
private final LayoutModel layout;
public LayoutGenerator(LayoutModel layout) {
this.layout = layout;
}
public void generate(final PrintStream stream) {
stream.printf("package %s;%n", layout.getPackageName());
stream.println();
generateImports(stream);
stream.println();
stream.printf("@GeneratedBy(%s.class)%n", layout.getInterfaceFullName());
stream.printf("public class %sLayoutImpl", layout.getName());
if (layout.getSuperLayout() != null) {
stream.printf(" extends %sLayoutImpl", layout.getSuperLayout().getName());
}
stream.printf(" implements %sLayout {%n", layout.getName());
stream.println(" ");
stream.printf(" public static final %sLayout INSTANCE = new %sLayoutImpl();%n", layout.getName(), layout.getName());
stream.println(" ");
generateObjectType(stream);
if (!layout.hasShapeProperties()) {
stream.printf(" protected static final %sType %s_TYPE = new %sType();%n", layout.getName(),
NameUtils.identifierToConstant(layout.getName()), layout.getName());
stream.println(" ");
}
generateAllocator(stream);
generateProperties(stream);
if (!layout.hasShapeProperties()) {
stream.printf(" private static final DynamicObjectFactory %s_FACTORY = create%sShape();%n",
NameUtils.identifierToConstant(layout.getName()), layout.getName());
stream.println(" ");
}
stream.printf(" protected %sLayoutImpl() {%n", layout.getName());
stream.println(" }");
stream.println(" ");
generateShapeFactory(stream);
generateFactory(stream);
generateGuards(stream);
generateAccessors(stream);
stream.println("}");
}
private void generateImports(PrintStream stream) {
boolean needsAtomicInteger = false;
boolean needsAtomicBoolean = false;
boolean needsAtomicReference = false;
boolean needsIncompatibleLocationException = false;
boolean needsFinalLocationException = false;
boolean needsHiddenKey = false;
boolean needsBoundary = false;
for (PropertyModel property : layout.getProperties()) {
if (!property.isShapeProperty() && !property.hasIdentifier()) {
needsHiddenKey = true;
}
if (property.isVolatile()) {
if (property.getType().getKind() == TypeKind.INT) {
needsAtomicInteger = true;
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
needsAtomicBoolean = true;
} else {
needsAtomicReference = true;
}
} else {
if (property.hasSetter()) {
if (!property.isShapeProperty()) {
needsIncompatibleLocationException = true;
needsFinalLocationException = true;
}
}
}
if (property.isShapeProperty() && (property.hasSetter() || property.hasShapeSetter())) {
needsBoundary = true;
}
}
if (layout.hasFinalInstanceProperties() || layout.hasNonNullableInstanceProperties()) {
stream.println("import java.util.EnumSet;");
}
if (needsAtomicBoolean) {
stream.println("import java.util.concurrent.atomic.AtomicBoolean;");
}
if (needsAtomicInteger) {
stream.println("import java.util.concurrent.atomic.AtomicInteger;");
}
if (needsAtomicReference) {
stream.println("import java.util.concurrent.atomic.AtomicReference;");
}
if (!layout.hasBuilder()) {
stream.println("import com.oracle.truffle.api.CompilerAsserts;");
}
stream.println("import com.oracle.truffle.api.dsl.GeneratedBy;");
if (needsBoundary) {
stream.println("import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;");
}
stream.println("import com.oracle.truffle.api.object.DynamicObject;");
stream.println("import com.oracle.truffle.api.object.DynamicObjectFactory;");
if (needsFinalLocationException) {
stream.println("import com.oracle.truffle.api.object.FinalLocationException;");
}
if (needsHiddenKey) {
stream.println("import com.oracle.truffle.api.object.HiddenKey;");
}
if (needsIncompatibleLocationException) {
stream.println("import com.oracle.truffle.api.object.IncompatibleLocationException;");
}
if (layout.getSuperLayout() == null) {
stream.println("import com.oracle.truffle.api.object.Layout;");
}
if (layout.hasFinalInstanceProperties() || layout.hasNonNullableInstanceProperties()) {
stream.println("import com.oracle.truffle.api.object.LocationModifier;");
}
stream.println("import com.oracle.truffle.api.object.ObjectType;");
if (!layout.getInstanceProperties().isEmpty()) {
stream.println("import com.oracle.truffle.api.object.Property;");
}
stream.println("import com.oracle.truffle.api.object.Shape;");
stream.printf("import %s;%n", layout.getInterfaceFullName());
if (layout.getSuperLayout() != null) {
stream.printf("import %s.%sLayoutImpl;%n", layout.getSuperLayout().getPackageName(), layout.getSuperLayout().getName());
}
}
private void generateObjectType(final PrintStream stream) {
final String typeSuperclass;
if (layout.getSuperLayout() == null) {
typeSuperclass = layout.getObjectTypeSuperclass().toString();
} else {
typeSuperclass = layout.getSuperLayout().getName() + "LayoutImpl." + layout.getSuperLayout().getName() + "Type";
}
stream.printf(" public static class %sType extends %s {%n", layout.getName(), typeSuperclass);
if (layout.hasShapeProperties()) {
stream.println(" ");
for (PropertyModel property : layout.getShapeProperties()) {
stream.printf(" protected final %s %s;%n", property.getType(), property.getName());
}
if (!layout.getShapeProperties().isEmpty()) {
stream.println(" ");
}
stream.printf(" public %sType(%n", layout.getName());
iterateProperties(layout.getAllShapeProperties(), new PropertyIteratorAction() {
@Override
public void run(PropertyModel property, boolean last) {
stream.printf(" %s %s", property.getType().toString(), property.getName());
if (last) {
stream.println(") {");
} else {
stream.println(",");
}
}
});
if (!layout.getInheritedShapeProperties().isEmpty()) {
stream.println(" super(");
iterateProperties(layout.getInheritedShapeProperties(), new PropertyIteratorAction() {
@Override
public void run(PropertyModel property, boolean last) {
stream.printf(" %s", property.getName());
if (last) {
stream.println(");");
} else {
stream.println(",");
}
}
});
}
iterateProperties(layout.getShapeProperties(), new PropertyIteratorAction() {
@Override
public void run(PropertyModel property, boolean last) {
stream.printf(" this.%s = %s;%n", property.getName(), property.getName());
}
});
stream.println(" }");
stream.println(" ");
for (PropertyModel property : layout.getAllShapeProperties()) {
final boolean inherited = !layout.getShapeProperties().contains(property);
if (!inherited) {
stream.printf(" public %s %s() {%n", property.getType(), NameUtils.asGetter(property.getName()));
stream.printf(" return %s;%n", property.getName());
stream.println(" }");
stream.println(" ");
}
if (inherited) {
stream.println(" @Override");
}
stream.printf(" public %sType %s(%s %s) {%n", layout.getName(), NameUtils.asSetter(property.getName()), property.getType(), property.getName());
stream.printf(" return new %sType(%n", layout.getName());
iterateProperties(layout.getAllShapeProperties(), new PropertyIteratorAction() {
@Override
public void run(PropertyModel p, boolean last) {
stream.printf(" %s", p.getName());
if (last) {
stream.println(");");
} else {
stream.println(",");
}
}
});
stream.println(" }");
stream.println(" ");
}
} else {
stream.println(" ");
}
stream.println(" }");
stream.println(" ");
}
private void generateAllocator(final PrintStream stream) {
if (layout.getSuperLayout() == null) {
stream.print(" protected static final Layout LAYOUT = Layout.newLayout()");
for (Layout.ImplicitCast implicitCast : layout.getImplicitCasts()) {
stream.print(".addAllowedImplicitCast(Layout.ImplicitCast.");
stream.print(implicitCast.name());
stream.print(")");
}
stream.println(".build();");
stream.printf(" protected static final Shape.Allocator %S_ALLOCATOR = LAYOUT.createAllocator();%n", NameUtils.identifierToConstant(layout.getName()));
} else {
stream.printf(" protected static final Shape.Allocator %S_ALLOCATOR = LAYOUT.createAllocator();%n", NameUtils.identifierToConstant(layout.getName()));
stream.println(" ");
if (layout.getSuperLayout().hasInstanceProperties()) {
stream.println(" static {");
for (PropertyModel property : layout.getSuperLayout().getAllInstanceProperties()) {
final List<String> modifiers = new ArrayList<>();
if (!property.isNullable()) {
modifiers.add("LocationModifier.NonNull");
}
if (property.isFinal()) {
modifiers.add("LocationModifier.Final");
}
final String modifiersExpression;
if (modifiers.isEmpty()) {
modifiersExpression = "";
} else {
final StringBuilder modifiersExpressionBuilder = new StringBuilder();
modifiersExpressionBuilder.append(", EnumSet.of(");
for (String modifier : modifiers) {
if (!modifier.equals(modifiers.get(0))) {
modifiersExpressionBuilder.append(", ");
}
modifiersExpressionBuilder.append(modifier);
}
modifiersExpressionBuilder.append(")");
modifiersExpression = modifiersExpressionBuilder.toString();
}
final String locationType;
if (property.isVolatile()) {
if (property.getType().getKind() == TypeKind.INT) {
locationType = "AtomicInteger";
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
locationType = "AtomicBoolean";
} else {
locationType = "AtomicReference";
}
} else {
locationType = NameUtils.typeWithoutParameters(property.getType().toString());
}
stream.printf(" %s_ALLOCATOR.locationForType(%s.class%s);%n",
NameUtils.identifierToConstant(layout.getName()),
locationType,
modifiersExpression);
}
stream.println(" }");
stream.println(" ");
}
}
}
private void generateProperties(final PrintStream stream) {
for (PropertyModel property : layout.getInstanceProperties()) {
if (!property.hasIdentifier()) {
stream.printf(" protected static final HiddenKey %s_IDENTIFIER = new HiddenKey(\"%s\");%n", NameUtils.identifierToConstant(property.getName()), property.getName());
}
final List<String> modifiers = new ArrayList<>();
if (!property.isNullable()) {
modifiers.add("LocationModifier.NonNull");
}
if (property.isFinal()) {
modifiers.add("LocationModifier.Final");
}
final String modifiersExpression;
if (modifiers.isEmpty()) {
modifiersExpression = "";
} else {
final StringBuilder modifiersExpressionBuilder = new StringBuilder();
modifiersExpressionBuilder.append(", EnumSet.of(");
for (String modifier : modifiers) {
if (!modifier.equals(modifiers.get(0))) {
modifiersExpressionBuilder.append(", ");
}
modifiersExpressionBuilder.append(modifier);
}
modifiersExpressionBuilder.append(")");
modifiersExpression = modifiersExpressionBuilder.toString();
}
final String locationType;
if (property.isVolatile()) {
if (property.getType().getKind() == TypeKind.INT) {
locationType = "AtomicInteger";
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
locationType = "AtomicBoolean";
} else {
locationType = "AtomicReference";
}
} else {
locationType = NameUtils.typeWithoutParameters(property.getType().toString());
}
stream.printf(" protected static final Property %S_PROPERTY = Property.create(%s_IDENTIFIER, %S_ALLOCATOR.locationForType(%s.class%s), 0);%n",
NameUtils.identifierToConstant(property.getName()),
NameUtils.identifierToConstant(property.getName()),
NameUtils.identifierToConstant(layout.getName()),
locationType,
modifiersExpression);
stream.println(" ");
}
}
private void generateShapeFactory(final PrintStream stream) {
if (layout.hasShapeProperties()) {
stream.println(" @Override");
stream.print(" public");
} else {
stream.print(" private static");
}
stream.printf(" DynamicObjectFactory create%sShape(", layout.getName());
if (layout.hasShapeProperties()) {
stream.println();
for (PropertyModel property : layout.getAllShapeProperties()) {
stream.printf(" %s %s", property.getType().toString(), property.getName());
if (property == layout.getAllShapeProperties().get(layout.getAllShapeProperties().size() - 1)) {
stream.println(") {");
} else {
stream.println(",");
}
}
} else {
stream.println(") {");
}
stream.printf(" return LAYOUT.createShape(new %sType(", layout.getName());
if (layout.hasShapeProperties()) {
stream.println();
iterateProperties(layout.getAllShapeProperties(), new PropertyIteratorAction() {
@Override
public void run(PropertyModel property, boolean last) {
stream.printf(" %s", property.getName());
if (last) {
stream.println("))");
} else {
stream.println(",");
}
}
});
} else {
stream.println("))");
}
iterateProperties(layout.getAllInstanceProperties(), new PropertyIteratorAction() {
@Override
public void run(PropertyModel property, boolean last) {
stream.printf(" .addProperty(%s_PROPERTY)%n", NameUtils.identifierToConstant(property.getName()));
}
});
stream.println(" .createFactory();");
stream.println(" }");
stream.println(" ");
}
private void generateFactory(final PrintStream stream) {
// The shortcut factory when there are no shape properties
if (!layout.hasShapeProperties()) {
stream.println(" @Override");
stream.printf(" public DynamicObject create%s(", layout.getName());
if (layout.getAllProperties().isEmpty()) {
stream.println(") {");
} else {
stream.println();
for (PropertyModel property : layout.getAllProperties()) {
stream.printf(" %s %s", property.getType().toString(), property.getName());
if (property == layout.getAllProperties().get(layout.getAllProperties().size() - 1)) {
stream.println(") {");
} else {
stream.println(",");
}
}
}
stream.printf(" return create%s(%s_FACTORY", layout.getName(), NameUtils.identifierToConstant(layout.getName()));
if (layout.getAllProperties().isEmpty()) {
stream.println(");");
} else {
stream.println(",");
for (PropertyModel property : layout.getAllProperties()) {
stream.printf(" %s", property.getName());
if (property == layout.getAllProperties().get(layout.getAllProperties().size() - 1)) {
stream.println(");");
} else {
stream.println(",");
}
}
}
stream.println(" }");
stream.println(" ");
}
// The full factory
final boolean builder = layout.hasBuilder();
final String methodName = builder ? "build" : "create" + layout.getName();
final String returnType = builder ? "Object[]" : "DynamicObject";
if (layout.hasShapeProperties()) {
stream.println(" @Override");
stream.print(" public");
} else {
stream.print(" private");
if (!layout.hasObjectTypeGuard()) {
stream.printf(" static");
}
}
if (layout.hasInstanceProperties()) {
stream.printf(" %s %s(%n", returnType, methodName);
if (!builder) {
stream.println(" DynamicObjectFactory factory,");
}
for (PropertyModel property : layout.getAllInstanceProperties()) {
stream.printf(" %s %s", property.getType().toString(), property.getName());
if (property == layout.getAllProperties().get(layout.getAllProperties().size() - 1)) {
stream.println(") {");
} else {
stream.println(",");
}
}
} else {
String factoryArg = builder ? "" : "DynamicObjectFactory factory";
stream.printf(" %s %s(%s) {%n", returnType, methodName, factoryArg);
}
if (!builder) {
stream.println(" assert factory != null;");
stream.println(" CompilerAsserts.partialEvaluationConstant(factory);");
stream.printf(" assert creates%s(factory);%n", layout.getName());
for (PropertyModel property : layout.getAllInstanceProperties()) {
stream.printf(" assert factory.getShape().hasProperty(%s_IDENTIFIER);%n", NameUtils.identifierToConstant(property.getName()));
}
}
for (PropertyModel property : layout.getAllInstanceProperties()) {
if (!property.getType().getKind().isPrimitive() && !property.isNullable()) {
stream.printf(" assert %s != null;%n", property.getName());
}
}
if (layout.hasInstanceProperties()) {
if (builder) {
stream.println(" return new Object[] { ");
} else {
stream.println(" return factory.newInstance(");
}
for (PropertyModel property : layout.getAllInstanceProperties()) {
if (property.isVolatile()) {
if (property.getType().getKind() == TypeKind.INT) {
stream.printf(" new AtomicInteger(%s)", property.getName());
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
stream.printf(" new AtomicBoolean(%s)", property.getName());
} else {
stream.printf(" new AtomicReference<%s>(%s)", property.getType(), property.getName());
}
} else {
stream.printf(" %s", property.getName());
}
if (property == layout.getAllProperties().get(layout.getAllProperties().size() - 1)) {
stream.println(builder ? " };" : ");");
} else {
stream.println(",");
}
}
} else {
if (builder) {
stream.println(" return new Object[0];");
} else {
stream.println(" return factory.newInstance();");
}
}
stream.println(" }");
stream.println(" ");
}
private void generateGuards(final PrintStream stream) {
if (layout.hasObjectGuard()) {
stream.println(" @Override");
stream.printf(" public boolean is%s(Object object) {%n", layout.getName());
stream.printf(" return (object instanceof DynamicObject) && is%s((DynamicObject) object);%n", layout.getName());
stream.println(" }");
stream.println(" ");
}
if (layout.hasDynamicObjectGuard() || layout.hasGettersOrSetters()) {
if (layout.hasDynamicObjectGuard()) {
stream.println(" @Override");
stream.print(" public");
} else {
stream.print(" private");
}
if (!layout.hasDynamicObjectGuard() && !layout.hasObjectTypeGuard()) {
stream.printf(" static");
}
stream.printf(" boolean is%s(DynamicObject object) {%n", layout.getName());
stream.printf(" return is%s(object.getShape().getObjectType());%n", layout.getName());
stream.println(" }");
stream.println(" ");
}
if (layout.hasObjectTypeGuard()) {
stream.println(" @Override");
stream.print(" public");
} else {
stream.print(" private static");
}
stream.printf(" boolean is%s(ObjectType objectType) {%n", layout.getName());
stream.printf(" return objectType instanceof %sType;%n", layout.getName());
stream.println(" }");
if (!layout.hasBuilder()) {
stream.println(" ");
stream.printf(" private");
if (!layout.hasObjectTypeGuard()) {
stream.printf(" static");
}
stream.printf(" boolean creates%s(DynamicObjectFactory factory) {%n", layout.getName());
stream.printf(" return is%s(factory.getShape().getObjectType());%n", layout.getName());
stream.println(" }");
}
stream.println(" ");
}
private void generateAccessors(final PrintStream stream) {
for (PropertyModel property : layout.getProperties()) {
if (property.hasObjectTypeGetter()) {
stream.println(" @Override");
stream.printf(" public %s %s(ObjectType objectType) {%n", property.getType(), NameUtils.asGetter(property.getName()));
stream.printf(" assert is%s(objectType);%n", layout.getName());
stream.printf(" return ((%sType) objectType).%s();%n", layout.getName(), NameUtils.asGetter(property.getName()));
stream.println(" }");
stream.println(" ");
}
if (property.hasShapeGetter()) {
stream.println(" @Override");
stream.printf(" public %s %s(DynamicObjectFactory factory) {%n", property.getType(), NameUtils.asGetter(property.getName()));
stream.printf(" assert creates%s(factory);%n", layout.getName());
stream.printf(" return ((%sType) factory.getShape().getObjectType()).%s();%n", layout.getName(), NameUtils.asGetter(property.getName()));
stream.println(" }");
stream.println(" ");
}
if (property.hasGetter()) {
addUncheckedCastWarning(stream, property);
stream.println(" @Override");
stream.printf(" public %s %s(DynamicObject object) {%n", property.getType(), NameUtils.asGetter(property.getName()));
stream.printf(" assert is%s(object);%n", layout.getName());
if (property.isShapeProperty()) {
stream.printf(" return getObjectType(object).%s();%n", NameUtils.asGetter(property.getName()));
} else {
stream.printf(" assert object.getShape().hasProperty(%s_IDENTIFIER);%n", NameUtils.identifierToConstant(property.getName()));
stream.println(" ");
if (property.isVolatile()) {
if (property.getType().getKind() == TypeKind.INT) {
stream.printf(" return ((AtomicInteger) %s_PROPERTY.get(object, is%s(object))).get();%n", NameUtils.identifierToConstant(property.getName()), layout.getName());
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
stream.printf(" return ((AtomicBoolean) %s_PROPERTY.get(object, is%s(object))).get();%n", NameUtils.identifierToConstant(property.getName()), layout.getName());
} else {
stream.printf(" return ((AtomicReference<%s>) %s_PROPERTY.get(object, is%s(object))).get();%n", property.getType(),
NameUtils.identifierToConstant(property.getName()), layout.getName());
}
} else {
stream.printf(" return %s%s_PROPERTY.get(object, is%s(object));%n", cast(property.getType()), NameUtils.identifierToConstant(property.getName()), layout.getName());
}
}
stream.println(" }");
stream.println(" ");
}
if (property.hasShapeSetter()) {
stream.println(" @TruffleBoundary");
stream.println(" @Override");
stream.printf(" public DynamicObjectFactory %s(DynamicObjectFactory factory, %s value) {%n", NameUtils.asSetter(property.getName()), property.getType());
stream.printf(" assert creates%s(factory);%n", layout.getName());
stream.println(" final Shape shape = factory.getShape();");
stream.printf(" return shape.changeType(((%sType) shape.getObjectType()).%s(value)).createFactory();%n", layout.getName(), NameUtils.asSetter(property.getName()));
stream.println(" }");
stream.println(" ");
}
if (property.hasSetter() || property.hasUnsafeSetter()) {
addUncheckedCastWarning(stream, property);
if (property.isShapeProperty()) {
stream.println(" @TruffleBoundary");
}
stream.println(" @Override");
final String methodNameSuffix;
if (property.hasUnsafeSetter()) {
methodNameSuffix = "Unsafe";
} else {
methodNameSuffix = "";
}
stream.printf(" public void %s%s(DynamicObject object, %s value) {%n", NameUtils.asSetter(property.getName()), methodNameSuffix, property.getType());
stream.printf(" assert is%s(object);%n", layout.getName());
if (property.isShapeProperty()) {
stream.println(" final Shape shape = object.getShape();");
stream.printf(" object.setShapeAndGrow(shape, shape.changeType(getObjectType(object).%s(value)));%n", NameUtils.asSetter(property.getName()));
} else {
stream.printf(" assert object.getShape().hasProperty(%s_IDENTIFIER);%n", NameUtils.identifierToConstant(property.getName()));
if (!property.getType().getKind().isPrimitive() && !property.isNullable()) {
stream.println(" assert value != null;");
}
stream.println(" ");
if (property.hasUnsafeSetter()) {
stream.printf(" %s_PROPERTY.setInternal(object, value);%n", NameUtils.identifierToConstant(property.getName()));
} else if (property.isVolatile()) {
if (property.getType().getKind() == TypeKind.INT) {
stream.printf(" ((AtomicInteger) %s_PROPERTY.get(object, is%s(object))).set(value);%n", NameUtils.identifierToConstant(property.getName()), layout.getName());
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
stream.printf(" ((AtomicBoolean) %s_PROPERTY.get(object, is%s(object))).set(value);%n", NameUtils.identifierToConstant(property.getName()), layout.getName());
} else {
stream.printf(" ((AtomicReference<%s>) %s_PROPERTY.get(object, is%s(object))).set(value);%n", property.getType(),
NameUtils.identifierToConstant(property.getName()),
layout.getName());
}
} else {
stream.printf(" try {%n");
stream.printf(" %s_PROPERTY.set(object, value, object.getShape());%n", NameUtils.identifierToConstant(property.getName()));
stream.printf(" } catch (IncompatibleLocationException | FinalLocationException e) {%n");
stream.printf(" throw new UnsupportedOperationException(e);%n");
stream.printf(" }%n");
}
}
stream.println(" }");
stream.println(" ");
}
if (property.hasCompareAndSet()) {
addUncheckedCastWarning(stream, property);
stream.println(" @Override");
stream.printf(" public boolean %s(DynamicObject object, %s expected_value, %s value) {%n",
NameUtils.asCompareAndSet(property.getName()),
property.getType(),
property.getType());
stream.printf(" assert is%s(object);%n", layout.getName());
stream.printf(" assert object.getShape().hasProperty(%s_IDENTIFIER);%n",
NameUtils.identifierToConstant(property.getName()));
if (!property.getType().getKind().isPrimitive() && !property.isNullable()) {
stream.println(" assert value != null;");
}
if (property.getType().getKind() == TypeKind.INT) {
stream.printf(
" return ((AtomicInteger) %s_PROPERTY.get(object, is%s(object))).compareAndSet(expected_value, value);%n",
NameUtils.identifierToConstant(property.getName()), layout.getName());
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
stream.printf(
" return ((AtomicBoolean) %s_PROPERTY.get(object, is%s(object))).compareAndSet(expected_value, value);%n",
NameUtils.identifierToConstant(property.getName()), layout.getName());
} else {
stream.printf(
" return ((AtomicReference<%s>) %s_PROPERTY.get(object, is%s(object))).compareAndSet(expected_value, value);%n",
property.getType(),
NameUtils.identifierToConstant(property.getName()), layout.getName());
}
stream.println(" }");
stream.println(" ");
}
if (property.hasGetAndSet()) {
addUncheckedCastWarning(stream, property);
stream.println(" @Override");
stream.printf(" public %s %s(DynamicObject object, %s value) {%n",
property.getType(),
NameUtils.asGetAndSet(property.getName()),
property.getType());
stream.printf(" assert is%s(object);%n", layout.getName());
stream.printf(" assert object.getShape().hasProperty(%s_IDENTIFIER);%n",
NameUtils.identifierToConstant(property.getName()));
if (!property.getType().getKind().isPrimitive() && !property.isNullable()) {
stream.println(" assert value != null;");
}
if (property.getType().getKind() == TypeKind.INT) {
stream.printf(
" return ((AtomicInteger) %s_PROPERTY.get(object, is%s(object))).getAndSet(value);%n",
NameUtils.identifierToConstant(property.getName()), layout.getName());
} else if (property.getType().getKind() == TypeKind.BOOLEAN) {
stream.printf(
" return ((AtomicBoolean) %s_PROPERTY.get(object, is%s(object))).getAndSet(value);%n",
NameUtils.identifierToConstant(property.getName()), layout.getName());
} else {
stream.printf(
" return ((AtomicReference<%s>) %s_PROPERTY.get(object, is%s(object))).getAndSet(value);%n",
property.getType(),
NameUtils.identifierToConstant(property.getName()), layout.getName());
}
stream.println(" }");
stream.println(" ");
}
}
if (!layout.getShapeProperties().isEmpty()) {
stream.print(" private");
if (!layout.hasObjectTypeGuard()) {
stream.print(" static");
}
stream.printf(" %sType getObjectType(DynamicObject object) {%n", layout.getName());
stream.printf(" assert is%s(object);%n", layout.getName());
stream.printf(" return (%sType) object.getShape().getObjectType();%n", layout.getName());
stream.println(" }");
stream.println(" ");
}
}
private static void addUncheckedCastWarning(final PrintStream stream, PropertyModel property) {
if (property.getType().toString().indexOf('<') != -1 ||
(property.isVolatile() && !property.getType().getKind().isPrimitive())) {
stream.println(" @SuppressWarnings(\"unchecked\")");
}
}
private static void iterateProperties(List<PropertyModel> properties, PropertyIteratorAction action) {
for (int n = 0; n < properties.size(); n++) {
action.run(properties.get(n), n == properties.size() - 1);
}
}
private static String cast(TypeMirror type) {
if (type.toString().equals(Object.class.getName())) {
return "";
} else {
return String.format("(%s) ", type.toString());
}
}
private interface PropertyIteratorAction {
void run(PropertyModel property, boolean last);
}
public String getGeneratedClassName() {
return layout.getPackageName() + "." + layout.getName() + "LayoutImpl";
}
}