diff --git a/src/main/java/dk/camelot64/kickc/passes/PassNAddNumberTypeConversions.java b/src/main/java/dk/camelot64/kickc/passes/PassNAddNumberTypeConversions.java index f1bed6038..b12ad19ca 100644 --- a/src/main/java/dk/camelot64/kickc/passes/PassNAddNumberTypeConversions.java +++ b/src/main/java/dk/camelot64/kickc/passes/PassNAddNumberTypeConversions.java @@ -1,12 +1,16 @@ package dk.camelot64.kickc.passes; +import dk.camelot64.kickc.model.CompileError; import dk.camelot64.kickc.model.InternalError; import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.iterator.BinaryExpressionIterator; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolTypeInference; import dk.camelot64.kickc.model.types.SymbolTypeIntegerFixed; -import dk.camelot64.kickc.model.values.*; +import dk.camelot64.kickc.model.values.ConstantInteger; +import dk.camelot64.kickc.model.values.ConstantLiteral; +import dk.camelot64.kickc.model.values.ConstantValue; +import dk.camelot64.kickc.model.values.RValue; /** * Add casts to {@link SymbolType#NUMBER} expressions that meet a typed value in a binary expression (including assignment) @@ -22,38 +26,86 @@ public class PassNAddNumberTypeConversions extends Pass2SsaOptimization { BinaryExpressionIterator.execute(getProgram(), (binaryExpression, currentStmt, stmtIt, currentBlock) -> { RValue left = binaryExpression.getLeft(); RValue right = binaryExpression.getRight(); + SymbolType conversionType = getNumberConversionType(left, right); + if(conversionType != null) { + // Convert both left and right to the found type + + getLog().append("Adding number conversion cast (" + fixedType+ ") " + binaryExpression.getRight().toString() + " in " + currentStmt.toString(getProgram(), false)); + - SymbolType leftType = SymbolTypeInference.inferType(getScope(), left); - SymbolType rightType = SymbolTypeInference.inferType(getScope(), right); - if(SymbolType.isInteger(leftType) && !SymbolType.NUMBER.equals(leftType) && SymbolType.NUMBER.equals(rightType)) { - SymbolTypeIntegerFixed leftIntType = (SymbolTypeIntegerFixed) leftType; - // Attempt to find number conversion! - if(right instanceof ConstantValue) { - ConstantLiteral constantLiteral = ((ConstantValue) right).calculateLiteral(getProgram().getScope()); - if(constantLiteral instanceof ConstantInteger) { - ConstantInteger constantInteger = (ConstantInteger) constantLiteral; - if(SymbolType.NUMBER.equals(constantInteger.getType())) { - Long value = constantInteger.getValue(); - if(leftIntType.getMinValue()<=value && leftIntType.getMaxValue()>=value) { - // The value matches the left type! - getLog().append("Adding number conversion cast ("+leftIntType+") "+binaryExpression.getRight().toString()+" in "+currentStmt.toString(getProgram(), false)); - binaryExpression.addRightCast(leftIntType); - } else { - throw new InternalError("TODO: Implement number conversion for non-equal types "+right.toString(), currentStmt); - } - } else { - throw new InternalError("Non-number constant has type number "+right.toString(), currentStmt); - } - } - } else { - // Postpone til later! - // Maybe handle AssignmentRValue separately! - getLog().append("Postponed number conversion " + right.toString()); - } } + }); return false; } + private SymbolType getNumberConversionType(RValue left, RValue right) { + + SymbolType leftType = SymbolTypeInference.inferType(getProgram().getScope(), left); + SymbolType rightType = SymbolTypeInference.inferType(getProgram().getScope(), right); + + if(SymbolType.NUMBER.equals(leftType) || SymbolType.NUMBER.equals(rightType)) { + // A special type number is assigned to integer constants without a postfix literal. + // Numbers are flexible and will take a type based on their actual value when they meet a typed number in a calculation. + // Number types are only usable at compile time. + + if(leftType.equals(rightType)) { + // a) If the two operands are numbers the result is a number + return null; + } + + RValue numberVal; + SymbolTypeIntegerFixed fixedType; + if(SymbolType.NUMBER.equals(leftType) && SymbolType.isInteger(rightType)) { + // Left is the number + numberVal = left; + fixedType = (SymbolTypeIntegerFixed) rightType; + } else if(SymbolType.NUMBER.equals(rightType) && SymbolType.isInteger(leftType)) { + // Right is the number + numberVal = right; + fixedType = (SymbolTypeIntegerFixed) leftType; + } else { + // Non-integer number binary + throw new CompileError("Error! Incompatible operands "+left.toString()+" and "+right.toString()); + } + + if(numberVal instanceof ConstantValue) { + ConstantLiteral constantLiteral = ((ConstantValue) numberVal).calculateLiteral(getProgram().getScope()); + if(constantLiteral instanceof ConstantInteger) { + ConstantInteger constantInteger = (ConstantInteger) constantLiteral; + if(SymbolType.NUMBER.equals(constantInteger.getType())) { + Long value = constantInteger.getValue(); + if(fixedType.getMinValue() <= value && fixedType.getMaxValue() >= value) { + // The value matches the left type! + binaryExpression.addRightCast(leftIntType); + } else { + throw new InternalError("TODO: Implement number conversion for non-equal types " + right.toString(), currentStmt); + } + } else { + throw new InternalError("Non-number constant has type number " + right.toString(), currentStmt); + } + } + } else { + // Postpone til later! + // Maybe handle AssignmentRValue separately! + getLog().append("Postponed number conversion " + right.toString()); + } + + + + + } + + // No number conversion + return null; + + if(SymbolType.isInteger(leftType) && !SymbolType.NUMBER.equals(leftType) && SymbolType.NUMBER.equals(rightType)) { + SymbolTypeIntegerFixed leftIntType = (SymbolTypeIntegerFixed) leftType; + // Attempt to find number conversion! + } + + return null; + } + }