/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.parser;
import static com.github.anba.es6draft.parser.Characters.digit;
import static com.github.anba.es6draft.parser.Characters.hexDigit;
import org.mozilla.javascript.StringToNumber;
/**
* Utility class for parsing number literals
*/
public final class NumberParser {
private NumberParser() {
}
/**
* Parse a decimal integer literal.
*
* @param cbuf
* the characters to parse
* @param length
* the length of the characters
* @return the parsed integer
*/
static double parseInteger(char[] cbuf, int length) {
if (length < 10) {
// integer [0, 9999_99999]
int num = 0;
for (int i = 0; i < length; ++i) {
num = (num * 10) + digit(cbuf[i]);
}
return num;
} else if (length < 19) {
// integer [0, 999_99999_99999_99999]
long num = 0;
for (int i = 0; i < length; ++i) {
num = (num * 10) + digit(cbuf[i]);
}
return num;
} else {
// integer ]999_99999_99999_99999, ...]
return parseDecimal(cbuf, length);
}
}
/**
* Parse a decimal integer literal.
*
* @param cbuf
* the characters to parse
* @param length
* the length of the characters
* @return the parsed integer
*/
static double parseSignedInteger(char[] cbuf, int length) {
final char sign = cbuf[0];
final int start = (sign == '-' || sign == '+') ? 1 : 0;
if (length - start < 10) {
// integer [0, 9999_99999]
int num = 0;
for (int i = start; i < length; ++i) {
num = (num * 10) + digit(cbuf[i]);
}
return (sign == '-') ? -num : num;
} else if (length - start < 19) {
// integer [0, 999_99999_99999_99999]
long num = 0;
for (int i = start; i < length; ++i) {
num = (num * 10) + digit(cbuf[i]);
}
return (sign == '-') ? -num : num;
} else {
// integer ]999_99999_99999_99999, ...]
return parseDecimal(cbuf, length);
}
}
/**
* Parse a decimal integer literal.
*
* @param s
* the string to parse
* @return the parsed integer
*/
public static double parseInteger(String s) {
final char sign = s.charAt(0);
final int start = (sign == '-' || sign == '+') ? 1 : 0;
final int length = s.length();
if (length - start < 10) {
// integer [0, 9999_99999]
int num = 0;
for (int i = start; i < length; ++i) {
num = (num * 10) + digit(s.charAt(i));
}
return (sign == '-') ? -(double) num : num;
} else if (length - start < 19) {
// integer [0, 999_99999_99999_99999]
long num = 0;
for (int i = start; i < length; ++i) {
num = (num * 10) + digit(s.charAt(i));
}
return (sign == '-') ? -(double) num : num;
} else {
// integer ]999_99999_99999_99999, ...]
return Double.parseDouble(s);
}
}
/**
* Parse a decimal integer literal.
*
* @param s
* the string to parse
* @param end
* the end index
* @return the parsed integer
*/
public static double parseInteger(String s, final int end) {
final char sign = s.charAt(0);
final int start = (sign == '-' || sign == '+') ? 1 : 0;
final int length = s.length();
if (end <= start || end >= length) {
throw new IndexOutOfBoundsException();
}
if (end - start < 10) {
// integer [0, 9999_99999]
int num = 0;
for (int i = start; i < end; ++i) {
num = (num * 10) + digit(s.charAt(i));
}
return (sign == '-') ? -(double) num : num;
} else if (end - start < 19) {
// integer [0, 999_99999_99999_99999]
long num = 0;
for (int i = start; i < end; ++i) {
num = (num * 10) + digit(s.charAt(i));
}
return (sign == '-') ? -(double) num : num;
} else {
// integer ]999_99999_99999_99999, ...]
return Double.parseDouble(s.substring(0, end));
}
}
/**
* Parse a decimal number literal.
*
* @param cbuf
* the characters to parse
* @param length
* the length of the characters
* @return the parsed decimal
*/
static double parseDecimal(char[] cbuf, int length) {
String string = new String(cbuf, 0, length);
return Double.parseDouble(string);
}
/**
* Parse a decimal number literal.
*
* @param s
* the string to parse
* @return the parsed decimal
*/
public static double parseDecimal(String s) {
return Double.parseDouble(s);
}
/**
* Parse a decimal number literal.
*
* @param s
* the string to parse
* @param end
* the end index
* @return the parsed decimal
*/
public static double parseDecimal(String s, int end) {
return Double.parseDouble(s.substring(0, end));
}
/**
* Parse a binary integer literal.
*
* @param cbuf
* the characters to parse
* @param length
* the length of the characters
* @return the binary integer
*/
static double parseBinary(char[] cbuf, int length) {
if (length < 32) {
// integer [0, 7FFFFFFF]
int num = 0;
for (int i = 0; i < length; ++i) {
num = (num << 1) | digit(cbuf[i]);
}
return num;
} else if (length < 64) {
// integer [0, 7FFFFFFFFFFFFFFF]
long num = 0;
for (int i = 0; i < length; ++i) {
num = (num << 1) | digit(cbuf[i]);
}
return num;
} else {
// integer ]7FFFFFFFFFFFFFFF, ...]
String string = new String(cbuf, 0, length);
return StringToNumber.stringToNumber(string, 0, 2);
}
}
/**
* Parse a binary integer literal.
*
* @param s
* the string to parse
* @return the binary integer
*/
public static double parseBinary(String s) {
final int start = 2; // "0b" prefix
final int length = s.length();
if (length - start < 32) {
// integer [0, 7FFFFFFF]
int num = 0;
for (int i = start; i < length; ++i) {
num = (num << 1) | digit(s.charAt(i));
}
return num;
} else if (length - start < 64) {
// integer [0, 7FFFFFFFFFFFFFFF]
long num = 0;
for (int i = start; i < length; ++i) {
num = (num << 1) | digit(s.charAt(i));
}
return num;
} else {
// integer ]7FFFFFFFFFFFFFFF, ...]
return StringToNumber.stringToNumber(s, start, 2);
}
}
/**
* Parse an octal integer literal.
*
* @param cbuf
* the characters to parse
* @param length
* the length of the characters
* @return the octal integer
*/
static double parseOctal(char[] cbuf, int length) {
if (length <= 10) {
// integer [0, 07777777777]
int num = 0;
for (int i = 0; i < length; ++i) {
num = (num << 3) | digit(cbuf[i]);
}
return num;
} else if (length <= 21) {
// integer [0, 0777777777777777777777]
long num = 0;
for (int i = 0; i < length; ++i) {
num = (num << 3) | digit(cbuf[i]);
}
return num;
} else {
// integer ]0777777777777777777777, ...]
String string = new String(cbuf, 0, length);
return StringToNumber.stringToNumber(string, 0, 8);
}
}
/**
* Parse an octal integer literal.
*
* @param s
* the string to parse
* @return the octal integer
*/
public static double parseOctal(String s) {
final int start = 2; // "0o" prefix
final int length = s.length();
if (length - start <= 10) {
// integer [0, 07777777777]
int num = 0;
for (int i = start; i < length; ++i) {
num = (num << 3) | digit(s.charAt(i));
}
return num;
} else if (length - start <= 21) {
// integer [0, 0777777777777777777777]
long num = 0;
for (int i = start; i < length; ++i) {
num = (num << 3) | digit(s.charAt(i));
}
return num;
} else {
// integer ]0777777777777777777777, ...]
return StringToNumber.stringToNumber(s, start, 8);
}
}
/**
* Parse a hexadecimal integer literal.
*
* @param cbuf
* the characters to parse
* @param length
* the length of the characters
* @return the hexadecimal integer
*/
static double parseHex(char[] cbuf, int length) {
if (length < 8) {
// integer [0, FFFFFFF]
int num = 0;
for (int i = 0; i < length; ++i) {
num = (num << 4) | hexDigit(cbuf[i]);
}
return num;
} else if (length < 16) {
// integer [0, FFFFFFFFFFFFFFF]
long num = 0;
for (int i = 0; i < length; ++i) {
num = (num << 4) | hexDigit(cbuf[i]);
}
return num;
} else {
// integer ]FFFFFFFFFFFFFFF, ...]
String string = new String(cbuf, 0, length);
return StringToNumber.stringToNumber(string, 0, 16);
}
}
/**
* Parse a hexadecimal integer literal.
*
* @param s
* the characters to parse
* @return the hexadecimal integer
*/
public static double parseHex(String s) {
final int start = 2; // "0x" prefix
final int length = s.length();
if (length - start < 8) {
// integer [0, FFFFFFF]
int num = 0;
for (int i = start; i < length; ++i) {
num = (num << 4) | hexDigit(s.charAt(i));
}
return num;
} else if (length - start < 16) {
// integer [0, FFFFFFFFFFFFFFF]
long num = 0;
for (int i = start; i < length; ++i) {
num = (num << 4) | hexDigit(s.charAt(i));
}
return num;
} else {
// integer ]FFFFFFFFFFFFFFF, ...]
return StringToNumber.stringToNumber(s, start, 16);
}
}
}