001    /*
002    // $Id: LiteralNode.java 404 2011-03-18 21:54:56Z lucboudreau $
003    // This software is subject to the terms of the Eclipse Public License v1.0
004    // Agreement, available at the following URL:
005    // http://www.eclipse.org/legal/epl-v10.html.
006    // Copyright (C) 2007-2010 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package org.olap4j.mdx;
011    
012    import org.olap4j.impl.Olap4jUtil;
013    import org.olap4j.type.*;
014    
015    import java.io.PrintWriter;
016    import java.math.BigDecimal;
017    
018    /**
019     * Represents a constant value, such as a string or number, in a parse tree.
020     *
021     * <p>Symbols, such as the <code>ASC</code> keyword in
022     * <code>Order([Store].Members, [Measures].[Unit Sales], ASC)</code>, are
023     * also represented as Literals.
024     *
025     * <p>A LiteralNode is immutable.
026     *
027     * @version $Id: LiteralNode.java 404 2011-03-18 21:54:56Z lucboudreau $
028     * @author jhyde
029     */
030    public class LiteralNode implements ParseTreeNode {
031    
032        // Data members.
033    
034        private final Object value;
035        private final Type type;
036        private final ParseRegion region;
037    
038        /**
039         * Private constructor.
040         *
041         * <p>Use the creation methods {@link #createString} etc.
042         *
043         * @param region Region of source code
044         * @param type Type of this literal; must not be null
045         * @param value Value of this literal, must be null only if this is the
046         *   null literal
047         */
048        private LiteralNode(
049            ParseRegion region,
050            Type type,
051            Object value)
052        {
053            assert type != null;
054            assert (type instanceof NullType) == (value == null);
055            assert (type instanceof StringType || type instanceof SymbolType)
056                   == (value instanceof String);
057            assert (type instanceof NumericType) == (value instanceof BigDecimal);
058            this.region = region;
059            this.type = type;
060            this.value = value;
061        }
062    
063        /**
064         * Creates a literal with the NULL value.
065         *
066         * @param region Region of source code
067         * @return literal representing the NULL value
068         */
069        public static LiteralNode createNull(ParseRegion region) {
070            return new LiteralNode(region, new NullType(), null);
071        }
072    
073        /**
074         * Creates a string literal.
075         *
076         * @param region Region of source code
077         * @param value String value
078         *
079         * @return literal representing the string value
080         *
081         * @see #createSymbol
082         */
083        public static LiteralNode createString(
084            ParseRegion region,
085            String value)
086        {
087            if (value == null) {
088                throw new IllegalArgumentException("value must not be null");
089            }
090            return new LiteralNode(region, new StringType(), value);
091        }
092    
093        /**
094         * Creates a symbol literal.
095         *
096         * @param region Region of source code
097         * @param value Name of symbol
098         *
099         * @return literal representing the symbol value
100         *
101         * @see #createString
102         */
103        public static LiteralNode createSymbol(
104            ParseRegion region,
105            String value)
106        {
107            if (value == null) {
108                throw new IllegalArgumentException("value must not be null");
109            }
110            return new LiteralNode(region, new SymbolType(), value);
111        }
112    
113        /**
114         * Creates a numeric literal.
115         *
116         * @param region Region of source code
117         * @param value Value of literal; must not be null
118         * @param approximate Whether the literal is approximate
119         *
120         * @return literal representing the integer value
121         */
122        public static LiteralNode createNumeric(
123            ParseRegion region,
124            BigDecimal value,
125            boolean approximate)
126        {
127            if (value == null) {
128                throw new IllegalArgumentException("value must not be null");
129            }
130            Olap4jUtil.discard(approximate); // reserved for future use
131            return new LiteralNode(region, new NumericType(), value);
132        }
133    
134        public <T> T accept(ParseTreeVisitor<T> visitor) {
135            return visitor.visit(this);
136        }
137    
138        public Type getType() {
139            return type;
140        }
141    
142        public ParseRegion getRegion() {
143            return region;
144        }
145    
146        /**
147         * Returns the value of this literal.
148         *
149         * <p>Value is always of type {@link String} (if the literal is a string or
150         * a symbol), of type {@link java.math.BigDecimal} (if the literal is
151         * numeric), or null (if the literal is of null type).
152         *
153         * @return value
154         */
155        public Object getValue() {
156            return value;
157        }
158    
159        public void unparse(ParseTreeWriter writer) {
160            PrintWriter pw = writer.getPrintWriter();
161            if (value == null) {
162                pw.print("NULL");
163            } else if (type instanceof SymbolType) {
164                pw.print(value);
165            } else if (type instanceof NumericType) {
166                pw.print(value);
167            } else if (type instanceof StringType) {
168                pw.print(MdxUtil.quoteForMdx((String) value));
169            } else {
170                throw new AssertionError("unexpected literal type " + type);
171            }
172        }
173    
174        public LiteralNode deepCopy() {
175            // No need to copy: literal nodes are immutable.
176            return this;
177        }
178    
179    }
180    
181    // End LiteralNode.java