Fix metamethods for compare with string.

This commit is contained in:
Enyby
2019-11-11 02:29:20 +02:00
parent da0b06555a
commit 725cf89b6f

View File

@@ -31,28 +31,28 @@ import java.io.PrintStream;
import org.luaj.vm2.lib.MathLib; import org.luaj.vm2.lib.MathLib;
/** /**
* Subclass of {@link LuaValue} for representing lua strings. * Subclass of {@link LuaValue} for representing lua strings.
* <p> * <p>
* Because lua string values are more nearly sequences of bytes than * Because lua string values are more nearly sequences of bytes than
* sequences of characters or unicode code points, the {@link LuaString} * sequences of characters or unicode code points, the {@link LuaString}
* implementation holds the string value in an internal byte array. * implementation holds the string value in an internal byte array.
* <p> * <p>
* {@link LuaString} values are not considered mutable once constructed, * {@link LuaString} values are not considered mutable once constructed,
* so multiple {@link LuaString} values can chare a single byte array. * so multiple {@link LuaString} values can chare a single byte array.
* <p> * <p>
* Currently {@link LuaString}s are pooled via a centrally managed weak table. * Currently {@link LuaString}s are pooled via a centrally managed weak table.
* To ensure that as many string values as possible take advantage of this, * To ensure that as many string values as possible take advantage of this,
* Constructors are not exposed directly. As with number, booleans, and nil, * Constructors are not exposed directly. As with number, booleans, and nil,
* instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API. * instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API.
* <p> * <p>
* Because of this pooling, users of LuaString <em>must not directly alter the * Because of this pooling, users of LuaString <em>must not directly alter the
* bytes in a LuaString</em>, or undefined behavior will result. * bytes in a LuaString</em>, or undefined behavior will result.
* <p> * <p>
* When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed. * When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed.
* The functions * The functions
* {@link #lengthAsUtf8(char[])}, * {@link #lengthAsUtf8(char[])},
* {@link #encodeToUtf8(char[], int, byte[], int)}, and * {@link #encodeToUtf8(char[], int, byte[], int)}, and
* {@link #decodeAsUtf8(byte[], int, int)} * {@link #decodeAsUtf8(byte[], int, int)}
* are used to convert back and forth between UTF8 byte arrays and character arrays. * are used to convert back and forth between UTF8 byte arrays and character arrays.
* *
* @see LuaValue * @see LuaValue
@@ -63,15 +63,15 @@ public class LuaString extends LuaValue {
/** The singleton instance for string metatables that forwards to the string functions. /** The singleton instance for string metatables that forwards to the string functions.
* Typically, this is set to the string metatable as a side effect of loading the string * Typically, this is set to the string metatable as a side effect of loading the string
* library, and is read-write to provide flexible behavior by default. When used in a * library, and is read-write to provide flexible behavior by default. When used in a
* server environment where there may be roge scripts, this should be replaced with a * server environment where there may be roge scripts, this should be replaced with a
* read-only table since it is shared across all lua code in this Java VM. * read-only table since it is shared across all lua code in this Java VM.
*/ */
public static LuaValue s_metatable; public static LuaValue s_metatable;
/** The bytes for the string. These <em><b>must not be mutated directly</b></em> because /** The bytes for the string. These <em><b>must not be mutated directly</b></em> because
* the backing may be shared by multiple LuaStrings, and the hash code is * the backing may be shared by multiple LuaStrings, and the hash code is
* computed only at construction time. * computed only at construction time.
* It is exposed only for performance and legacy reasons. */ * It is exposed only for performance and legacy reasons. */
public final byte[] m_bytes; public final byte[] m_bytes;
@@ -84,29 +84,29 @@ public class LuaString extends LuaValue {
/** The hashcode for this string. Computed at construct time. */ /** The hashcode for this string. Computed at construct time. */
private final int m_hashcode; private final int m_hashcode;
/** Size of cache of recent short strings. This is the maximum number of LuaStrings that /** Size of cache of recent short strings. This is the maximum number of LuaStrings that
* will be retained in the cache of recent short strings. Exposed to package for testing. */ * will be retained in the cache of recent short strings. Exposed to package for testing. */
static final int RECENT_STRINGS_CACHE_SIZE = 128; static final int RECENT_STRINGS_CACHE_SIZE = 128;
/** Maximum length of a string to be considered for recent short strings caching. /** Maximum length of a string to be considered for recent short strings caching.
* This effectively limits the total memory that can be spent on the recent strings cache, * This effectively limits the total memory that can be spent on the recent strings cache,
* because no LuaString whose backing exceeds this length will be put into the cache. * because no LuaString whose backing exceeds this length will be put into the cache.
* Exposed to package for testing. */ * Exposed to package for testing. */
static final int RECENT_STRINGS_MAX_LENGTH = 32; static final int RECENT_STRINGS_MAX_LENGTH = 32;
/** Simple cache of recently created strings that are short. /** Simple cache of recently created strings that are short.
* This is simply a list of strings, indexed by their hash codes modulo the cache size * This is simply a list of strings, indexed by their hash codes modulo the cache size
* that have been recently constructed. If a string is being constructed frequently * that have been recently constructed. If a string is being constructed frequently
* from different contexts, it will generally show up as a cache hit and resolve * from different contexts, it will generally show up as a cache hit and resolve
* to the same value. */ * to the same value. */
private static final class RecentShortStrings { private static final class RecentShortStrings {
private static final LuaString recent_short_strings[] = private static final LuaString recent_short_strings[] =
new LuaString[RECENT_STRINGS_CACHE_SIZE]; new LuaString[RECENT_STRINGS_CACHE_SIZE];
} }
/** /**
* Get a {@link LuaString} instance whose bytes match * Get a {@link LuaString} instance whose bytes match
* the supplied Java String using the UTF8 encoding. * the supplied Java String using the UTF8 encoding.
* @param string Java String containing characters to encode as UTF8 * @param string Java String containing characters to encode as UTF8
* @return {@link LuaString} with UTF8 bytes corresponding to the supplied String * @return {@link LuaString} with UTF8 bytes corresponding to the supplied String
*/ */
@@ -120,7 +120,7 @@ public class LuaString extends LuaValue {
/** Construct a {@link LuaString} for a portion of a byte array. /** Construct a {@link LuaString} for a portion of a byte array.
* <p> * <p>
* The array is first be used as the backing for this object, so clients must not change contents. * The array is first be used as the backing for this object, so clients must not change contents.
* If the supplied value for 'len' is more than half the length of the container, the * If the supplied value for 'len' is more than half the length of the container, the
* supplied byte array will be used as the backing, otherwise the bytes will be copied to a * supplied byte array will be used as the backing, otherwise the bytes will be copied to a
* new byte array, and cache lookup may be performed. * new byte array, and cache lookup may be performed.
* <p> * <p>
@@ -172,11 +172,11 @@ public class LuaString extends LuaValue {
/** Construct a {@link LuaString} using the supplied characters as byte values. /** Construct a {@link LuaString} using the supplied characters as byte values.
* <p> * <p>
* Only the low-order 8-bits of each character are used, the remainder is ignored. * Only the low-order 8-bits of each character are used, the remainder is ignored.
* <p> * <p>
* This is most useful for constructing byte sequences that do not conform to UTF8. * This is most useful for constructing byte sequences that do not conform to UTF8.
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array. * @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
* @return {@link LuaString} wrapping a copy of the byte buffer * @return {@link LuaString} wrapping a copy of the byte buffer
*/ */
public static LuaString valueOf(char[] bytes) { public static LuaString valueOf(char[] bytes) {
return valueOf(bytes, 0, bytes.length); return valueOf(bytes, 0, bytes.length);
@@ -184,11 +184,11 @@ public class LuaString extends LuaValue {
/** Construct a {@link LuaString} using the supplied characters as byte values. /** Construct a {@link LuaString} using the supplied characters as byte values.
* <p> * <p>
* Only the low-order 8-bits of each character are used, the remainder is ignored. * Only the low-order 8-bits of each character are used, the remainder is ignored.
* <p> * <p>
* This is most useful for constructing byte sequences that do not conform to UTF8. * This is most useful for constructing byte sequences that do not conform to UTF8.
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array. * @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
* @return {@link LuaString} wrapping a copy of the byte buffer * @return {@link LuaString} wrapping a copy of the byte buffer
*/ */
public static LuaString valueOf(char[] bytes, int off, int len) { public static LuaString valueOf(char[] bytes, int off, int len) {
byte[] b = new byte[len]; byte[] b = new byte[len];
@@ -215,7 +215,7 @@ public class LuaString extends LuaValue {
* The LuaString returned will either be a new LuaString containing the byte array, * The LuaString returned will either be a new LuaString containing the byte array,
* or be an existing LuaString used already having the same value. * or be an existing LuaString used already having the same value.
* <p> * <p>
* The caller must not mutate the contents of the byte array after this call, as * The caller must not mutate the contents of the byte array after this call, as
* it may be used elsewhere due to recent short string caching. * it may be used elsewhere due to recent short string caching.
* @param bytes byte buffer * @param bytes byte buffer
* @return {@link LuaString} wrapping the byte buffer * @return {@link LuaString} wrapping the byte buffer
@@ -241,11 +241,11 @@ public class LuaString extends LuaValue {
} }
public boolean isstring() { public boolean isstring() {
return true; return true;
} }
public LuaValue getmetatable() { public LuaValue getmetatable() {
return s_metatable; return s_metatable;
} }
public int type() { public int type() {
@@ -289,20 +289,20 @@ public class LuaString extends LuaValue {
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); } public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); }
// relational operators, these only work with other strings // relational operators, these only work with other strings
public LuaValue lt( LuaValue rhs ) { return rhs.strcmp(this)>0? LuaValue.TRUE: FALSE; } public LuaValue lt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>0? LuaValue.TRUE: FALSE) : super.lt(rhs); }
public boolean lt_b( LuaValue rhs ) { return rhs.strcmp(this)>0; } public boolean lt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>0 : super.lt_b(rhs); }
public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue lteq( LuaValue rhs ) { return rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE; } public LuaValue lteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE) : super.lteq(rhs); }
public boolean lteq_b( LuaValue rhs ) { return rhs.strcmp(this)>=0; } public boolean lteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>=0 : super.lteq_b(rhs); }
public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue gt( LuaValue rhs ) { return rhs.strcmp(this)<0? LuaValue.TRUE: FALSE; } public LuaValue gt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<0? LuaValue.TRUE: FALSE) : super.gt(rhs); }
public boolean gt_b( LuaValue rhs ) { return rhs.strcmp(this)<0; } public boolean gt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<0 : super.gt_b(rhs); }
public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue gteq( LuaValue rhs ) { return rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE; } public LuaValue gteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE) : super.gteq(rhs); }
public boolean gteq_b( LuaValue rhs ) { return rhs.strcmp(this)<=0; } public boolean gteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<=0 : super.gteq_b(rhs); }
public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
@@ -310,14 +310,14 @@ public class LuaString extends LuaValue {
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); } public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
public Buffer concat(Buffer rhs) { return rhs.concatTo(this); } public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
public LuaValue concatTo(LuaNumber lhs) { return concatTo(lhs.strvalue()); } public LuaValue concatTo(LuaNumber lhs) { return concatTo(lhs.strvalue()); }
public LuaValue concatTo(LuaString lhs) { public LuaValue concatTo(LuaString lhs) {
byte[] b = new byte[lhs.m_length+this.m_length]; byte[] b = new byte[lhs.m_length+this.m_length];
System.arraycopy(lhs.m_bytes, lhs.m_offset, b, 0, lhs.m_length); System.arraycopy(lhs.m_bytes, lhs.m_offset, b, 0, lhs.m_length);
System.arraycopy(this.m_bytes, this.m_offset, b, lhs.m_length, this.m_length); System.arraycopy(this.m_bytes, this.m_offset, b, lhs.m_length, this.m_length);
return valueUsing(b, 0, b.length); return valueUsing(b, 0, b.length);
} }
// string comparison // string comparison
public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); } public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); }
public int strcmp(LuaString rhs) { public int strcmp(LuaString rhs) {
for ( int i=0, j=0; i<m_length && j<rhs.m_length; ++i, ++j ) { for ( int i=0, j=0; i<m_length && j<rhs.m_length; ++i, ++j ) {
@@ -329,9 +329,9 @@ public class LuaString extends LuaValue {
} }
/** Check for number in arithmetic, or throw aritherror */ /** Check for number in arithmetic, or throw aritherror */
private double checkarith() { private double checkarith() {
double d = scannumber(); double d = scannumber();
if ( Double.isNaN(d) ) if ( Double.isNaN(d) )
aritherror(); aritherror();
return d; return d;
} }
@@ -368,15 +368,15 @@ public class LuaString extends LuaValue {
public boolean isint() { public boolean isint() {
double d = scannumber(); double d = scannumber();
if ( Double.isNaN(d) ) if ( Double.isNaN(d) )
return false; return false;
int i = (int) d; int i = (int) d;
return i == d; return i == d;
} }
public boolean islong() { public boolean islong() {
double d = scannumber(); double d = scannumber();
if ( Double.isNaN(d) ) if ( Double.isNaN(d) )
return false; return false;
long l = (long) d; long l = (long) d;
return l == d; return l == d;
@@ -398,7 +398,7 @@ public class LuaString extends LuaValue {
return checkint(); return checkint();
} }
public LuaInteger optinteger(LuaInteger defval) { public LuaInteger optinteger(LuaInteger defval) {
return checkinteger(); return checkinteger();
} }
@@ -411,15 +411,15 @@ public class LuaString extends LuaValue {
} }
public LuaString optstring(LuaString defval) { public LuaString optstring(LuaString defval) {
return this; return this;
} }
public LuaValue tostring() { public LuaValue tostring() {
return this; return this;
} }
public String optjstring(String defval) { public String optjstring(String defval) {
return tojstring(); return tojstring();
} }
public LuaString strvalue() { public LuaString strvalue() {
@@ -429,7 +429,7 @@ public class LuaString extends LuaValue {
/** Take a substring using Java zero-based indexes for begin and end or range. /** Take a substring using Java zero-based indexes for begin and end or range.
* @param beginIndex The zero-based index of the first character to include. * @param beginIndex The zero-based index of the first character to include.
* @param endIndex The zero-based index of position after the last character. * @param endIndex The zero-based index of position after the last character.
* @return LuaString which is a substring whose first character is at offset * @return LuaString which is a substring whose first character is at offset
* beginIndex and extending for (endIndex - beginIndex ) characters. * beginIndex and extending for (endIndex - beginIndex ) characters.
*/ */
public LuaString substring( int beginIndex, int endIndex ) { public LuaString substring( int beginIndex, int endIndex ) {
@@ -476,7 +476,7 @@ public class LuaString extends LuaValue {
return val.raweq(this); return val.raweq(this);
} }
public boolean raweq( LuaString s ) { public boolean raweq( LuaString s ) {
if ( this == s ) if ( this == s )
return true; return true;
if ( s.m_length != m_length ) if ( s.m_length != m_length )
@@ -503,7 +503,7 @@ public class LuaString extends LuaValue {
public static boolean equals( byte[] a, int i, byte[] b, int j, int n ) { public static boolean equals( byte[] a, int i, byte[] b, int j, int n ) {
if ( a.length < i + n || b.length < j + n ) if ( a.length < i + n || b.length < j + n )
return false; return false;
while ( --n>=0 ) while ( --n>=0 )
if ( a[i++]!=b[j++] ) if ( a[i++]!=b[j++] )
return false; return false;
return true; return true;
@@ -535,8 +535,8 @@ public class LuaString extends LuaValue {
return luaByte( index ); return luaByte( index );
} }
public String checkjstring() { public String checkjstring() {
return tojstring(); return tojstring();
} }
public LuaString checkstring() { public LuaString checkstring() {
@@ -552,7 +552,7 @@ public class LuaString extends LuaValue {
} }
/** /**
* Copy the bytes of the string into the given byte array. * Copy the bytes of the string into the given byte array.
* @param strOffset offset from which to copy * @param strOffset offset from which to copy
* @param bytes destination byte array * @param bytes destination byte array
* @param arrayOffset offset in destination * @param arrayOffset offset in destination
@@ -626,12 +626,12 @@ public class LuaString extends LuaValue {
/** /**
* Convert to Java String interpreting as utf8 characters. * Convert to Java String interpreting as utf8 characters.
* *
* @param bytes byte array in UTF8 encoding to convert * @param bytes byte array in UTF8 encoding to convert
* @param offset starting index in byte array * @param offset starting index in byte array
* @param length number of bytes to convert * @param length number of bytes to convert
* @return Java String corresponding to the value of bytes interpreted using UTF8 * @return Java String corresponding to the value of bytes interpreted using UTF8
* @see #lengthAsUtf8(char[]) * @see #lengthAsUtf8(char[])
* @see #encodeToUtf8(char[], int, byte[], int) * @see #encodeToUtf8(char[], int, byte[], int)
* @see #isValidUtf8() * @see #isValidUtf8()
@@ -662,7 +662,7 @@ public class LuaString extends LuaValue {
* @see #decodeAsUtf8(byte[], int, int) * @see #decodeAsUtf8(byte[], int, int)
* @see #isValidUtf8() * @see #isValidUtf8()
*/ */
public static int lengthAsUtf8(char[] chars) { public static int lengthAsUtf8(char[] chars) {
int i,b; int i,b;
char c; char c;
for ( i=b=chars.length; --i>=0; ) for ( i=b=chars.length; --i>=0; )
@@ -673,7 +673,7 @@ public class LuaString extends LuaValue {
/** /**
* Encode the given Java string as UTF-8 bytes, writing the result to bytes * Encode the given Java string as UTF-8 bytes, writing the result to bytes
* starting at offset. * starting at offset.
* <p> * <p>
* The string should be measured first with lengthAsUtf8 * The string should be measured first with lengthAsUtf8
* to make sure the given byte array is large enough. * to make sure the given byte array is large enough.
@@ -694,11 +694,11 @@ public class LuaString extends LuaValue {
bytes[j++] = (byte) c; bytes[j++] = (byte) c;
} else if ( c < 0x800 ) { } else if ( c < 0x800 ) {
bytes[j++] = (byte) (0xC0 | ((c>>6) & 0x1f)); bytes[j++] = (byte) (0xC0 | ((c>>6) & 0x1f));
bytes[j++] = (byte) (0x80 | ( c & 0x3f)); bytes[j++] = (byte) (0x80 | ( c & 0x3f));
} else { } else {
bytes[j++] = (byte) (0xE0 | ((c>>12) & 0x0f)); bytes[j++] = (byte) (0xE0 | ((c>>12) & 0x0f));
bytes[j++] = (byte) (0x80 | ((c>>6) & 0x3f)); bytes[j++] = (byte) (0x80 | ((c>>6) & 0x3f));
bytes[j++] = (byte) (0x80 | ( c & 0x3f)); bytes[j++] = (byte) (0x80 | ( c & 0x3f));
} }
} }
return j - off; return j - off;
@@ -714,12 +714,12 @@ public class LuaString extends LuaValue {
for (int i=m_offset,j=m_offset+m_length; i<j;) { for (int i=m_offset,j=m_offset+m_length; i<j;) {
int c = m_bytes[i++]; int c = m_bytes[i++];
if ( c >= 0 ) continue; if ( c >= 0 ) continue;
if ( ((c & 0xE0) == 0xC0) if ( ((c & 0xE0) == 0xC0)
&& i<j && i<j
&& (m_bytes[i++] & 0xC0) == 0x80) continue; && (m_bytes[i++] & 0xC0) == 0x80) continue;
if ( ((c & 0xF0) == 0xE0) if ( ((c & 0xF0) == 0xE0)
&& i+1<j && i+1<j
&& (m_bytes[i++] & 0xC0) == 0x80 && (m_bytes[i++] & 0xC0) == 0x80
&& (m_bytes[i++] & 0xC0) == 0x80) continue; && (m_bytes[i++] & 0xC0) == 0x80) continue;
return false; return false;
} }
@@ -728,32 +728,32 @@ public class LuaString extends LuaValue {
// --------------------- number conversion ----------------------- // --------------------- number conversion -----------------------
/** /**
* convert to a number using baee 10 or base 16 if it starts with '0x', * convert to a number using baee 10 or base 16 if it starts with '0x',
* or NIL if it can't be converted * or NIL if it can't be converted
* @return IntValue, DoubleValue, or NIL depending on the content of the string. * @return IntValue, DoubleValue, or NIL depending on the content of the string.
* @see LuaValue#tonumber() * @see LuaValue#tonumber()
*/ */
public LuaValue tonumber() { public LuaValue tonumber() {
double d = scannumber(); double d = scannumber();
return Double.isNaN(d)? NIL: valueOf(d); return Double.isNaN(d)? NIL: valueOf(d);
} }
/** /**
* convert to a number using a supplied base, or NIL if it can't be converted * convert to a number using a supplied base, or NIL if it can't be converted
* @param base the base to use, such as 10 * @param base the base to use, such as 10
* @return IntValue, DoubleValue, or NIL depending on the content of the string. * @return IntValue, DoubleValue, or NIL depending on the content of the string.
* @see LuaValue#tonumber() * @see LuaValue#tonumber()
*/ */
public LuaValue tonumber( int base ) { public LuaValue tonumber( int base ) {
double d = scannumber( base ); double d = scannumber( base );
return Double.isNaN(d)? NIL: valueOf(d); return Double.isNaN(d)? NIL: valueOf(d);
} }
/** /**
* Convert to a number in base 10, or base 16 if the string starts with '0x', * Convert to a number in base 10, or base 16 if the string starts with '0x',
* or return Double.NaN if it cannot be converted to a number. * or return Double.NaN if it cannot be converted to a number.
* @return double value if conversion is valid, or Double.NaN if not * @return double value if conversion is valid, or Double.NaN if not
*/ */
public double scannumber() { public double scannumber() {
int i=m_offset,j=m_offset+m_length; int i=m_offset,j=m_offset+m_length;
@@ -767,10 +767,10 @@ public class LuaString extends LuaValue {
return Double.isNaN(l)? scandouble(i,j): l; return Double.isNaN(l)? scandouble(i,j): l;
} }
/** /**
* Convert to a number in a base, or return Double.NaN if not a number. * Convert to a number in a base, or return Double.NaN if not a number.
* @param base the base to use between 2 and 36 * @param base the base to use between 2 and 36
* @return double value if conversion is valid, or Double.NaN if not * @return double value if conversion is valid, or Double.NaN if not
*/ */
public double scannumber(int base) { public double scannumber(int base) {
if ( base < 2 || base > 36 ) if ( base < 2 || base > 36 )
@@ -788,7 +788,7 @@ public class LuaString extends LuaValue {
* @param base the base to use, such as 10 * @param base the base to use, such as 10
* @param start the index to start searching from * @param start the index to start searching from
* @param end the first index beyond the search range * @param end the first index beyond the search range
* @return double value if conversion is valid, * @return double value if conversion is valid,
* or Double.NaN if not * or Double.NaN if not
*/ */
private double scanlong( int base, int start, int end ) { private double scanlong( int base, int start, int end ) {
@@ -798,7 +798,7 @@ public class LuaString extends LuaValue {
int digit = m_bytes[i] - (base<=10||(m_bytes[i]>='0'&&m_bytes[i]<='9')? '0': int digit = m_bytes[i] - (base<=10||(m_bytes[i]>='0'&&m_bytes[i]<='9')? '0':
m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10)); m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
if ( digit < 0 || digit >= base ) if ( digit < 0 || digit >= base )
return Double.NaN; return Double.NaN;
x = x * base + digit; x = x * base + digit;
if ( x < 0 ) if ( x < 0 )
return Double.NaN; // overflow return Double.NaN; // overflow
@@ -810,7 +810,7 @@ public class LuaString extends LuaValue {
* Scan and convert a double value, or return Double.NaN if not a double. * Scan and convert a double value, or return Double.NaN if not a double.
* @param start the index to start searching from * @param start the index to start searching from
* @param end the first index beyond the search range * @param end the first index beyond the search range
* @return double value if conversion is valid, * @return double value if conversion is valid,
* or Double.NaN if not * or Double.NaN if not
*/ */
private double scandouble(int start, int end) { private double scandouble(int start, int end) {
@@ -833,7 +833,7 @@ public class LuaString extends LuaValue {
c[i-start] = (char) m_bytes[i]; c[i-start] = (char) m_bytes[i];
try { try {
return Double.parseDouble(new String(c)); return Double.parseDouble(new String(c));
} catch ( Exception e ) { } catch ( Exception e ) {
return Double.NaN; return Double.NaN;
} }
} }