use of dyvilx.tools.compiler.ast.type.IType in project Dyvil by Dyvil.
the class MatchExpr method generateSwitch.
private void generateSwitch(MethodWriter writer, Object frameType) throws BytecodeException {
MatchCase defaultCase = null;
Label defaultLabel = null;
int cases = 0;
// the minimum int
int low = Integer.MAX_VALUE;
// the maximum int
int high = Integer.MIN_VALUE;
// Do we need to store the value in a variable (for string equality checks later)
boolean switchVar = false;
// generated.
for (int i = 0; i < this.caseCount; i++) {
MatchCase matchCase = this.cases[i];
Pattern pattern = matchCase.pattern;
if (switchVar || pattern.switchCheck()) {
switchVar = true;
}
if (pattern.isExhaustive()) {
defaultCase = matchCase;
defaultLabel = new Label();
continue;
}
int min = pattern.minValue();
if (min < low) {
low = min;
}
int max = pattern.maxValue();
if (max > high) {
high = max;
}
cases += pattern.subPatterns();
}
// Check if a match error should be generated - Non-exhaustive pattern
// and no default label
final Label endLabel = new Label();
Label matchErrorLabel = null;
if (!this.exhaustive) {
// Need a variable for MatchError
switchVar = true;
matchErrorLabel = new Label();
if (defaultLabel == null) {
defaultLabel = matchErrorLabel;
}
} else if (defaultLabel == null) {
// Exhaustive pattern - default label is end label
defaultLabel = endLabel;
}
final boolean expr = frameType != null;
// Write the value
final IType matchedType = this.matchedValue.getType();
final int localCount = writer.localCount();
final int varIndex;
if (switchVar) {
varIndex = this.matchedValue.writeStoreLoad(writer, null);
} else {
varIndex = -1;
this.matchedValue.writeExpression(writer, null);
}
if (Types.isSuperClass(Types.ENUM, matchedType)) {
// x.name().hashCode()
writer.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Enum", "name", "()Ljava/lang/String;", false);
writer.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false);
} else if (Types.isSuperClass(Types.STRING, matchedType)) {
// x.hashCode()
writer.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false);
} else if (matchedType.getAnnotation(Types.SWITCHOPTIMIZED_CLASS) != null) {
// x.getClass().getName().hashCode()
writer.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
writer.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false);
writer.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false);
}
final int localCountInner = writer.localCount();
final KeyCache keyCache = new KeyCache(cases);
// Third run: fill the Key Cache
for (int i = 0; i < this.caseCount; i++) {
final MatchCase matchCase = this.cases[i];
final Pattern pattern = matchCase.pattern;
final int subPatterns = pattern.subPatterns();
for (int j = 0; j < subPatterns; j++) {
final Pattern subPattern = pattern.subPattern(j);
if (subPattern.isExhaustive()) {
continue;
}
final int switchValue = subPattern.switchValue();
keyCache.add(switchValue, matchCase, subPattern);
}
}
final Collection<KeyCache.Entry> entries = keyCache.uniqueEntries();
// Generate switch target labels
for (KeyCache.Entry topEntry : entries) {
for (KeyCache.Entry entry = topEntry; entry != null; entry = entry.next) {
entry.switchLabel = new Label();
}
}
// Choose and generate the appropriate instruction
if (useTableSwitch(low, high, cases)) {
this.writeTableSwitch(writer, entries, defaultLabel, low, high);
} else {
this.writeLookupSwitch(writer, entries, defaultLabel, cases);
}
// Fourth run: generate the target labels
for (KeyCache.Entry topEntry : entries) {
KeyCache.Entry entry = topEntry;
final int key = entry.key;
do {
final KeyCache.Entry next = entry.next;
final MatchCase matchCase = entry.matchCase;
final Pattern pattern = entry.pattern;
Label elseLabel;
if (next != null && next.key == key) {
elseLabel = next.switchLabel;
if (elseLabel == null) {
elseLabel = next.switchLabel = new Label();
}
} else {
elseLabel = defaultLabel;
}
writer.visitTargetLabel(entry.switchLabel);
if (pattern.switchCheck()) {
pattern.writeJumpOnMismatch(writer, varIndex, elseLabel);
}
if (matchCase.condition != null) {
matchCase.condition.writeInvJump(writer, elseLabel);
}
this.writeAction(writer, expr, frameType, matchCase.action);
writer.resetLocals(localCountInner);
if (!writer.hasReturn()) {
writer.visitJumpInsn(Opcodes.GOTO, endLabel);
}
entry = next;
} while (entry != null && entry.key == key);
}
// Default Case
if (defaultCase != null) {
writer.visitTargetLabel(defaultLabel);
if (defaultCase.pattern.switchCheck()) {
defaultCase.pattern.writeJumpOnMismatch(writer, varIndex, matchErrorLabel);
}
if (defaultCase.condition != null) {
defaultCase.condition.writeInvJump(writer, matchErrorLabel);
}
this.writeAction(writer, expr, frameType, defaultCase.action);
writer.resetLocals(localCountInner);
if (!writer.hasReturn()) {
writer.visitJumpInsn(Opcodes.GOTO, endLabel);
}
}
// Generate Match Error
if (matchErrorLabel != null) {
writer.visitLabel(matchErrorLabel);
this.writeMatchError(writer, varIndex, matchedType);
}
writer.visitLabel(endLabel);
writer.resetLocals(localCount);
}
use of dyvilx.tools.compiler.ast.type.IType in project Dyvil by Dyvil.
the class EnumConstant method check.
@Override
public void check(MarkerList markers, IContext context) {
final IClass enclosingClass = this.getEnclosingClass();
final IType classType = enclosingClass.getClassType();
if (!enclosingClass.hasModifier(Modifiers.ENUM_CLASS)) {
final Marker marker = Markers.semanticError(this.position, "field.enum.class", this.name);
marker.addInfo(Markers.getSemantic("method.enclosing_class", classType));
markers.add(marker);
}
super.check(markers, context);
}
use of dyvilx.tools.compiler.ast.type.IType in project Dyvil by Dyvil.
the class IDataMember method toString.
static void toString(String prefix, StringBuilder buffer, IMember field, String key) {
final IType type = field.getType();
appendKeyword(buffer, field);
buffer.append(' ').append(field.getName());
if (type != null && type != Types.UNKNOWN) {
Formatting.appendSeparator(buffer, key, ':');
type.toString(prefix, buffer);
}
}
use of dyvilx.tools.compiler.ast.type.IType in project Dyvil by Dyvil.
the class IVariable method writeLocal.
default void writeLocal(MethodWriter writer, Label start, Label end) {
final IType internalType = this.getInternalType();
final String signature = internalType.needsSignature() ? internalType.getSignature() : null;
writer.visitLocalVariable(this.getInternalName(), this.getDescriptor(), signature, start, end, this.getLocalIndex());
}
use of dyvilx.tools.compiler.ast.type.IType in project Dyvil by Dyvil.
the class ThisExpr method resolveTypes.
@Override
public void resolveTypes(MarkerList markers, IContext context) {
if (this.type != Types.UNKNOWN) {
this.type = this.type.resolveType(markers, context);
// Replace e.g. this<List> with this<List<T>> in class List<type T>
final IClass iclass = this.type.getTheClass();
if (iclass != null) {
this.type = iclass.getThisType();
}
return;
}
final IType thisType = context.getThisType();
if (thisType != null) {
this.type = thisType;
} else {
markers.add(Markers.semanticError(this.position, "this.access.unresolved"));
}
}
Aggregations