Skip to content

Commit

Permalink
Move ReferenceExpression to API for more usage
Browse files Browse the repository at this point in the history
Signed-off-by: TheSilkMiner <thesilkminer@outlook.com>
  • Loading branch information
TheSilkMiner committed May 3, 2022
1 parent 6adffa2 commit ae21942
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package com.blamejared.contenttweaker.core.api.zen.bracket;

import com.blamejared.contenttweaker.core.api.object.ObjectType;
import com.blamejared.contenttweaker.core.api.zen.object.Reference;
import com.blamejared.contenttweaker.core.zen.rt.ReferenceMetaFactory;
import com.blamejared.contenttweaker.core.zen.rt.Unknown;
import com.blamejared.crafttweaker.api.CraftTweakerAPI;
import com.blamejared.crafttweaker.api.util.ParseUtil;
import com.blamejared.crafttweaker.api.zencode.IScriptLoader;
import com.blamejared.crafttweaker.api.zencode.IZenClassRegistry;
import com.google.gson.reflect.TypeToken;
import net.minecraft.resources.ResourceLocation;
import org.openzen.zencode.shared.CodePosition;
import org.openzen.zencode.shared.CompileException;
import org.openzen.zenscript.codemodel.partial.IPartialExpression;
import org.openzen.zenscript.codemodel.scope.ExpressionScope;
import org.openzen.zenscript.parser.expression.ParsedCallArguments;
import org.openzen.zenscript.parser.expression.ParsedExpression;
import org.openzen.zenscript.parser.expression.ParsedExpressionCall;
import org.openzen.zenscript.parser.expression.ParsedExpressionMember;
import org.openzen.zenscript.parser.type.IParsedType;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public final class ReferenceExpression<T, U extends Reference<T>> extends ParsedExpression {
private final ObjectType<T> objectType;
private final TypeToken<U> referenceToken;
private final ResourceLocation registryId;
private final ResourceLocation objectId;

public ReferenceExpression(
final CodePosition position,
final ObjectType<T> objectType,
final TypeToken<U> referenceToken,
final ResourceLocation registryId,
final ResourceLocation objectId
) {
super(Objects.requireNonNull(position));
this.objectType = objectType;
this.referenceToken = checkToken(Objects.requireNonNull(referenceToken));
this.registryId = Objects.requireNonNull(registryId);
this.objectId = Objects.requireNonNull(objectId);
}

public ReferenceExpression(
final CodePosition position,
final ObjectType<T> objectType,
final TypeToken<U> referenceToken,
final ResourceLocation objectId
) {
this(position, Objects.requireNonNull(objectType), referenceToken, objectType.id().location(), objectId);
}

private static <R> TypeToken<R> checkToken(final TypeToken<R> token) {
final Type type = token.getType();
if (!(type instanceof Class<?> || type instanceof ParameterizedType)) {
throw new IllegalStateException(token + " represents type " + type + " which is unsupported");
}
return token;
}

@Override
public IPartialExpression compile(final ExpressionScope scope) throws CompileException {
final ParsedExpression metaFactory = ParseUtil.staticMemberExpression(this.position, ReferenceMetaFactory.ZEN_NAME);
final ParsedExpression of = new ParsedExpressionMember(this.position, metaFactory, "of", null);
final ParsedCallArguments arguments = new ParsedCallArguments(this.generics(), this.arguments());
final ParsedExpression invocation = new ParsedExpressionCall(this.position, of, arguments);
return invocation.compile(scope);
}

private List<IParsedType> generics() throws CompileException {
final IScriptLoader loader = CraftTweakerAPI.getScriptRunManager().currentRunInfo().loader();
final IZenClassRegistry classes = CraftTweakerAPI.getRegistry().getZenClassRegistry();

final Class<?> objectType = this.objectType == null? Unknown.class : this.objectType.type(); // TODO("Find a better way")
final String objectName = classes.getNameFor(loader, objectType).orElseThrow();

final String referenceName = this.buildGenericReferenceName(loader, classes, objectType);

final IParsedType object = BracketHelper.parseToCompile(this.position, () -> ParseUtil.readParsedType(objectName, this.position));
final IParsedType reference = BracketHelper.parseToCompile(this.position, () -> ParseUtil.readParsedType(referenceName, this.position));

return List.of(object, reference);
}

private String buildGenericReferenceName(final IScriptLoader loader, final IZenClassRegistry classes, final Class<?> objectType) {
return buildGenericReferenceName(loader, classes, this.referenceToken.getType(), objectType);
}

private String buildGenericReferenceName(final IScriptLoader loader, final IZenClassRegistry classes, final Type targetType, final Class<?> objectType) {
if (targetType instanceof ParameterizedType genericType) {
final String rawTypeName = this.buildGenericReferenceName(loader, classes, genericType.getRawType(), objectType);
final String generics = Arrays.stream(genericType.getActualTypeArguments())
.map(it -> this.buildGenericReferenceName(loader, classes, it, objectType))
.collect(Collectors.joining(", ", "<", ">"));
return rawTypeName + generics;
} else if (targetType instanceof Class<?> rawClass) {
return classes.getNameFor(loader, rawClass).orElseThrow();
} else if (targetType instanceof TypeVariable<?>) {
return classes.getNameFor(loader, objectType).orElseThrow();
} else {
throw new IllegalStateException();
}
}

private List<ParsedExpression> arguments() {
final ParsedExpression registryId = BracketHelper.locationArgument(this.position, this.registryId);
final ParsedExpression objectId = BracketHelper.locationArgument(this.position, this.objectId);
return List.of(registryId, objectId);
}

@Override
public boolean hasStrongType() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import java.util.List;
import java.util.stream.Stream;

public final class FactoryBracketExpressionParser implements BracketExpressionParser {
final class FactoryBracketExpressionParser implements BracketExpressionParser {
private static final class BracketMetaFactoryExpression<T> extends ParsedExpression {
private final ObjectType<T> type;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,81 +3,25 @@
import com.blamejared.contenttweaker.core.ContentTweakerCore;
import com.blamejared.contenttweaker.core.api.object.ObjectType;
import com.blamejared.contenttweaker.core.api.zen.bracket.BracketHelper;
import com.blamejared.contenttweaker.core.api.zen.bracket.ReferenceExpression;
import com.blamejared.contenttweaker.core.api.zen.object.Reference;
import com.blamejared.contenttweaker.core.zen.rt.ReferenceMetaFactory;
import com.blamejared.contenttweaker.core.zen.rt.Unknown;
import com.blamejared.crafttweaker.api.CraftTweakerAPI;
import com.blamejared.crafttweaker.api.util.ParseUtil;
import com.blamejared.crafttweaker.api.zencode.IScriptLoader;
import com.blamejared.crafttweaker.api.zencode.IZenClassRegistry;
import com.google.gson.reflect.TypeToken;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
import org.openzen.zencode.shared.CodePosition;
import org.openzen.zencode.shared.CompileException;
import org.openzen.zenscript.codemodel.partial.IPartialExpression;
import org.openzen.zenscript.codemodel.scope.ExpressionScope;
import org.openzen.zenscript.lexer.ParseException;
import org.openzen.zenscript.lexer.ZSTokenParser;
import org.openzen.zenscript.parser.BracketExpressionParser;
import org.openzen.zenscript.parser.expression.ParsedCallArguments;
import org.openzen.zenscript.parser.expression.ParsedExpression;
import org.openzen.zenscript.parser.expression.ParsedExpressionCall;
import org.openzen.zenscript.parser.expression.ParsedExpressionMember;
import org.openzen.zenscript.parser.type.IParsedType;

import java.util.Comparator;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Stream;

public final class ReferenceBracketExpressionParser implements BracketExpressionParser {
private static final class ReferenceExpression<T> extends ParsedExpression {
private final ObjectType<T> type;
private final ResourceLocation registry;
private final ResourceLocation id;

ReferenceExpression(final CodePosition position, final ObjectType<T> type, final ResourceLocation registry, final ResourceLocation id) {
super(position);
this.type = type;
this.registry = registry;
this.id = id;
}

@Override
public IPartialExpression compile(final ExpressionScope scope) throws CompileException {
final ParsedExpression metaFactory = ParseUtil.staticMemberExpression(this.position, ReferenceMetaFactory.ZEN_NAME);
final ParsedExpression of = new ParsedExpressionMember(this.position, metaFactory, "of", null);
final ParsedCallArguments arguments = new ParsedCallArguments(this.generics(), this.arguments());
final ParsedExpression invocation = new ParsedExpressionCall(this.position, of, arguments);
return invocation.compile(scope);
}

private List<IParsedType> generics() throws CompileException {
final IScriptLoader loader = CraftTweakerAPI.getScriptRunManager().currentRunInfo().loader();
final IZenClassRegistry classes = CraftTweakerAPI.getRegistry().getZenClassRegistry();
final Class<?> objectType = this.type == null? Unknown.class : this.type.type();
final String objectName = classes.getNameFor(loader, objectType).orElseThrow();
final String referenceName = classes.getNameFor(loader, Reference.class).orElseThrow();
final String generifiedName = "%s<%s>".formatted(referenceName, objectName);
final IParsedType object = BracketHelper.parseToCompile(this.position, () -> ParseUtil.readParsedType(objectName, this.position));
final IParsedType reference = BracketHelper.parseToCompile(this.position, () -> ParseUtil.readParsedType(generifiedName, this.position));
return List.of(object, reference);
}

private List<ParsedExpression> arguments() {
final ParsedExpression registryId = BracketHelper.locationArgument(this.position, this.registry);
final ParsedExpression objectId = BracketHelper.locationArgument(this.position, this.id);
return List.of(registryId, objectId);
}

@Override
public boolean hasStrongType() {
return true;
}
}

final class ReferenceBracketExpressionParser implements BracketExpressionParser {
private record EntryData(ResourceLocation registry, ResourceLocation object) {
@Override
public String toString() {
Expand Down Expand Up @@ -134,8 +78,12 @@ private ParsedExpression parseModdedModded(final CodePosition position, final St
}

private ParsedExpression createExpression(final CodePosition position, final ResourceLocation registry, final ResourceLocation id) {
return createExpression(position, this.grabType(ResourceKey.createRegistryKey(registry)), registry, id);
}

private <T> ParsedExpression createExpression(final CodePosition position, final ObjectType<T> type, final ResourceLocation registry, final ResourceLocation id) {
// Scripts run before registry creation and object registration, so no validation has to be performed
return new ReferenceExpression<>(position, this.grabType(ResourceKey.createRegistryKey(registry)), registry, id);
return new ReferenceExpression<>(position, type, new TypeToken<>() {}, registry, id);
}

private ParseException fail(final CodePosition position, final String contents) throws ParseException {
Expand Down

0 comments on commit ae21942

Please sign in to comment.