From e094fe41926608ab52c46ee51a0b4b0b72578d92 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Mon, 10 Feb 2014 16:34:40 +0400 Subject: [PATCH] Adds emulation of Integer.parseInt --- .../org/teavm/classlib/java/lang/TClass.java | 2 +- .../teavm/classlib/java/lang/TInteger.java | 55 +++++++++++++++++-- .../teavm/classlib/java/lang/IntegerTest.java | 48 ++++++++++++++++ .../javascript/BlockRefCountVisitor.java | 1 + 4 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 teavm-classlib/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index de02ed8e1..3388305c3 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -66,5 +66,5 @@ public class TClass extends TObject { static native TClass booleanClass(); @InjectedBy(ClassNativeGenerator.class) - static native TClass integerClass(); + static native TClass intClass(); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java index 51c83b824..3063fe596 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java @@ -21,15 +21,19 @@ package org.teavm.classlib.java.lang; */ public class TInteger extends TNumber implements TComparable { public static final int SIZE = 32; - public static final int MIN_VALUE = (2 << (SIZE - 1)); - public static final int MAX_VALUE = (2 << (SIZE - 1)) - 1; - public static final TClass TYPE = TClass.integerClass(); + public static final int MIN_VALUE = 0x80000000; + public static final int MAX_VALUE = 0x7FFFFFFF; + public static final TClass TYPE = TClass.intClass(); private int value; public TInteger(int value) { this.value = value; } + public TInteger(TString s) throws NumberFormatException { + this(parseInt(s)); + } + @Override public int compareTo(TInteger other) { return compare(value, other.value); @@ -59,7 +63,46 @@ public class TInteger extends TNumber implements TComparable { return x > y ? 1 : x < y ? -1 : 0; } - /*public static int parseInt(TString s, int radix) throws TNumberFormatException { - return 0; - }*/ + public static int parseInt(TString s, int radix) throws TNumberFormatException { + if (radix < TCharacter.MIN_RADIX || radix > TCharacter.MAX_RADIX) { + throw new TNumberFormatException(TString.wrap("Illegal radix: " + radix)); + } + if (s == null || s.isEmpty()) { + throw new TNumberFormatException(TString.wrap("String is null or empty")); + } + boolean negative = false; + int index = 0; + switch (s.charAt(0)) { + case '-': + negative = true; + index = 1; + break; + case '+': + index = 1; + break; + } + int value = 0; + while (index < s.length()) { + int digit = TCharacter.digit(s.charAt(index++)); + if (digit < 0) { + throw new TNumberFormatException(TString.wrap("String contains invalid digits: " + s)); + } + if (digit >= radix) { + throw new TNumberFormatException(TString.wrap("String contains digits out of radix " + radix + + ": " + s)); + } + value = radix * value + digit; + if (value < 0) { + if (index == s.length() && value == MIN_VALUE && negative) { + return MIN_VALUE; + } + throw new TNumberFormatException(TString.wrap("The value is too big for int type: " + s)); + } + } + return negative ? -value : value; + } + + public static int parseInt(TString s) throws TNumberFormatException { + return parseInt(s, 10); + } } diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java new file mode 100644 index 000000000..4b825c0fb --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.java.lang; + +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +public class IntegerTest { + @Test + public void parsesInteger() { + assertEquals(0, Integer.parseInt("0", 10)); + assertEquals(473, Integer.parseInt("473", 10)); + assertEquals(42, Integer.parseInt("+42", 10)); + assertEquals(0, Integer.parseInt("-0", 10)); + assertEquals(-255, Integer.parseInt("-FF", 16)); + assertEquals(102, Integer.parseInt("1100110", 2)); + assertEquals(2147483647, Integer.parseInt("2147483647", 10)); + assertEquals(-2147483648, Integer.parseInt("-2147483648", 10)); + assertEquals(411787, Integer.parseInt("Kona", 27)); + } + + @Test(expected = NumberFormatException.class) + public void rejectsTooBigInteger() { + Integer.parseInt("2147483648", 10); + } + + @Test(expected = NumberFormatException.class) + public void rejectsIntegerWithDigitsOutOfRadix() { + Integer.parseInt("99", 8); + } +} diff --git a/teavm-core/src/main/java/org/teavm/javascript/BlockRefCountVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/BlockRefCountVisitor.java index 384d9a1d8..aebe0b162 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/BlockRefCountVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/BlockRefCountVisitor.java @@ -49,6 +49,7 @@ class BlockRefCountVisitor implements StatementVisitor { @Override public void visit(SwitchStatement statement) { + refs.put(statement, 0); for (SwitchClause clause : statement.getClauses()) { for (Statement part : clause.getBody()) { part.acceptVisitor(this);