/*
* Copyright (C) 2011 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.errai.codegen.builder.callstack;
import java.util.Arrays;
import org.jboss.errai.codegen.Context;
import org.jboss.errai.codegen.Statement;
import org.jboss.errai.codegen.VariableReference;
import org.jboss.errai.codegen.exception.GenerationException;
import org.jboss.errai.codegen.exception.InvalidTypeException;
import org.jboss.errai.codegen.meta.MetaClass;
import org.jboss.errai.codegen.meta.MetaClassFactory;
import org.jboss.errai.codegen.util.GenUtil;
/**
* {@link CallElement} to load {@link VariableReference}s. Indexes can be provided in case of an array.
*
* @author Mike Brock <cbrock@redhat.com>
* @author Christian Sadilek <csadilek@redhat.com>
*/
public class LoadVariable extends AbstractCallElement {
private final String variableName;
private final Object[] indexes;
private boolean classMember;
public LoadVariable(final String variableName, final Object... indexes) {
this.variableName = variableName;
this.indexes = indexes == null ? new Object[0] : indexes;
}
public LoadVariable(final String variableName, final boolean classMember, final Object... indexes) {
this(variableName, indexes);
this.classMember = classMember;
}
@Override
public void handleCall(final CallWriter writer, final Context context, final Statement statement) {
writer.reset();
try {
final Statement[] idx = new Statement[this.indexes.length];
for (int i = 0; i < idx.length; i++) {
idx[i] = GenUtil.convert(context, GenUtil.generate(context, this.indexes[i]), MetaClassFactory.get(Integer.class));
}
final VariableReference ref = context.getVariable(variableName);
if (idx.length > 0) {
if (!ref.getType().isArray()) {
throw new InvalidTypeException("attempt to use indexed accessor on non-array type: " + ref);
}
}
final Statement stmt = new VariableReference() {
@Override
public String getName() {
return ref.getName();
}
@Override
public Statement getValue() {
return ref.getValue();
}
String generatedCache;
@Override
public String generate(final Context context) {
if (generatedCache != null) return generatedCache;
if (variableName.equals("this") && next != null && !(next instanceof ReturnValue)) {
return generatedCache = "";
}
final StringBuilder buf = new StringBuilder((classMember
&& context.isAmbiguous(ref.getName()) ? "this." : "").concat(getName()));
Arrays.stream(idx).forEach(s -> buf.append('[').append(s.generate(context)).append(']'));
return generatedCache = buf.toString();
}
@Override
public MetaClass getType() {
final MetaClass ret;
final int dims = GenUtil.getArrayDimensions(ref.getType());
if (ref.getType().isArray() && idx.length > 0) {
final int newDims = dims - idx.length;
if (newDims > 0) {
ret = ref.getType().getOuterComponentType().asArrayOf(dims - idx.length);
}
else {
ret = ref.getType().getOuterComponentType();
}
}
else {
ret = ref.getType();
}
return ret;
}
};
ref.setIndexes(idx);
nextOrReturn(writer, context, stmt);
}
catch (final GenerationException e) {
blameAndRethrow(e);
}
}
public String getVariableName() {
return variableName;
}
@Override
public String toString() {
return "[[LoadVariable<" + variableName + ">]" + next + "]";
}
}