001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 1998-2005 Julian Hyde
008// Copyright (C) 2005-2011 Pentaho and others
009// All Rights Reserved.
010*/
011package mondrian.olap;
012
013import mondrian.calc.Calc;
014import mondrian.calc.ExpCompiler;
015import mondrian.calc.impl.ConstantCalc;
016import mondrian.mdx.MdxVisitor;
017import mondrian.olap.type.*;
018
019import org.olap4j.impl.UnmodifiableArrayMap;
020
021import java.io.PrintWriter;
022import java.math.BigDecimal;
023import java.util.Map;
024
025/**
026 * Represents a constant value, such as a string or number, in a parse tree.
027 *
028 * <p>Symbols, such as the <code>ASC</code> keyword in
029 * <code>Order([Store].Members, [Measures].[Unit Sales], ASC)</code>, are
030 * also represented as Literals.
031 *
032 * @author jhyde, 21 January, 1999
033 */
034public class Literal extends ExpBase {
035
036    // Data members.
037
038    public final int category;
039    private final Object o;
040
041
042    // Constants for commonly used literals.
043
044    public static final Literal nullValue = new Literal(Category.Null, null);
045
046    public static final Literal emptyString = new Literal(Category.String, "");
047
048    public static final Literal zero =
049        new Literal(Category.Numeric, BigDecimal.ZERO);
050
051    public static final Literal one =
052        new Literal(Category.Numeric, BigDecimal.ONE);
053
054    public static final Literal negativeOne =
055        new Literal(Category.Numeric, BigDecimal.ONE.negate());
056
057    public static final Literal doubleZero = zero;
058
059    public static final Literal doubleOne = one;
060
061    public static final Literal doubleNegativeOne = negativeOne;
062
063    private static final Map<BigDecimal, Literal> MAP =
064        UnmodifiableArrayMap.of(
065            BigDecimal.ZERO, zero,
066            BigDecimal.ONE, one,
067            BigDecimal.ONE.negate(), negativeOne);
068
069    /**
070     * Private constructor.
071     *
072     * <p>Use the creation methods {@link #createString(String)} etc.
073     */
074    private Literal(int type, Object o) {
075        this.category = type;
076        this.o = o;
077    }
078
079    /**
080     * Creates a string literal.
081     * @see #createSymbol
082     */
083    public static Literal createString(String s) {
084        return (s.equals(""))
085            ? emptyString
086            : new Literal(Category.String, s);
087    }
088
089    /**
090     * Creates a symbol.
091     *
092     * @see #createString
093     */
094    public static Literal createSymbol(String s) {
095        return new Literal(Category.Symbol, s);
096    }
097
098    /**
099     * Creates a numeric literal.
100     *
101     * @deprecated Use {@link #create(java.math.BigDecimal)}
102     */
103    public static Literal create(Double d) {
104        return new Literal(Category.Numeric, new BigDecimal(d));
105    }
106
107    /**
108     * Creates an integer literal.
109     *
110     * @deprecated Use {@link #create(java.math.BigDecimal)}
111     */
112    public static Literal create(Integer i) {
113        return new Literal(Category.Numeric, new BigDecimal(i));
114    }
115
116    /**
117     * Creates a numeric literal.
118     *
119     * <p>Using a {@link BigDecimal} allows us to store the precise value that
120     * the user typed. We will have to fit the value into a native
121     * {@code double} or {@code int} later on, but parse time is not the time to
122     * be throwing away information.
123     */
124    public static Literal create(BigDecimal d) {
125        final Literal literal = MAP.get(d);
126        if (literal != null) {
127            return literal;
128        }
129        return new Literal(Category.Numeric, d);
130    }
131
132    public Literal clone() {
133        return this;
134    }
135
136    public void unparse(PrintWriter pw) {
137        switch (category) {
138        case Category.Symbol:
139        case Category.Numeric:
140            pw.print(o);
141            break;
142        case Category.String:
143            pw.print(Util.quoteForMdx((String) o));
144            break;
145        case Category.Null:
146            pw.print("NULL");
147            break;
148        default:
149            throw Util.newInternal("bad literal type " + category);
150        }
151    }
152
153    public int getCategory() {
154        return category;
155    }
156
157    public Type getType() {
158        switch (category) {
159        case Category.Symbol:
160            return new SymbolType();
161        case Category.Numeric:
162            return new NumericType();
163        case Category.String:
164            return new StringType();
165        case Category.Null:
166            return new NullType();
167        default:
168            throw Category.instance.badValue(category);
169        }
170    }
171
172    public Exp accept(Validator validator) {
173        return this;
174    }
175
176    public Calc accept(ExpCompiler compiler) {
177        return new ConstantCalc(getType(), o);
178    }
179
180    public Object accept(MdxVisitor visitor) {
181        return visitor.visit(this);
182    }
183
184    public Object getValue() {
185        return o;
186    }
187
188    public int getIntValue() {
189        if (o instanceof Number) {
190            return ((Number) o).intValue();
191        } else {
192            throw Util.newInternal("cannot convert " + o + " to int");
193        }
194    }
195
196}
197
198// End Literal.java