use of dyvilx.tools.compiler.ast.expression.access.MethodCall in project Dyvil by Dyvil.
the class ForEachStatement method resolve.
@Override
public IValue resolve(MarkerList markers, IContext context) {
IType varType = this.variable.getType();
final IValue value = this.resolveValue(markers, context);
final IType valueType = value.getType();
if (value.valueTag() == IValue.METHOD_CALL) {
final MethodCall rangeOperator = (MethodCall) value;
if (RangeForStatement.isRangeOperator(rangeOperator)) {
final IType elementType = RangeForStatement.getElementType(rangeOperator);
if (varType == Types.UNKNOWN) {
this.inferVariableType(markers, elementType);
} else if (!Types.isAssignable(varType, elementType)) {
final Marker marker = Markers.semanticError(value.getPosition(), "for.range.type");
marker.addInfo(Markers.getSemantic("range.type", valueType));
marker.addInfo(Markers.getSemantic("variable.type", varType));
markers.add(marker);
}
final RangeForStatement rangeForStatement = new RangeForStatement(this.position, this.variable, elementType);
rangeForStatement.resolveAction(this.action, markers, context);
return rangeForStatement;
}
}
final ArrayType arrayType = valueType.extract(ArrayType.class);
if (arrayType != null) {
if (varType == Types.UNKNOWN) {
this.inferVariableType(markers, arrayType.getElementType());
} else if (!Types.isAssignable(varType, arrayType.getElementType())) {
final Marker marker = Markers.semanticError(value.getPosition(), "for.array.type");
marker.addInfo(Markers.getSemantic("array.type", valueType));
marker.addInfo(Markers.getSemantic("variable.type", varType));
markers.add(marker);
}
final ArrayForStatement arrayForStatement = new ArrayForStatement(this.position, this.variable, arrayType);
arrayForStatement.resolveAction(this.action, markers, context);
return arrayForStatement;
}
if (Types.isAssignable(IterableForStatement.LazyFields.ITERATOR, valueType)) {
return this.toIteratorLoop(markers, context, varType, value, valueType);
}
if (Types.isAssignable(IterableForStatement.LazyFields.ITERABLE, valueType)) {
return this.toIterable(markers, context, varType, value, valueType);
}
if (Types.isAssignable(Types.STRING, valueType)) {
return this.toStringLoop(markers, context, varType, value);
}
final Marker marker = Markers.semanticError(this.variable.getPosition(), "for.each.invalid");
marker.addInfo(Markers.getSemantic("value.type", valueType));
markers.add(marker);
this.resolveAction(this.action, markers, context);
return this;
}
use of dyvilx.tools.compiler.ast.expression.access.MethodCall in project Dyvil by Dyvil.
the class Template method makeMainMethod.
private void makeMainMethod() {
// func main(args: [String]) -> void = new TemplateName().mainImpl(args)
final ParameterList params = this.mainMethod.getParameters();
final CodeParameter argsParam = new CodeParameter(this.mainMethod, null, Name.fromRaw("args"), new ArrayType(Types.STRING));
params.add(argsParam);
final IValue newTemplate = new ConstructorCall(null, this.templateClass.getClassType(), ArgumentList.EMPTY);
this.mainMethod.setValue(new MethodCall(null, newTemplate, Name.fromRaw("mainImpl"), new ArgumentList(new FieldAccess(argsParam))));
}
use of dyvilx.tools.compiler.ast.expression.access.MethodCall in project Dyvil by Dyvil.
the class UnapplyPattern method withType.
@Override
public Pattern withType(IType type, MarkerList markers) {
// PatternType.unapply(_ : MatchedType)
final IClass matchClass = this.type.getTheClass();
if (matchClass == null) {
return null;
}
final MethodCall methodCall = new MethodCall(this.position, new ClassAccess(this.type), Names.unapply, new ArgumentList(new DummyValue(type)));
final IValue resolvedCall = methodCall.resolveCall(MarkerList.BLACKHOLE, matchClass, false);
return resolvedCall != null && this.withMethod(type, resolvedCall, markers) ? this : null;
}
use of dyvilx.tools.compiler.ast.expression.access.MethodCall in project Dyvil by Dyvil.
the class CaseClassMetadata method createUnapplyAnyMethod.
private CodeMethod createUnapplyAnyMethod() {
// static final func unapply<TypeParams...>(value: any) -> (T...)?
final SourcePosition position = this.theClass.position();
final AttributeList attributes = AttributeList.of(Modifiers.PUBLIC | Modifiers.STATIC_FINAL | Modifiers.GENERATED);
final IType type = NullableType.apply(this.getUnapplyReturnType());
final CodeMethod unapply = new CodeMethod(this.theClass, Names.unapply, type, attributes);
unapply.setPosition(position);
unapply.getTypeParameters().addAll(this.theClass.getTypeParameters());
final CodeParameter parameter = new CodeParameter(unapply, position, Names.value, Types.NULLABLE_ANY);
unapply.getParameters().add(parameter);
// = (param is This) ? unapply(param as This) : null
final InstanceOfOperator isOperator = new InstanceOfOperator(new FieldAccess(parameter), this.theClass.getClassType());
final CastOperator castOperator = new CastOperator(new FieldAccess(parameter), this.theClass.getThisType());
final IValue call = new MethodCall(position, null, Names.unapply, new ArgumentList(castOperator));
final IfStatement ifStatement = new IfStatement(isOperator, call, new NullValue());
unapply.setValue(ifStatement);
return unapply;
}
use of dyvilx.tools.compiler.ast.expression.access.MethodCall in project Dyvil by Dyvil.
the class RangeForStatement method writeStatement.
@Override
public void writeStatement(MethodWriter writer) throws BytecodeException {
// Determine the kind (int, long, float, double, Rangeable) of the range to fasten up compilation.
byte kind = RANGEABLE;
boolean boxed = false;
final int lineNumber = this.lineNumber();
final IVariable var = this.variable;
final IType varType = var.getType();
final MethodCall rangeOperator = (MethodCall) var.getValue();
final IValue startValue = getStartValue(rangeOperator);
final IValue endValue = getEndValue(rangeOperator);
final IType elementType = this.elementType;
final boolean halfOpen = isHalfOpen(rangeOperator);
if (elementType.isPrimitive()) {
switch(elementType.getTypecode()) {
case PrimitiveType.BYTE_CODE:
case PrimitiveType.SHORT_CODE:
case PrimitiveType.CHAR_CODE:
case PrimitiveType.INT_CODE:
kind = INT;
break;
case PrimitiveType.LONG_CODE:
kind = LONG;
break;
case PrimitiveType.FLOAT_CODE:
kind = FLOAT;
break;
case PrimitiveType.DOUBLE_CODE:
kind = DOUBLE;
break;
}
if (!varType.isPrimitive()) {
boxed = true;
}
}
dyvilx.tools.asm.Label startLabel = this.startLabel.getTarget();
dyvilx.tools.asm.Label updateLabel = this.updateLabel.getTarget();
dyvilx.tools.asm.Label endLabel = this.endLabel.getTarget();
dyvilx.tools.asm.Label scopeLabel = new dyvilx.tools.asm.Label();
writer.visitLabel(scopeLabel);
// Write the start value and store it in the variable.
startValue.writeExpression(writer, elementType);
final int counterVarIndex, varIndex;
if (boxed) {
// Create two variables, the counter variable and the user-visible loop variable
writer.visitInsn(Opcodes.AUTO_DUP);
counterVarIndex = writer.localCount();
writer.visitVarInsn(elementType.getStoreOpcode(), counterVarIndex);
elementType.writeCast(writer, varType, lineNumber);
var.writeInit(writer, null);
varIndex = var.getLocalIndex();
} else {
// Use the loop variable as the counter variable
var.writeInit(writer, null);
varIndex = counterVarIndex = var.getLocalIndex();
}
endValue.writeExpression(writer, elementType);
final int endVarIndex = writer.localCount();
writer.visitVarInsn(elementType.getStoreOpcode(), endVarIndex);
writer.visitTargetLabel(startLabel);
// Check the condition
switch(kind) {
case INT:
writer.visitVarInsn(Opcodes.ILOAD, counterVarIndex);
writer.visitVarInsn(Opcodes.ILOAD, endVarIndex);
writer.visitJumpInsn(halfOpen ? Opcodes.IF_ICMPGE : Opcodes.IF_ICMPGT, endLabel);
break;
case LONG:
writer.visitVarInsn(Opcodes.LLOAD, counterVarIndex);
writer.visitVarInsn(Opcodes.LLOAD, endVarIndex);
writer.visitJumpInsn(halfOpen ? Opcodes.IF_LCMPGE : Opcodes.IF_LCMPGT, endLabel);
break;
case FLOAT:
writer.visitVarInsn(Opcodes.FLOAD, counterVarIndex);
writer.visitVarInsn(Opcodes.FLOAD, endVarIndex);
writer.visitJumpInsn(halfOpen ? Opcodes.IF_FCMPGE : Opcodes.IF_FCMPGT, endLabel);
break;
case DOUBLE:
writer.visitVarInsn(Opcodes.DLOAD, counterVarIndex);
writer.visitVarInsn(Opcodes.DLOAD, endVarIndex);
writer.visitJumpInsn(halfOpen ? Opcodes.IF_DCMPGE : Opcodes.IF_DCMPGT, endLabel);
break;
case RANGEABLE:
writer.visitVarInsn(Opcodes.ALOAD, counterVarIndex);
writer.visitVarInsn(Opcodes.ALOAD, endVarIndex);
writer.visitLineNumber(lineNumber);
writer.visitMethodInsn(Opcodes.INVOKEINTERFACE, "dyvil/collection/range/Rangeable", "compareTo", "(Ldyvil/collection/range/Rangeable;)I", true);
writer.visitJumpInsn(halfOpen ? Opcodes.IFGE : Opcodes.IFGT, endLabel);
break;
}
// Action
if (this.action != null) {
this.action.writeExpression(writer, Types.VOID);
}
// Increment
writer.visitLabel(updateLabel);
switch(kind) {
case INT:
writer.visitIincInsn(counterVarIndex, 1);
if (boxed) {
writer.visitVarInsn(Opcodes.ILOAD, counterVarIndex);
elementType.writeCast(writer, varType, lineNumber);
writer.visitVarInsn(varType.getStoreOpcode(), varIndex);
}
break;
case LONG:
writer.visitVarInsn(Opcodes.LLOAD, counterVarIndex);
writer.visitInsn(Opcodes.LCONST_1);
writer.visitInsn(Opcodes.LADD);
if (boxed) {
writer.visitInsn(Opcodes.DUP2);
elementType.writeCast(writer, varType, lineNumber);
writer.visitVarInsn(varType.getStoreOpcode(), varIndex);
}
writer.visitVarInsn(Opcodes.LSTORE, counterVarIndex);
break;
case FLOAT:
writer.visitVarInsn(Opcodes.FLOAD, counterVarIndex);
writer.visitInsn(Opcodes.FCONST_1);
writer.visitInsn(Opcodes.FADD);
if (boxed) {
writer.visitInsn(Opcodes.DUP);
elementType.writeCast(writer, varType, lineNumber);
writer.visitVarInsn(varType.getStoreOpcode(), varIndex);
}
writer.visitVarInsn(Opcodes.FSTORE, counterVarIndex);
break;
case DOUBLE:
writer.visitVarInsn(Opcodes.DLOAD, counterVarIndex);
writer.visitInsn(Opcodes.DCONST_1);
writer.visitInsn(Opcodes.DADD);
if (boxed) {
writer.visitInsn(Opcodes.DUP2);
elementType.writeCast(writer, varType, lineNumber);
writer.visitVarInsn(varType.getStoreOpcode(), varIndex);
}
writer.visitVarInsn(Opcodes.DSTORE, counterVarIndex);
break;
case RANGEABLE:
writer.visitVarInsn(Opcodes.ALOAD, counterVarIndex);
writer.visitLineNumber(lineNumber);
writer.visitMethodInsn(Opcodes.INVOKEINTERFACE, "dyvil/collection/range/Rangeable", "next", "()Ldyvil/collection/range/Rangeable;", true);
if (elementType.getTheClass() != LazyFields.RANGEABLE_CLASS) {
LazyFields.RANGEABLE.writeCast(writer, elementType, lineNumber);
}
assert !boxed;
writer.visitVarInsn(Opcodes.ASTORE, counterVarIndex);
break;
}
writer.visitJumpInsn(Opcodes.GOTO, startLabel);
// Local Variables
writer.resetLocals(counterVarIndex);
writer.visitLabel(endLabel);
var.writeLocal(writer, scopeLabel, endLabel);
}
Aggregations