package de.skuzzle.polly.core.parser.ast.expressions.literals; import de.skuzzle.polly.core.parser.Position; import de.skuzzle.polly.core.parser.ast.declarations.types.Type; import de.skuzzle.polly.core.parser.ast.expressions.Expression; import de.skuzzle.polly.core.parser.ast.visitor.ASTTraversalException; import de.skuzzle.polly.core.parser.ast.visitor.Transformation; import de.skuzzle.polly.core.parser.problems.ProblemReporter; import de.skuzzle.polly.core.parser.problems.Problems; import de.skuzzle.polly.tools.Equatable; /** * Represents a number literal. Numbers are always floating point doubles. * * @author Simon Taddiken */ public class NumberLiteral extends Literal { private final double value; private int radix; /** * Creates a new NumberLiteral. * * @param position Position of this literal within the source. * @param value Value of this literal. */ public NumberLiteral(Position position, double value) { super(position, Type.NUM); this.value = value; this.radix = 10; } /** * Gets the radix of this number. Only suitable for integer numbers and will only * be used when formatting this literal using {@link #format(LiteralFormatter)}. * * @return The radix of this literal. */ public int getRadix() { return this.radix; } /** * Sets the radix for this literal. Only suitable for integer numbers and will only * have effect on the output of {@link #format(LiteralFormatter)}. * * @param radix The new radix for this number. */ public void setRadix(int radix) { this.radix = radix; } /** * Gets the value of this literal. * * @return The literal's value. */ public double getValue() { return this.value; } /** * Asserts that this literal's value is an integer number. If not, an * {@link ASTTraversalException} will be thrown. The exception uses this literal's * position. * * @param reporter Error reporter which will report the assertion error. * @return This literal's value as integer. * @throws ASTTraversalException If {@link #getValue()} returns 0. */ public int isInteger(ProblemReporter reporter) throws ASTTraversalException { return this.isInteger(this.getPosition(), reporter); } /** * Asserts that this literal's value is an integer number. If not, an * {@link ASTTraversalException} will be thrown. * * @param pos Position that will be reported in the thrown exception. * @param reporter Error reporter which will report the assertion error. * @return This literal's value as integer. * @throws ASTTraversalException If {@link #getValue()} returns 0. */ public int isInteger(Position pos, ProblemReporter reporter) throws ASTTraversalException { if (Math.round(this.getValue()) != this.getValue()) { reporter.runtimeProblem(Problems.INTEGER_REQUIRED, pos); } return (int) Math.round(this.getValue()); } /** * Asserts that this literal's value is non zero and integer. If not, an * {@link ASTTraversalException} will be thrown. The exception uses this literal's * position. * @param reporter Error reporter which will report the assertion error. * @return This literal's value as returned by {@link #getValue()}. * @throws ASTTraversalException If {@link #getValue()} returns 0. */ public int nonZeroInteger(ProblemReporter reporter) throws ASTTraversalException { this.nonZero(reporter); return this.isInteger(reporter); } /** * Asserts that this literal's value is non zero and integer. If not, * an {@link ASTTraversalException} will be thrown. * * @param pos Position that will be reported in the thrown exception. * @param reporter Error reporter which will report the assertion error. * @return This literal's value as returned by {@link #getValue()}. * @throws ASTTraversalException If {@link #getValue()} returns 0 or the value * is no integer. */ public int nonZeroInteger(Position pos, ProblemReporter reporter) throws ASTTraversalException { this.nonZero(pos, reporter); return this.isInteger(pos, reporter); } /** * Asserts that this literal's value is non zero. If it is zero, an * {@link ASTTraversalException} exception is thrown. The exception uses the position * of this literal. * @param reporter Error reporter which will report the assertion error. * @return This literal's value as returned by {@link #getValue()}. * @throws ASTTraversalException If {@link #getValue()} returns 0. */ public double nonZero(ProblemReporter reporter) throws ASTTraversalException { return this.nonZero(this.getPosition(), reporter); } /** * Asserts that this literal's value is non zero. If it is zero, an * {@link ASTTraversalException} exception is thrown. * * @param pos Position that will be reported in the thrown exception. * @param reporter Error reporter which will report the assertion error. * @return This literal's value as returned by {@link #getValue()}. * @throws ASTTraversalException If {@link #getValue()} returns 0. */ public double nonZero(Position pos, ProblemReporter reporter) throws ASTTraversalException { if (this.getValue() == 0.0) { reporter.runtimeProblem(Problems.DIVISION_BY_ZERO, pos); } return this.getValue(); } @Override public String format(LiteralFormatter formatter) { return formatter.formatNumberLiteral(this); } @Override public Expression transform(Transformation transformation) throws ASTTraversalException { return transformation.transformNumber(this); } @Override public int compareTo(Literal o) { if (o instanceof NumberLiteral) { return Double.compare(this.value, ((NumberLiteral) o).value); } return super.compareTo(o); } @Override public Literal castTo(Type type) throws ASTTraversalException { if (type.equals(Type.TIMESPAN)) { // treat this number as milliseconds return new TimespanLiteral(this.getPosition(), (int)(this.getValue() / 1000)); } return super.castTo(type); } @Override public String toString() { return Double.toString(this.value); } @Override public Class<?> getEquivalenceClass() { return NumberLiteral.class; } @Override public boolean actualEquals(Equatable o) { final NumberLiteral other = (NumberLiteral) o; return Double.compare(this.value, other.value) == 0; } }