blob: f9acc0da87be31cd4f3aa516ce5e940d5a9cbe29 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.jsdt.internal.compiler.ast;
import org.eclipse.wst.jsdt.core.ast.IASTNode;
import org.eclipse.wst.jsdt.core.ast.ILongLiteral;
import org.eclipse.wst.jsdt.internal.compiler.ASTVisitor;
import org.eclipse.wst.jsdt.internal.compiler.impl.Constant;
import org.eclipse.wst.jsdt.internal.compiler.impl.DoubleConstant;
import org.eclipse.wst.jsdt.internal.compiler.impl.LongConstant;
import org.eclipse.wst.jsdt.internal.compiler.lookup.BlockScope;
import org.eclipse.wst.jsdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.wst.jsdt.internal.compiler.parser.ScannerHelper;
public class LongLiteral extends NumberLiteral implements ILongLiteral {
static final Constant FORMAT_ERROR = DoubleConstant.fromValue(1.0/0.0); // NaN;
public LongLiteral(char[] token, int s,int e) {
super(token, s,e);
}
public void computeConstant() {
//the overflow (when radix=10) is tested using the fact that
//the value should always grow during its computation
int length = source.length - 1; //minus one because the last char is 'l' or 'L'
long computedValue ;
if (source[0] == '0') {
if (length == 1) {
constant = LongConstant.fromValue(0L);
return;
}
final int shift,radix;
int j ;
if ( (source[1] == 'x') || (source[1] == 'X') ) {
shift = 4 ; j = 2; radix = 16;
} else {
shift = 3 ; j = 1; radix = 8;
}
int nbDigit = 0;
while (source[j]=='0') {
j++; //jump over redondant zero
if ( j == length) {
//watch for 0000000000000L
constant = LongConstant.fromValue(0L);
return ;
}
}
int digitValue ;
if ((digitValue = ScannerHelper.digit(source[j++],radix)) < 0 ) {
constant = FORMAT_ERROR; return ;
}
if (digitValue >= 8)
nbDigit = 4;
else if (digitValue >= 4)
nbDigit = 3;
else if (digitValue >= 2)
nbDigit = 2;
else
nbDigit = 1; //digitValue is not 0
computedValue = digitValue ;
while (j<length) {
if ((digitValue = ScannerHelper.digit(source[j++],radix)) < 0) {
constant = FORMAT_ERROR; return ;
}
if ((nbDigit += shift) > 64)
return /*constant stays null*/ ;
computedValue = (computedValue<<shift) | digitValue ;
}
} else {
//-----------case radix=10-----------------
long previous = 0;
computedValue = 0;
final long limit = Long.MAX_VALUE / 10; // needed to check prior to the multiplication
for (int i = 0 ; i < length; i++) {
int digitValue ;
if ((digitValue = ScannerHelper.digit(source[i], 10)) < 0 ) return /*constant stays null*/;
previous = computedValue;
if (computedValue > limit)
return /*constant stays null*/;
computedValue *= 10;
if ((computedValue + digitValue) > Long.MAX_VALUE)
return /*constant stays null*/;
computedValue += digitValue;
if (previous > computedValue)
return /*constant stays null*/;
}
}
constant = LongConstant.fromValue(computedValue);
}
public TypeBinding literalType(BlockScope scope) {
return TypeBinding.LONG;
}
public final boolean mayRepresentMIN_VALUE(){
//a special autorized int literral is 9223372036854775808L
//which is ONE over the limit. This special case
//only is used in combinaison with - to denote
//the minimal value of int -9223372036854775808L
return ((source.length == 20) &&
(source[0] == '9') &&
(source[1] == '2') &&
(source[2] == '2') &&
(source[3] == '3') &&
(source[4] == '3') &&
(source[5] == '7') &&
(source[6] == '2') &&
(source[7] == '0') &&
(source[8] == '3') &&
(source[9] == '6') &&
(source[10] == '8') &&
(source[11] == '5') &&
(source[12] == '4') &&
(source[13] == '7') &&
(source[14] == '7') &&
(source[15] == '5') &&
(source[16] == '8') &&
(source[17] == '0') &&
(source[18] == '8') &&
(((this.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) == 0));
}
public TypeBinding resolveType(BlockScope scope) {
// the format may be incorrect while the scanner could detect
// such error only on painfull tests...easier and faster here
TypeBinding tb = super.resolveType(scope);
if (constant == FORMAT_ERROR) {
constant = Constant.NotAConstant;
scope.problemReporter().constantOutOfFormat(this);
this.resolvedType = null;
return null;
}
return tb;
}
public void traverse(ASTVisitor visitor, BlockScope scope) {
visitor.visit(this, scope);
visitor.endVisit(this, scope);
}
public int getASTType() {
return IASTNode.LONG_LITERAL;
}
}