DoubleConstant.java

package org.sterling.runtime.expression;

import static org.sterling.runtime.expression.BooleanConstant.FALSE;
import static org.sterling.runtime.expression.BooleanConstant.TRUE;
import static org.sterling.runtime.expression.ExpressionConversions.convertDouble;
import static org.sterling.runtime.expression.ExpressionConversions.convertSymbol;
import static org.sterling.runtime.expression.ExpressionFactory.constant;
import static org.sterling.util.StringUtil.stringify;

import java.util.Objects;
import org.sterling.SterlingException;

public class DoubleConstant extends Expression {

    private final double value;

    public DoubleConstant(double value) {
        this.value = value;
    }

    @Override
    public boolean equals(Object o) {
        return o == this || o instanceof DoubleConstant && value == ((DoubleConstant) o).value;
    }

    @Override
    public Expression access(Expression member) throws SterlingException {
        switch (convertSymbol(member).getValue()) {
            case "+": return new AddClosure(value);
            case "-": return new SubtractClosure(value);
            case "*": return new MultiplyClosure(value);
            case "/": return new DivideClosure(value);
            case "%": return new ModuloClosure(value);
            case "positive": return new DoubleConstant(Math.abs(value));
            case "negative": return new DoubleConstant(-value);
            case "toBoolean": return toBoolean();
            case "toInteger": return new IntegerConstant(Double.valueOf(value).intValue());
            case "toDouble": return this;
            case "toString": return constant(Double.valueOf(value).toString());
            default: return super.access(member);
        }
    }

    @Override
    public int hashCode() {
        return Objects.hash(value);
    }

    @Override
    public String toString() {
        return stringify(this, value);
    }

    private BooleanConstant toBoolean() {
        return value == 1D ? TRUE : FALSE;
    }

    private static abstract class DoubleClosure extends Expression {

        private final double value;

        public DoubleClosure(double value) {
            this.value = value;
        }

        @Override
        public Expression apply(Expression argument) throws SterlingException {
            return new DoubleConstant(operate(value, convertDouble(argument).value));
        }

        @Override
        public String toString() {
            return stringify(this, value);
        }

        protected abstract double operate(double leftValue, double rightValue);
    }

    private static final class AddClosure extends DoubleClosure {

        public AddClosure(double value) {
            super(value);
        }

        @Override
        protected double operate(double leftValue, double rightValue) {
            return leftValue + rightValue;
        }
    }

    private static final class SubtractClosure extends DoubleClosure {

        public SubtractClosure(double value) {
            super(value);
        }

        @Override
        protected double operate(double leftValue, double rightValue) {
            return leftValue - rightValue;
        }
    }

    private static final class MultiplyClosure extends DoubleClosure {

        public MultiplyClosure(double value) {
            super(value);
        }

        @Override
        protected double operate(double leftValue, double rightValue) {
            return leftValue * rightValue;
        }
    }

    private static final class DivideClosure extends DoubleClosure {

        public DivideClosure(double value) {
            super(value);
        }

        @Override
        protected double operate(double leftValue, double rightValue) {
            return leftValue / rightValue;
        }
    }

    private static final class ModuloClosure extends DoubleClosure {

        public ModuloClosure(double value) {
            super(value);
        }

        @Override
        protected double operate(double leftValue, double rightValue) {
            return leftValue % rightValue;
        }
    }
}