001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.internal.compiler.ASTVisitor;
013: import org.eclipse.jdt.internal.compiler.impl.*;
014: import org.eclipse.jdt.internal.compiler.codegen.*;
015: import org.eclipse.jdt.internal.compiler.lookup.*;
016: import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
017:
018: public class LongLiteral extends NumberLiteral {
019: static final Constant FORMAT_ERROR = DoubleConstant
020: .fromValue(1.0 / 0.0); // NaN;
021:
022: public LongLiteral(char[] token, int s, int e) {
023: super (token, s, e);
024: }
025:
026: public void computeConstant() {
027: //the overflow (when radix=10) is tested using the fact that
028: //the value should always grow during its computation
029: int length = source.length - 1; //minus one because the last char is 'l' or 'L'
030:
031: long computedValue;
032: if (source[0] == '0') {
033: if (length == 1) {
034: constant = LongConstant.fromValue(0L);
035: return;
036: }
037: final int shift, radix;
038: int j;
039: if ((source[1] == 'x') || (source[1] == 'X')) {
040: shift = 4;
041: j = 2;
042: radix = 16;
043: } else {
044: shift = 3;
045: j = 1;
046: radix = 8;
047: }
048: int nbDigit = 0;
049: while (source[j] == '0') {
050: j++; //jump over redondant zero
051: if (j == length) {
052: //watch for 0000000000000L
053: constant = LongConstant.fromValue(0L);
054: return;
055: }
056: }
057:
058: int digitValue;
059: if ((digitValue = ScannerHelper.digit(source[j++], radix)) < 0) {
060: constant = FORMAT_ERROR;
061: return;
062: }
063: if (digitValue >= 8)
064: nbDigit = 4;
065: else if (digitValue >= 4)
066: nbDigit = 3;
067: else if (digitValue >= 2)
068: nbDigit = 2;
069: else
070: nbDigit = 1; //digitValue is not 0
071: computedValue = digitValue;
072: while (j < length) {
073: if ((digitValue = ScannerHelper.digit(source[j++],
074: radix)) < 0) {
075: constant = FORMAT_ERROR;
076: return;
077: }
078: if ((nbDigit += shift) > 64)
079: return /*constant stays null*/;
080: computedValue = (computedValue << shift) | digitValue;
081: }
082: } else {
083: //-----------case radix=10-----------------
084: long previous = 0;
085: computedValue = 0;
086: final long limit = Long.MAX_VALUE / 10; // needed to check prior to the multiplication
087: for (int i = 0; i < length; i++) {
088: int digitValue;
089: if ((digitValue = ScannerHelper.digit(source[i], 10)) < 0)
090: return /*constant stays null*/;
091: previous = computedValue;
092: if (computedValue > limit)
093: return /*constant stays null*/;
094: computedValue *= 10;
095: if ((computedValue + digitValue) > Long.MAX_VALUE)
096: return /*constant stays null*/;
097: computedValue += digitValue;
098: if (previous > computedValue)
099: return /*constant stays null*/;
100: }
101: }
102: constant = LongConstant.fromValue(computedValue);
103: }
104:
105: /**
106: * Code generation for long literal
107: *
108: * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
109: * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
110: * @param valueRequired boolean
111: */
112: public void generateCode(BlockScope currentScope,
113: CodeStream codeStream, boolean valueRequired) {
114: int pc = codeStream.position;
115: if (valueRequired) {
116: codeStream.generateConstant(constant, implicitConversion);
117: }
118: codeStream.recordPositionsFrom(pc, this .sourceStart);
119: }
120:
121: public TypeBinding literalType(BlockScope scope) {
122: return TypeBinding.LONG;
123: }
124:
125: public final boolean mayRepresentMIN_VALUE() {
126: //a special autorized int literral is 9223372036854775808L
127: //which is ONE over the limit. This special case
128: //only is used in combinaison with - to denote
129: //the minimal value of int -9223372036854775808L
130:
131: return ((source.length == 20) && (source[0] == '9')
132: && (source[1] == '2') && (source[2] == '2')
133: && (source[3] == '3') && (source[4] == '3')
134: && (source[5] == '7') && (source[6] == '2')
135: && (source[7] == '0') && (source[8] == '3')
136: && (source[9] == '6') && (source[10] == '8')
137: && (source[11] == '5') && (source[12] == '4')
138: && (source[13] == '7') && (source[14] == '7')
139: && (source[15] == '5') && (source[16] == '8')
140: && (source[17] == '0') && (source[18] == '8') && (((this .bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) == 0));
141: }
142:
143: public TypeBinding resolveType(BlockScope scope) {
144: // the format may be incorrect while the scanner could detect
145: // such error only on painfull tests...easier and faster here
146:
147: TypeBinding tb = super .resolveType(scope);
148: if (constant == FORMAT_ERROR) {
149: constant = Constant.NotAConstant;
150: scope.problemReporter().constantOutOfFormat(this );
151: this .resolvedType = null;
152: return null;
153: }
154: return tb;
155: }
156:
157: public void traverse(ASTVisitor visitor, BlockScope scope) {
158: visitor.visit(this, scope);
159: visitor.endVisit(this, scope);
160: }
161: }
|