Support data parsing operations (#380)
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
Q: How do I run my program?
|
||||
|
||||
A: Define top level function `fun main(args: Array<String>)`, please ensure it's not
|
||||
in a package.
|
||||
+3
-1
@@ -23,7 +23,9 @@ the following platforms:
|
||||
|
||||
* Mac OS X 10.10 and later (x86-64)
|
||||
* x86-64 Ubuntu Linux (14.04, 16.04 and later), other Linux flavours may work as well
|
||||
* Apple iOS (arm64 and simulator on x86-64)
|
||||
* Apple iOS (arm64 and simulator on x86-64), cross-compiled on MacOS X host
|
||||
* Raspberry Pi, cross-compiled on Linux host
|
||||
|
||||
|
||||
Adding support for other target platforms shalln't be too hard, if LLVM support
|
||||
is available.
|
||||
|
||||
@@ -1034,6 +1034,19 @@ task string0(type: RunKonanTest) {
|
||||
source = "runtime/text/string0.kt"
|
||||
}
|
||||
|
||||
task parse0(type: RunKonanTest) {
|
||||
goldValue = "false\n" +
|
||||
"true\n" +
|
||||
"-1\n" +
|
||||
"-86\n" +
|
||||
"30\n" +
|
||||
"4294967295\n" +
|
||||
"bad format\n" +
|
||||
"0.5\n" +
|
||||
"2.39\n"
|
||||
source = "runtime/text/parse0.kt"
|
||||
}
|
||||
|
||||
task catch1(type: RunKonanTest) {
|
||||
goldValue = "Before\nCaught Throwable\nDone\n"
|
||||
source = "runtime/exceptions/catch1.kt"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
fun main(args: Array<String>) {
|
||||
println("false".toBoolean())
|
||||
println("true".toBoolean())
|
||||
println("-1".toByte())
|
||||
println("aa".toByte(16))
|
||||
println("11110".toInt(2))
|
||||
println("ffffffff".toLong(16))
|
||||
try {
|
||||
val x = "ffffffff".toLong(10)
|
||||
} catch (ne: NumberFormatException) {
|
||||
println("bad format")
|
||||
}
|
||||
println("0.5".toFloat())
|
||||
println("2.39".toDouble())
|
||||
}
|
||||
@@ -22,8 +22,10 @@ void ThrowNullPointerException();
|
||||
void ThrowArrayIndexOutOfBoundsException();
|
||||
// Throws class cast exception.
|
||||
void ThrowClassCastException();
|
||||
// Throws arithmetic exception
|
||||
// Throws arithmetic exception.
|
||||
void ThrowArithmeticException();
|
||||
// Throws number format exception.
|
||||
void ThrowNumberFormatException();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
@@ -47,6 +47,58 @@ OBJ_GETTER(utf8ToUtf16, Raw<const char> rawString) {
|
||||
RETURN_OBJ(result->obj());
|
||||
}
|
||||
|
||||
template <typename T> T parseInt(KString value, KInt radix) {
|
||||
Raw<const KChar> utf16(
|
||||
CharArrayAddressOfElementAt(value, 0), value->count_);
|
||||
std::string utf8;
|
||||
utf8::utf16to8(utf16.begin(), utf16.end(), back_inserter(utf8));
|
||||
char* end = nullptr;
|
||||
long result = strtol(utf8.c_str(), &end, radix);
|
||||
if (end != utf8.c_str() + utf8.size()) {
|
||||
ThrowNumberFormatException();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
KLong parseLong(KString value, KInt radix) {
|
||||
Raw<const KChar> utf16(
|
||||
CharArrayAddressOfElementAt(value, 0), value->count_);
|
||||
std::string utf8;
|
||||
utf8::utf16to8(utf16.begin(), utf16.end(), back_inserter(utf8));
|
||||
char* end = nullptr;
|
||||
KLong result = strtoll(utf8.c_str(), &end, radix);
|
||||
if (end != utf8.c_str() + utf8.size()) {
|
||||
ThrowNumberFormatException();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
KFloat parseFloat(KString value) {
|
||||
Raw<const KChar> utf16(
|
||||
CharArrayAddressOfElementAt(value, 0), value->count_);
|
||||
std::string utf8;
|
||||
utf8::utf16to8(utf16.begin(), utf16.end(), back_inserter(utf8));
|
||||
char* end = nullptr;
|
||||
KFloat result = strtof(utf8.c_str(), &end);
|
||||
if (end != utf8.c_str() + utf8.size()) {
|
||||
ThrowNumberFormatException();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
KDouble parseDouble(KString value) {
|
||||
Raw<const KChar> utf16(
|
||||
CharArrayAddressOfElementAt(value, 0), value->count_);
|
||||
std::string utf8;
|
||||
utf8::utf16to8(utf16.begin(), utf16.end(), back_inserter(utf8));
|
||||
char* end = nullptr;
|
||||
KDouble result = strtod(utf8.c_str(), &end);
|
||||
if (end != utf8.c_str() + utf8.size()) {
|
||||
ThrowNumberFormatException();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
@@ -301,6 +353,22 @@ KChar Kotlin_Char_toUpperCase(KChar ch) {
|
||||
return towupper(ch);
|
||||
}
|
||||
|
||||
KInt Kotlin_Char_digitOf(KChar ch, KInt radix) {
|
||||
// TODO: make smarter and support full unicode.
|
||||
const static KInt digits[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
-1, -1, -1, -1, -1, -1, -1,
|
||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, 33, 34, 35,
|
||||
-1, -1, -1, -1, -1, -1,
|
||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, 33, 34, 35 };
|
||||
if (ch < 0x30 /* 0 */ || ch > 0x7a /* z */) return -1;
|
||||
return digits[ch - 0x30];
|
||||
}
|
||||
|
||||
KInt Kotlin_String_indexOfChar(KString thiz, KChar ch, KInt fromIndex) {
|
||||
if (fromIndex < 0 || fromIndex > thiz->count_) {
|
||||
return false;
|
||||
@@ -430,4 +498,28 @@ OBJ_GETTER0(Kotlin_io_Console_readLine) {
|
||||
RETURN_RESULT_OF(CreateStringFromCString, data);
|
||||
}
|
||||
|
||||
KByte Kotlin_String_parseByte(KString value, KInt radix) {
|
||||
return parseInt<KByte>(value, radix);
|
||||
}
|
||||
|
||||
KShort Kotlin_String_parseShort(KString value, KInt radix) {
|
||||
return parseInt<KShort>(value, radix);
|
||||
}
|
||||
|
||||
KInt Kotlin_String_parseInt(KString value, KInt radix) {
|
||||
return parseInt<KInt>(value, radix);
|
||||
}
|
||||
|
||||
KLong Kotlin_String_parseLong(KString value, KInt radix) {
|
||||
return parseLong(value, radix);
|
||||
}
|
||||
|
||||
KFloat Kotlin_String_parseFloat(KString value) {
|
||||
return parseFloat(value);
|
||||
}
|
||||
|
||||
KDouble Kotlin_String_parseDouble(KString value) {
|
||||
return parseDouble(value);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -43,12 +43,50 @@ OBJ_GETTER(Kotlin_Int_toString, KInt value) {
|
||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_Int_toStringRadix, KInt value, KInt radix) {
|
||||
// TODO: maye not fit for smaller radices.
|
||||
char cstring[32];
|
||||
switch (radix) {
|
||||
case 8:
|
||||
snprintf(cstring, sizeof(cstring), "%o", value);
|
||||
break;
|
||||
case 10:
|
||||
snprintf(cstring, sizeof(cstring), "%d", value);
|
||||
break;
|
||||
case 16:
|
||||
snprintf(cstring, sizeof(cstring), "%x", value);
|
||||
break;
|
||||
default:
|
||||
RuntimeAssert(false, "Unsupported radix");
|
||||
}
|
||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_Long_toString, KLong value) {
|
||||
char cstring[32];
|
||||
snprintf(cstring, sizeof(cstring), "%lld", static_cast<long long>(value));
|
||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_Long_toStringRadix, KLong value, KInt radix) {
|
||||
// TODO: may not fit for smaller radices.
|
||||
char cstring[64];
|
||||
switch (radix) {
|
||||
case 8:
|
||||
snprintf(cstring, sizeof(cstring), "%llo", value);
|
||||
break;
|
||||
case 10:
|
||||
snprintf(cstring, sizeof(cstring), "%lld", value);
|
||||
break;
|
||||
case 16:
|
||||
snprintf(cstring, sizeof(cstring), "%llx", value);
|
||||
break;
|
||||
default:
|
||||
RuntimeAssert(false, "Unsupported radix");
|
||||
}
|
||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||
}
|
||||
|
||||
// TODO: use David Gay's dtoa() here instead. It's *very* big and ugly.
|
||||
OBJ_GETTER(Kotlin_Float_toString, KFloat value) {
|
||||
char cstring[32];
|
||||
|
||||
@@ -20,6 +20,11 @@ internal fun ThrowArithmeticException() : Nothing {
|
||||
throw ArithmeticException()
|
||||
}
|
||||
|
||||
@ExportForCppRuntime
|
||||
internal fun ThrowNumberFormatException() : Nothing {
|
||||
throw NumberFormatException()
|
||||
}
|
||||
|
||||
fun ThrowNoWhenBranchMatchedException(): Nothing {
|
||||
throw NoWhenBranchMatchedException()
|
||||
}
|
||||
|
||||
@@ -89,6 +89,16 @@ public final class Char : Comparable<Char> {
|
||||
* The maximum value of a Unicode surrogate code unit.
|
||||
*/
|
||||
public const val MAX_SURROGATE: Char = MAX_LOW_SURROGATE
|
||||
|
||||
/**
|
||||
* The minimum radix available for conversion to and from strings.
|
||||
*/
|
||||
public const val MIN_RADIX: Int = 2
|
||||
|
||||
/**
|
||||
* The minimum radix available for conversion to and from strings.
|
||||
*/
|
||||
public const val MAX_RADIX: Int = 36
|
||||
}
|
||||
|
||||
// Konan-specific.
|
||||
|
||||
@@ -192,4 +192,12 @@ public open class OutOfMemoryError : Error {
|
||||
|
||||
constructor(s: String) : super(s) {
|
||||
}
|
||||
}
|
||||
|
||||
public open class NumberFormatException : IllegalArgumentException {
|
||||
|
||||
constructor() : super() {
|
||||
}
|
||||
|
||||
constructor(s: String) : super(s) {}
|
||||
}
|
||||
@@ -78,4 +78,18 @@ external public fun Char.isHighSurrogate(): Boolean
|
||||
* Returns `true` if this character is a Unicode low-surrogate code unit (also known as trailing-surrogate code unit).
|
||||
*/
|
||||
@SymbolName("Kotlin_Char_isLowSurrogate")
|
||||
external public fun Char.isLowSurrogate(): Boolean
|
||||
external public fun Char.isLowSurrogate(): Boolean
|
||||
|
||||
@SymbolName("Kotlin_Char_digitOf")
|
||||
external internal fun digitOf(char: Char, radix: Int): Int
|
||||
|
||||
/**
|
||||
* Checks whether the given [radix] is valid radix for string to number and number to string conversion.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun checkRadix(radix: Int): Int {
|
||||
if(radix !in Char.MIN_RADIX..Char.MAX_RADIX) {
|
||||
throw IllegalArgumentException("radix $radix was not in valid range ${Char.MIN_RADIX..Char.MAX_RADIX}")
|
||||
}
|
||||
return radix
|
||||
}
|
||||
|
||||
@@ -0,0 +1,320 @@
|
||||
package kotlin.text
|
||||
|
||||
/**
|
||||
* Returns a string representation of this [Byte] value in the specified [radix].
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun Byte.toString(radix: Int): String = this.toInt().toString(checkRadix(radix))
|
||||
|
||||
/**
|
||||
* Returns a string representation of this [Short] value in the specified [radix].
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun Short.toString(radix: Int): String = this.toInt().toString(checkRadix(radix))
|
||||
|
||||
@SymbolName("Kotlin_Int_toStringRadix")
|
||||
external private fun intToString(value: Int, radix: Int): String
|
||||
|
||||
/**
|
||||
* Returns a string representation of this [Int] value in the specified [radix].
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun Int.toString(radix: Int): String = intToString(this, checkRadix(radix))
|
||||
|
||||
@SymbolName("Kotlin_Long_toStringRadix")
|
||||
external private fun longToString(value: Long, radix: Int): String
|
||||
|
||||
/**
|
||||
* Returns a string representation of this [Long] value in the specified [radix].
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun Long.toString(radix: Int): String = longToString(this, checkRadix(radix))
|
||||
|
||||
/**
|
||||
* Returns `true` if the contents of this string is equal to the word "true", ignoring case, and `false` otherwise.
|
||||
*/
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun String.toBoolean(): Boolean = this == "true"
|
||||
|
||||
@SymbolName("Kotlin_String_parseByte")
|
||||
external private fun parseByte(value: String, radix: Int): Byte
|
||||
|
||||
/**
|
||||
* Parses the string as a signed [Byte] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun String.toByte(): Byte = parseByte(this, 10)
|
||||
|
||||
/**
|
||||
* Parses the string as a signed [Byte] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun String.toByte(radix: Int): Byte = parseByte(this, checkRadix(radix))
|
||||
|
||||
@SymbolName("Kotlin_String_parseShort")
|
||||
external private fun parseShort(value: String, radix: Int): Short
|
||||
|
||||
/**
|
||||
* Parses the string as a [Short] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun String.toShort(): Short = parseShort(this, 10)
|
||||
|
||||
/**
|
||||
* Parses the string as a [Short] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun String.toShort(radix: Int): Short = parseShort(this, checkRadix(radix))
|
||||
|
||||
@SymbolName("Kotlin_String_parseInt")
|
||||
external private fun parseInt(value: String, radix: Int): Int
|
||||
|
||||
/**
|
||||
* Parses the string as an [Int] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun String.toInt(): Int = parseInt(this, 10)
|
||||
|
||||
/**
|
||||
* Parses the string as an [Int] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun String.toInt(radix: Int): Int = parseInt(this, checkRadix(radix))
|
||||
|
||||
|
||||
@SymbolName("Kotlin_String_parseLong")
|
||||
external private fun parseLong(value: String, radix: Int): Long
|
||||
|
||||
/**
|
||||
* Parses the string as a [Long] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun String.toLong(): Long = parseLong(this, 10)
|
||||
|
||||
/**
|
||||
* Parses the string as a [Long] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun String.toLong(radix: Int): Long = parseLong(this, checkRadix(radix))
|
||||
|
||||
@SymbolName("Kotlin_String_parseFloat")
|
||||
external private fun parseFloat(value: String): Float
|
||||
|
||||
/**
|
||||
* Parses the string as a [Float] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun String.toFloat(): Float = parseFloat(this)
|
||||
|
||||
|
||||
@SymbolName("Kotlin_String_parseDouble")
|
||||
external private fun parseDouble(value: String): Double
|
||||
|
||||
/**
|
||||
* Parses the string as a [Double] number and returns the result.
|
||||
* @throws NumberFormatException if the string is not a valid representation of a number.
|
||||
*/
|
||||
@kotlin.internal.InlineOnly
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
public inline fun String.toDouble(): Double = parseDouble(this)
|
||||
|
||||
|
||||
/**
|
||||
* Parses the string as a signed [Byte] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun String.toByteOrNull(): Byte? = toByteOrNull(radix = 10)
|
||||
|
||||
/**
|
||||
* Parses the string as a signed [Byte] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun String.toByteOrNull(radix: Int): Byte? {
|
||||
val int = this.toIntOrNull(radix) ?: return null
|
||||
if (int < Byte.MIN_VALUE || int > Byte.MAX_VALUE) return null
|
||||
return int.toByte()
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string as a [Short] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun String.toShortOrNull(): Short? = toShortOrNull(radix = 10)
|
||||
|
||||
/**
|
||||
* Parses the string as a [Short] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun String.toShortOrNull(radix: Int): Short? {
|
||||
val int = this.toIntOrNull(radix) ?: return null
|
||||
if (int < Short.MIN_VALUE || int > Short.MAX_VALUE) return null
|
||||
return int.toShort()
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string as an [Int] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun String.toIntOrNull(): Int? = toIntOrNull(radix = 10)
|
||||
|
||||
/**
|
||||
* Parses the string as an [Int] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun String.toIntOrNull(radix: Int): Int? {
|
||||
checkRadix(radix)
|
||||
|
||||
val length = this.length
|
||||
if (length == 0) return null
|
||||
|
||||
val start: Int
|
||||
val isNegative: Boolean
|
||||
val limit: Int
|
||||
|
||||
val firstChar = this[0]
|
||||
if (firstChar < '0') { // Possible leading sign
|
||||
if (length == 1) return null // non-digit (possible sign) only, no digits after
|
||||
|
||||
start = 1
|
||||
|
||||
if (firstChar == '-') {
|
||||
isNegative = true
|
||||
limit = Int.MIN_VALUE
|
||||
} else if (firstChar == '+') {
|
||||
isNegative = false
|
||||
limit = -Int.MAX_VALUE
|
||||
} else
|
||||
return null
|
||||
} else {
|
||||
start = 0
|
||||
isNegative = false
|
||||
limit = -Int.MAX_VALUE
|
||||
}
|
||||
|
||||
|
||||
val limitBeforeMul = limit / radix
|
||||
var result = 0
|
||||
for (i in start..(length - 1)) {
|
||||
val digit = digitOf(this[i], radix)
|
||||
|
||||
if (digit < 0) return null
|
||||
if (result < limitBeforeMul) return null
|
||||
|
||||
result *= radix
|
||||
|
||||
if (result < limit + digit) return null
|
||||
|
||||
result -= digit
|
||||
}
|
||||
|
||||
return if (isNegative) result else -result
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string as a [Long] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun String.toLongOrNull(): Long? = toLongOrNull(radix = 10)
|
||||
|
||||
/**
|
||||
* Parses the string as a [Long] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun String.toLongOrNull(radix: Int): Long? {
|
||||
checkRadix(radix)
|
||||
|
||||
val length = this.length
|
||||
if (length == 0) return null
|
||||
|
||||
val start: Int
|
||||
val isNegative: Boolean
|
||||
val limit: Long
|
||||
|
||||
val firstChar = this[0]
|
||||
if (firstChar < '0') { // Possible leading sign
|
||||
if (length == 1) return null // non-digit (possible sign) only, no digits after
|
||||
|
||||
start = 1
|
||||
|
||||
if (firstChar == '-') {
|
||||
isNegative = true
|
||||
limit = Long.MIN_VALUE
|
||||
} else if (firstChar == '+') {
|
||||
isNegative = false
|
||||
limit = -Long.MAX_VALUE
|
||||
} else
|
||||
return null
|
||||
} else {
|
||||
start = 0
|
||||
isNegative = false
|
||||
limit = -Long.MAX_VALUE
|
||||
}
|
||||
|
||||
|
||||
val limitBeforeMul = limit / radix
|
||||
var result = 0L
|
||||
for (i in start..(length - 1)) {
|
||||
val digit = digitOf(this[i], radix)
|
||||
|
||||
if (digit < 0) return null
|
||||
if (result < limitBeforeMul) return null
|
||||
|
||||
result *= radix
|
||||
|
||||
if (result < limit + digit) return null
|
||||
|
||||
result -= digit
|
||||
}
|
||||
|
||||
return if (isNegative) result else -result
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string as a [Float] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun String.toFloatOrNull(): Float? = TODO()
|
||||
|
||||
/**
|
||||
* Parses the string as a [Double] number and returns the result
|
||||
* or `null` if the string is not a valid representation of a number.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun String.toDoubleOrNull(): Double? = TODO()
|
||||
@@ -2,10 +2,16 @@ Start with building compiler by using `dist` and `cross_dist` for cross-targets.
|
||||
To build Tetris application for your host platform use
|
||||
./build
|
||||
note that SDL2 must be installed on the host.
|
||||
For cross-compilation to iOS use
|
||||
TARGET=iphone ./build
|
||||
For cross-compilation to iOS (on Mac host) use
|
||||
TARGET=iphone ./build
|
||||
For cross-compilation to Raspberry Pi (on Linux host) use
|
||||
TARGET=raspberrypi ./build
|
||||
|
||||
During build process compilation script creates interoperability bindings to SDL2, using SDL C headers,
|
||||
and then compiles an application with the produced bindings.
|
||||
|
||||
To deploy executable to iPhone device take Info.plist, then use XCode and your own private signing identity.
|
||||
|
||||
To run on Raspberry Pi one need to install SDL package with `apt-get install libsdl2-2.0.0` on the Pi.
|
||||
Also GLES2 renderer is recommended (use `SDL_RENDER_DRIVER=opengles2 ./tetris.kexe`).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user