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*/ 020package org.olap4j.mdx; 021 022import org.olap4j.impl.Olap4jUtil; 023import org.olap4j.type.*; 024 025import java.io.PrintWriter; 026import 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 */ 040public 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