Skip to content

Commit

Permalink
Remove Array constructor that projected another array
Browse files Browse the repository at this point in the history
This will be handled by stdlib.Arrays.zs#map
We decided against these two array constructors because they were the
only usecase currently where a constructor would require a generic
argument. Since this would make calls more complicated (generic class
with generic constructor), it was decided that these ctors should be
removed and constructors should not be made generic.
  • Loading branch information
kindlich committed Mar 10, 2024
1 parent f325e2f commit d972755
Show file tree
Hide file tree
Showing 4 changed files with 0 additions and 220 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,38 +155,6 @@ public ResolvedType resolve(TypeID[] typeArguments) {
FunctionHeader lambdaConstructorHeader = new FunctionHeader(VOID, lambdaConstructorParameters);
members.constructor(new MethodInstance(BuiltinMethodSymbol.ARRAY_CONSTRUCTOR_LAMBDA, lambdaConstructorHeader, type));

{
TypeParameter mappedConstructorParameter = new TypeParameter(BUILTIN, "T");
GenericTypeID mappedConstructorParameterType = new GenericTypeID(mappedConstructorParameter);
FunctionHeader mappedConstructorHeaderWithoutIndex = new FunctionHeader(baseType, mappedConstructorParameterType);
FunctionHeader mappedConstructorFunctionWithoutIndex = new FunctionHeader(
new TypeParameter[]{mappedConstructorParameter},
VOID,
null,
new FunctionParameter(new ArrayTypeID(mappedConstructorParameterType, dimension), "original"),
new FunctionParameter(new FunctionTypeID(mappedConstructorHeaderWithoutIndex), "projection"));
members.constructor(new MethodInstance(BuiltinMethodSymbol.ARRAY_CONSTRUCTOR_PROJECTED, mappedConstructorFunctionWithoutIndex, type));
}

{
TypeParameter mappedConstructorParameter = new TypeParameter(BUILTIN, "T");
GenericTypeID mappedConstructorParameterType = new GenericTypeID(mappedConstructorParameter);

FunctionParameter[] projectionParameters = new FunctionParameter[dimension + 1];
for (int i = 0; i < dimension; i++)
projectionParameters[i] = new FunctionParameter(USIZE);
projectionParameters[dimension] = new FunctionParameter(mappedConstructorParameterType);

FunctionHeader mappedConstructorHeaderWithIndex = new FunctionHeader(baseType, projectionParameters);
FunctionHeader mappedConstructorFunctionWithIndex = new FunctionHeader(
new TypeParameter[]{mappedConstructorParameter},
VOID,
null,
new FunctionParameter(new ArrayTypeID(mappedConstructorParameterType, dimension), "original"),
new FunctionParameter(new FunctionTypeID(mappedConstructorHeaderWithIndex), "projection"));
members.constructor(new MethodInstance(BuiltinMethodSymbol.ARRAY_CONSTRUCTOR_PROJECTED_INDEXED, mappedConstructorFunctionWithIndex, type));
}

FunctionParameter[] indexSetParameters = new FunctionParameter[dimension + 1];
for (int i = 0; i < dimension; i++)
indexSetParameters[i] = new FunctionParameter(USIZE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -523,8 +523,6 @@ public Optional<CompileTimeConstant> evaluate(TypeID[] typeArguments, CompileTim
ARRAY_CONSTRUCTOR_SIZED(ArrayTypeSymbol.ARRAY, CONSTRUCTOR, FunctionHeader.PLACEHOLDER),
ARRAY_CONSTRUCTOR_INITIAL_VALUE(ArrayTypeSymbol.ARRAY, CONSTRUCTOR, FunctionHeader.PLACEHOLDER),
ARRAY_CONSTRUCTOR_LAMBDA(ArrayTypeSymbol.ARRAY, CONSTRUCTOR, FunctionHeader.PLACEHOLDER),
ARRAY_CONSTRUCTOR_PROJECTED(ArrayTypeSymbol.ARRAY, CONSTRUCTOR, FunctionHeader.PLACEHOLDER),
ARRAY_CONSTRUCTOR_PROJECTED_INDEXED(ArrayTypeSymbol.ARRAY, CONSTRUCTOR, FunctionHeader.PLACEHOLDER),
ARRAY_INDEXGET(ArrayTypeSymbol.ARRAY, INDEXGET, FunctionHeader.PLACEHOLDER),
ARRAY_INDEXSET(ArrayTypeSymbol.ARRAY, INDEXSET, FunctionHeader.PLACEHOLDER),
// 1D arrays only
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,11 @@
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import org.openzen.zenscript.codemodel.expression.Expression;
import org.openzen.zenscript.codemodel.expression.FunctionExpression;
import org.openzen.zenscript.codemodel.statement.ReturnStatement;

import java.util.ArrayList;

class ArrayInitializerHelper {

/**
* creates an int[] with the given array size locations and writes the code that gets them in the generated file.
* Uses an already present origin array (rectangular!)
*
* @param dimension the array's dim
* @param originArrayType the type of the original array
* @param originArrayLocation the location of the original array
* @param javaWriter the writer
* @return the size locations
*/
static int[] getArraySizeLocationsProjected(int dimension, Type originArrayType, int originArrayLocation, JavaWriter javaWriter) {
int[] arraySizes;
final ArrayList<Integer> list = new ArrayList<>();
javaWriter.loadObject(originArrayLocation);
Type currentElementType = originArrayType;
for (int i = 0; i < dimension; i++) {
currentElementType = Type.getType(currentElementType.getDescriptor().substring(1));
final int location = javaWriter.local(int.class);
javaWriter.dup();
javaWriter.arrayLength();
javaWriter.storeInt(location);
list.add(location);

if (i < dimension - 1) {
javaWriter.iConst0();
javaWriter.arrayLoad(currentElementType);
}
}
javaWriter.pop();
arraySizes = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
arraySizes[i] = list.get(i);
}
return arraySizes;
}

/**
* Creates an int[] with the given array size locations and writes the code that gets them in the generated file
* Uses the constructor arguments (sizes are expressions 0 .. dimension-1)
Expand All @@ -71,40 +33,6 @@ static int[] getArraySizeLocationsFromConstructor(int dimension, Expression[] ar
return arraySizes;
}

/**
* Writes the code for visiting a multidimensional array that is projected from an origin array.
* Accepts a function that will decide what to do with each value from the origin array
* When the function is executed, the value from the origin array will be on top of the stack and when it is finished the value on top should be what will be inserted into the array.
* After the function is completed the stack size must be the same as when it started (effectively replacing the item on top of the stack with the item that should be inserted.
* The function should not modify the other stacks.
*
* @param javaWriter the writer that will write the actual opcode
* @param sizeLocations the locations of the array dimension sizes sizeLocations.length == dim !!
* @param dim the array's dimensions, reduced during the recursions of the loop to find the innermost loop
* @param originArrayLocation The location of the origin array.
* @param originArrayType the type of the origin array. The element type needs to be assignable to the new array element type!
* @param currentArrayType The current type of the array, reduced during the recursions of the functions
* @param innermostFunction The function that will decide what to add to the array, needs to increase the stack size by one and may not touch the other stacks!
*/
static void visitProjected(JavaWriter javaWriter, int[] sizeLocations, int dim, int originArrayLocation, Type originArrayType, Type currentArrayType, InnermostFunction innermostFunction) {

visitMultiDimArray(javaWriter, sizeLocations, dim, currentArrayType, (elementType, counterLocations) -> {
//Load origin array
javaWriter.loadObject(originArrayLocation);

//Use arrayGets until we are at the element type
Type modifiedOriginArrayType = originArrayType;
for (final int location : counterLocations) {
javaWriter.loadInt(location);
javaWriter.arrayLoad(modifiedOriginArrayType = Type.getType(modifiedOriginArrayType.getDescriptor().substring(1)));
}

innermostFunction.apply(elementType, counterLocations);


});
}

/**
* Writes the code for visiting a multidimensional array with a default value.
* The variable at defaultLocation needs to be of or assignable to the resulting array element type.
Expand All @@ -119,32 +47,6 @@ static void visitMultiDimArrayWithDefaultValue(JavaWriter javaWriter, int[] size
visitMultiDimArray(javaWriter, sizeLocations, new int[dim], dim, currentArrayType, (elementType, counterLocations) -> javaWriter.load(elementType, defaultLocation));
}

/**
* Writes the code for visiting a multidimensional array.
* Accepts a function that will decide what value to insert into the array slots.
* When the function is finished, one additional item needs to have been added to the stack.
* The already present stacks may not be touched!
*
* @param javaWriter the writer that will write the actual opcode
* @param sizeLocations the locations of the array dimension sizes sizeLocations.length == dim !!
* @param dim the array's dimensions, reduced during the recursions of the loop to find the innermost loop
* @param currentArrayType The current type of the array, reduced during the recursions of the functions
* @param innermostFunction The function that will decide what to add to the array, needs to increase the stack size by one and may not touch the other stacks!
*/
private static void visitMultiDimArray(JavaWriter javaWriter, int[] sizeLocations, int dim, Type currentArrayType, InnermostFunction innermostFunction) {
visitMultiDimArray(javaWriter, sizeLocations, new int[dim], dim, currentArrayType, innermostFunction);
}

/**
* Checks if an expression can be inLined
*
* @param expression Expression to check for.
* @return can expression be inLined
*/
static boolean canBeInLined(Expression expression) {
return expression instanceof FunctionExpression && ((FunctionExpression) expression).body instanceof ReturnStatement;
}

/**
* The function that is actually setting up the loops and naming the counter variables.
* Private because the other static methods provide the new int[] sizeLocations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,94 +299,6 @@ public Void builtinConstructor(BuiltinMethodSymbol method, TypeID type, CallArgu
javaWriter.label(end);
return null;
}
case ARRAY_CONSTRUCTOR_PROJECTED:
case ARRAY_CONSTRUCTOR_PROJECTED_INDEXED: {
ArrayTypeID arrayType = (ArrayTypeID) type;

//Labels
final Label begin = new Label();
final Label end = new Label();
javaWriter.label(begin);

//Origin Array
arguments[0].accept(expressionVisitor);
final Type originArrayType = context.getType(arguments[0].type);
final int originArrayLocation = javaWriter.local(originArrayType);
javaWriter.storeObject(originArrayLocation);
Type destinationArrayType = context.getType(type);

final boolean indexed = method == BuiltinMethodSymbol.ARRAY_CONSTRUCTOR_PROJECTED_INDEXED;
final boolean canBeInLined = ArrayInitializerHelper.canBeInLined(arguments[1]);
if (canBeInLined) {
//We can inline, so do it
final int[] arraySizes = ArrayInitializerHelper.getArraySizeLocationsProjected(arrayType.dimension, originArrayType, originArrayLocation, javaWriter);
final Type projectedElementType = Type.getType(originArrayType.getDescriptor().substring(arrayType.dimension));
ArrayInitializerHelper.visitProjected(javaWriter, arraySizes, arrayType.dimension, originArrayLocation, originArrayType, destinationArrayType,
(elementType, counterLocations) -> {
Label inlineBegin = new Label();
Label inlineEnd = new Label();
javaWriter.label(inlineBegin);

final int projectedElementLocal = javaWriter.local(projectedElementType);
javaWriter.store(projectedElementType, projectedElementLocal);


JavaExpressionVisitor visitor = new JavaExpressionVisitor(context, module, javaWriter) {
@Override
public Void visitGetFunctionParameter(GetFunctionParameterExpression expression) {
if (indexed) {
final JavaParameterInfo parameterInfo = module.getParameterInfo(expression.parameter);
if (parameterInfo != null && parameterInfo.index <= arrayType.dimension) {
javaWriter.loadInt(counterLocations[parameterInfo.index - 1]);
return null;
}
}

javaWriter.load(projectedElementType, projectedElementLocal);
return null;
}
};

Expression funcExpression = arguments[1];
if (funcExpression instanceof FunctionExpression && ((FunctionExpression) funcExpression).body instanceof ReturnStatement) {
CompilerUtils.tagMethodParameters(context, module, ((FunctionExpression) funcExpression).header, false, Collections
.emptyList());
((ReturnStatement) ((FunctionExpression) funcExpression).body).value.accept(visitor);
javaWriter.addVariableInfo(new JavaLocalVariableInfo(projectedElementType, projectedElementLocal, inlineBegin, ((FunctionExpression) funcExpression).header.parameters[0].name, inlineEnd));

} else throw new IllegalStateException("Trying to inline a non-inlineable expression");


javaWriter.label(inlineEnd);
});
} else {
//We cannot inline, so get a hold of the function expression and apply it to every
arguments[1].accept(expressionVisitor); //Projection Function
final Type functionType = context.getType(arguments[1].type);
final int functionLocation = javaWriter.local(functionType);
javaWriter.storeObject(functionLocation);
javaWriter.addVariableInfo(new JavaLocalVariableInfo(functionType, functionLocation, begin, "projectionFunction", end));
final int[] arraySizes = ArrayInitializerHelper.getArraySizeLocationsProjected(arrayType.dimension, originArrayType, originArrayLocation, javaWriter);
ArrayInitializerHelper.visitProjected(javaWriter, arraySizes, arrayType.dimension, originArrayLocation, originArrayType, destinationArrayType,
(elementType, counterLocations) -> {
//Apply function here
javaWriter.loadObject(functionLocation);
javaWriter.swap();

if (indexed) {
for (int counterLocation : counterLocations) {
javaWriter.loadInt(counterLocation);
javaWriter.swap();
}
}

javaWriter.invokeInterface(context.getFunctionalInterface(arguments[1].type));
});
}

javaWriter.label(end);
return null;
}
}
return null;
}
Expand Down

0 comments on commit d972755

Please sign in to comment.