use of dyvilx.tools.compiler.ast.field.IVariable in project Dyvil by Dyvil.
the class IterableForStatement method writeStatement.
@Override
public void writeStatement(MethodWriter writer) throws BytecodeException {
dyvilx.tools.asm.Label startLabel = this.startLabel.getTarget();
dyvilx.tools.asm.Label updateLabel = this.updateLabel.getTarget();
dyvilx.tools.asm.Label endLabel = this.endLabel.getTarget();
final IVariable var = this.variable;
final IType varType = var.getType();
final int lineNumber = this.lineNumber();
// Scope
dyvilx.tools.asm.Label scopeLabel = new dyvilx.tools.asm.Label();
writer.visitLabel(scopeLabel);
int localCount = writer.localCount();
// Get the iterator
var.getValue().writeExpression(writer, null);
if (!this.iterator) {
writer.visitLineNumber(lineNumber);
writer.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/lang/Iterable", "iterator", "()Ljava/util/Iterator;", true);
}
// Local Variables
int iteratorVarIndex = writer.localCount();
var.setLocalIndex(iteratorVarIndex + 1);
// Store Iterator
writer.visitVarInsn(Opcodes.ASTORE, iteratorVarIndex);
// Jump to hasNext check
writer.visitJumpInsn(Opcodes.GOTO, updateLabel);
writer.visitTargetLabel(startLabel);
// Invoke Iterator.next()
writer.visitVarInsn(Opcodes.ALOAD, iteratorVarIndex);
writer.visitLineNumber(lineNumber);
writer.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;", true);
// Auocasting
Types.OBJECT.writeCast(writer, varType, lineNumber);
// Store the next element
writer.visitVarInsn(varType.getStoreOpcode(), iteratorVarIndex + 1);
// Action
if (this.action != null) {
this.action.writeExpression(writer, Types.VOID);
}
writer.visitLabel(updateLabel);
// Load Iterator
writer.visitVarInsn(Opcodes.ALOAD, iteratorVarIndex);
// Check hasNext
writer.visitLineNumber(lineNumber);
writer.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z", true);
// Go back to start if Iterator.hasNext() returned true
writer.visitJumpInsn(Opcodes.IFNE, startLabel);
// Local Variables
writer.resetLocals(localCount);
writer.visitLabel(endLabel);
var.writeLocal(writer, scopeLabel, endLabel);
}
use of dyvilx.tools.compiler.ast.field.IVariable in project Dyvil by Dyvil.
the class StringForStatement method writeStatement.
@Override
public void writeStatement(MethodWriter writer) throws BytecodeException {
dyvilx.tools.asm.Label startLabel = this.startLabel.getTarget();
dyvilx.tools.asm.Label updateLabel = this.updateLabel.getTarget();
dyvilx.tools.asm.Label endLabel = this.endLabel.getTarget();
final IVariable var = this.variable;
final int lineNumber = this.lineNumber();
// Scope
dyvilx.tools.asm.Label scopeLabel = new dyvilx.tools.asm.Label();
writer.visitLabel(scopeLabel);
final int localCount = writer.localCount();
// Load the String
var.getValue().writeExpression(writer, null);
// Local Variables
final int stringVarIndex = writer.localCount();
final int lengthVarIndex = stringVarIndex + 1;
final int indexVarIndex = stringVarIndex + 2;
writer.visitInsn(Opcodes.DUP);
writer.visitVarInsn(Opcodes.ASTORE, stringVarIndex);
// Get the length
writer.visitLineNumber(lineNumber);
writer.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "length", "()I", false);
writer.visitInsn(Opcodes.DUP);
writer.visitVarInsn(Opcodes.ISTORE, lengthVarIndex);
// Initial Boundary Check - if the length is 0, skip the loop.
writer.visitJumpInsn(Opcodes.IFEQ, endLabel);
// Set index to 0
writer.visitLdcInsn(0);
writer.visitVarInsn(Opcodes.ISTORE, indexVarIndex);
writer.visitTargetLabel(startLabel);
// Get the char at the index
writer.visitVarInsn(Opcodes.ALOAD, stringVarIndex);
writer.visitVarInsn(Opcodes.ILOAD, indexVarIndex);
writer.visitLineNumber(lineNumber);
writer.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false);
// Autocasting
Types.CHAR.writeCast(writer, var.getType(), lineNumber);
var.writeInit(writer, null);
// Action
if (this.action != null) {
this.action.writeExpression(writer, Types.VOID);
}
writer.visitLabel(updateLabel);
// Increment index
writer.visitIincInsn(indexVarIndex, 1);
// Boundary Check
writer.visitVarInsn(Opcodes.ILOAD, indexVarIndex);
writer.visitVarInsn(Opcodes.ILOAD, lengthVarIndex);
writer.visitJumpInsn(Opcodes.IF_ICMPLT, startLabel);
// Local Variables
writer.resetLocals(localCount);
writer.visitLabel(endLabel);
var.writeLocal(writer, scopeLabel, endLabel);
}
use of dyvilx.tools.compiler.ast.field.IVariable in project Dyvil by Dyvil.
the class StatementList method addVariable.
protected void addVariable(VariableStatement initializer, MarkerList markers, IContext context) {
final IVariable variable = initializer.variable;
final Name variableName = variable.getName();
// Uninitialized Variables
if (variable.getValue() == null) {
variable.setValue(variable.getType().getDefaultValue());
markers.add(Markers.semanticError(variable.getPosition(), "variable.uninitialized", variableName));
}
// Variable Name Shadowing
final IDataMember dataMember = context.resolveField(variableName);
if (dataMember != null && dataMember.isLocal() && !variable.hasModifier(Modifiers.GENERATED)) {
markers.add(Markers.semantic(initializer.getPosition(), "variable.shadow", variableName));
}
// Actually add the Variable to the List (this has to happen after checking for shadowed variables)
this.addVariable(variable);
}
use of dyvilx.tools.compiler.ast.field.IVariable 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);
}
use of dyvilx.tools.compiler.ast.field.IVariable in project Dyvil by Dyvil.
the class StatementListParser method parse.
@Override
public void parse(IParserManager pm, IToken token) {
final int type = token.type();
if (type == BaseSymbols.CLOSE_CURLY_BRACKET) {
this.end(pm);
return;
}
if (type == Tokens.EOF) {
this.end(pm);
pm.report(token, "statement_list.close_brace");
return;
}
switch(this.mode) {
case OPEN_BRACKET:
{
final IToken next = token.next();
final IToken lambdaArrow = this.findLambdaArrow(next);
if (lambdaArrow != null) {
this.lambdaExpr = new LambdaExpr(lambdaArrow.raw());
this.lambdaExpr.setValue(this.statementList = new StatementList(token));
if (next == lambdaArrow) {
// { ->
// { =>
this.mode = LAMBDA_TYPE_ARROW;
return;
}
if (next.type() == BaseSymbols.OPEN_PARENTHESIS) {
// { ( ... ) =>
// { ( ... ) ->
pm.skip();
pm.pushParser(new ParameterListParser(this.lambdaExpr));
this.mode = LAMBDA_PARAMETERS_END;
return;
}
// { ... ->
// { ... =>
pm.pushParser(new ParameterListParser(this.lambdaExpr).withFlags(LAMBDA_ARROW_END));
this.mode = LAMBDA_TYPE_ARROW;
return;
}
// { ...
this.statementList = this.closure ? new Closure(token) : new StatementList(token);
this.mode = EXPRESSION;
if (type != BaseSymbols.OPEN_CURLY_BRACKET) {
pm.report(token, "statement_list.open_brace");
pm.reparse();
}
return;
}
case LAMBDA_PARAMETERS_END:
this.mode = LAMBDA_TYPE_ARROW;
if (type != BaseSymbols.CLOSE_PARENTHESIS) {
pm.report(token, "statement_list.lambda.close_paren");
}
return;
case LAMBDA_TYPE_ARROW:
if (type == DyvilSymbols.ARROW_RIGHT) {
pm.pushParser(LambdaOrTupleParser.returnTypeParser(this.lambdaExpr));
this.mode = LAMBDA_RETURN_ARROW;
return;
}
// Fallthrough
case LAMBDA_RETURN_ARROW:
if (type != DyvilSymbols.DOUBLE_ARROW_RIGHT) {
pm.report(token, "statement_list.lambda.arrow");
return;
}
this.mode = EXPRESSION;
return;
case EXPRESSION:
switch(type) {
case BaseSymbols.SEMICOLON:
case BaseSymbols.COMMA:
return;
case DyvilKeywords.LABEL:
this.mode = LABEL_NAME;
return;
}
this.mode = SEPARATOR;
final MemberParser<IVariable> parser = new MemberParser<>(this).withFlags(MemberParser.NO_FIELD_PROPERTIES);
if (this.tryParserManager.tryParse(pm, parser, token, EXIT_ON_ROOT)) {
return;
}
pm.pushParser(new ExpressionParser(this));
return;
case LABEL_NAME:
if (Tokens.isIdentifier(type)) {
this.label = token.nameValue();
this.mode = LABEL_END;
return;
}
this.mode = EXPRESSION;
if (type != BaseSymbols.COLON) {
pm.reparse();
}
pm.report(token, "statement_list.label.name");
return;
case LABEL_END:
switch(type) {
case BaseSymbols.COLON:
case BaseSymbols.SEMICOLON:
this.mode = EXPRESSION;
return;
}
this.mode = EXPRESSION;
pm.reparse();
pm.report(SourcePosition.between(token, token.next()), "statement_list.label.separator");
return;
case SEPARATOR:
this.mode = EXPRESSION;
switch(type) {
case BaseSymbols.SEMICOLON:
case BaseSymbols.COMMA:
return;
}
pm.report(token, "statement_list.semicolon");
}
}
Aggregations