001 /*
002 // $Id: LiteralNode.java 482 2012-01-05 23:27:27Z jhyde $
003 //
004 // Licensed to Julian Hyde under one or more contributor license
005 // agreements. See the NOTICE file distributed with this work for
006 // additional information regarding copyright ownership.
007 //
008 // Julian Hyde licenses this file to you under the Apache License,
009 // Version 2.0 (the "License"); you may not use this file except in
010 // compliance with the License. You may obtain a copy of the License at:
011 //
012 // http://www.apache.org/licenses/LICENSE-2.0
013 //
014 // Unless required by applicable law or agreed to in writing, software
015 // distributed under the License is distributed on an "AS IS" BASIS,
016 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 // See the License for the specific language governing permissions and
018 // limitations under the License.
019 */
020 package org.olap4j.mdx;
021
022 import org.olap4j.impl.Olap4jUtil;
023 import org.olap4j.type.*;
024
025 import java.io.PrintWriter;
026 import java.math.BigDecimal;
027
028 /**
029 * Represents a constant value, such as a string or number, in a parse tree.
030 *
031 * <p>Symbols, such as the <code>ASC</code> keyword in
032 * <code>Order([Store].Members, [Measures].[Unit Sales], ASC)</code>, are
033 * also represented as Literals.
034 *
035 * <p>A LiteralNode is immutable.
036 *
037 * @version $Id: LiteralNode.java 482 2012-01-05 23:27:27Z jhyde $
038 * @author jhyde
039 */
040 public class LiteralNode implements ParseTreeNode {
041
042 // Data members.
043
044 private final Object value;
045 private final Type type;
046 private final ParseRegion region;
047
048 /**
049 * Private constructor.
050 *
051 * <p>Use the creation methods {@link #createString} etc.
052 *
053 * @param region Region of source code
054 * @param type Type of this literal; must not be null
055 * @param value Value of this literal, must be null only if this is the
056 * null literal
057 */
058 private LiteralNode(
059 ParseRegion region,
060 Type type,
061 Object value)
062 {
063 assert type != null;
064 assert (type instanceof NullType) == (value == null);
065 assert (type instanceof StringType || type instanceof SymbolType)
066 == (value instanceof String);
067 assert (type instanceof NumericType) == (value instanceof BigDecimal);
068 this.region = region;
069 this.type = type;
070 this.value = value;
071 }
072
073 /**
074 * Creates a literal with the NULL value.
075 *
076 * @param region Region of source code
077 * @return literal representing the NULL value
078 */
079 public static LiteralNode createNull(ParseRegion region) {
080 return new LiteralNode(region, new NullType(), null);
081 }
082
083 /**
084 * Creates a string literal.
085 *
086 * @param region Region of source code
087 * @param value String value
088 *
089 * @return literal representing the string value
090 *
091 * @see #createSymbol
092 */
093 public static LiteralNode createString(
094 ParseRegion region,
095 String value)
096 {
097 if (value == null) {
098 throw new IllegalArgumentException("value must not be null");
099 }
100 return new LiteralNode(region, new StringType(), value);
101 }
102
103 /**
104 * Creates a symbol literal.
105 *
106 * @param region Region of source code
107 * @param value Name of symbol
108 *
109 * @return literal representing the symbol value
110 *
111 * @see #createString
112 */
113 public static LiteralNode createSymbol(
114 ParseRegion region,
115 String value)
116 {
117 if (value == null) {
118 throw new IllegalArgumentException("value must not be null");
119 }
120 return new LiteralNode(region, new SymbolType(), value);
121 }
122
123 /**
124 * Creates a numeric literal.
125 *
126 * @param region Region of source code
127 * @param value Value of literal; must not be null
128 * @param approximate Whether the literal is approximate
129 *
130 * @return literal representing the integer value
131 */
132 public static LiteralNode createNumeric(
133 ParseRegion region,
134 BigDecimal value,
135 boolean approximate)
136 {
137 if (value == null) {
138 throw new IllegalArgumentException("value must not be null");
139 }
140 Olap4jUtil.discard(approximate); // reserved for future use
141 return new LiteralNode(region, new NumericType(), value);
142 }
143
144 public <T> T accept(ParseTreeVisitor<T> visitor) {
145 return visitor.visit(this);
146 }
147
148 public Type getType() {
149 return type;
150 }
151
152 public ParseRegion getRegion() {
153 return region;
154 }
155
156 /**
157 * Returns the value of this literal.
158 *
159 * <p>Value is always of type {@link String} (if the literal is a string or
160 * a symbol), of type {@link java.math.BigDecimal} (if the literal is
161 * numeric), or null (if the literal is of null type).
162 *
163 * @return value
164 */
165 public Object getValue() {
166 return value;
167 }
168
169 public void unparse(ParseTreeWriter writer) {
170 PrintWriter pw = writer.getPrintWriter();
171 if (value == null) {
172 pw.print("NULL");
173 } else if (type instanceof SymbolType) {
174 pw.print(value);
175 } else if (type instanceof NumericType) {
176 pw.print(value);
177 } else if (type instanceof StringType) {
178 pw.print(MdxUtil.quoteForMdx((String) value));
179 } else {
180 throw new AssertionError("unexpected literal type " + type);
181 }
182 }
183
184 public LiteralNode deepCopy() {
185 // No need to copy: literal nodes are immutable.
186 return this;
187 }
188
189 }
190
191 // End LiteralNode.java