Adds some java.lang.Float implementation

This commit is contained in:
konsoletyper 2014-03-07 16:32:22 +04:00
parent 758c7c7966
commit 2afbb3d4bd
6 changed files with 237 additions and 6 deletions

View File

@ -92,6 +92,9 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
case "doubleClass":
context.getWriter().append("$rt_cls($rt_doublecls())");
break;
case "floatClass":
context.getWriter().append("$rt_cls($rt_floatcls())");
break;
case "wrap":
context.writeExpr(context.getArgument(0));
break;
@ -179,11 +182,12 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
@Override
public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
switch (graph.getReference().getName()) {
case "booleanClass":
case "intClass":
case "charClass":
case "byteClass":
case "voidClass":
case "booleanClass":
case "byteClass":
case "charClass":
case "intClass":
case "floatClass":
case "doubleClass":
case "wrap":
case "getSuperclass":

View File

@ -19,13 +19,15 @@ import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.ni.Injector;
import org.teavm.javascript.ni.InjectorContext;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public class FloatNativeGenerator implements Generator {
public class FloatNativeGenerator implements Generator, Injector {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
@ -38,6 +40,15 @@ public class FloatNativeGenerator implements Generator {
}
}
@Override
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "getNaN":
context.getWriter().append("NaN");
break;
}
}
private void generateIsNaN(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append("return (isNaN(").append(context.getParameterName(1)).append(")").ws().append("?")
.ws().append("1").ws().append(":").ws().append("0").ws().append(");").softNewLine();

View File

@ -89,6 +89,10 @@ public class TClass<T> extends TObject {
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TByte> byteClass();
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TFloat> floatClass();
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TDouble> doubleClass();

View File

@ -203,6 +203,12 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
return other instanceof TDouble && ((TDouble)other).value == value;
}
@Override
public int hashCode() {
long h = doubleToLongBits(value);
return (int)(h >>> 32) ^ ((int)h | 0);
}
public static int compare(double a, double b) {
return a > b ? 1 : a < b ? -1 : 0;
}

View File

@ -22,13 +22,31 @@ import org.teavm.javascript.ni.Rename;
*
* @author Alexey Andreev
*/
public class TFloat extends TNumber {
public class TFloat extends TNumber implements TComparable<TFloat> {
public static final float POSITIVE_INFINITY = 1 / 0.0f;
public static final float NEGATIVE_INFINITY = -POSITIVE_INFINITY;
public static final float NaN = getNaN();
public static final float MAX_VALUE = 0x1.fffffeP+127f;
public static final float MIN_VALUE = 0x1.0p-126f;
public static final float MIN_NORMAL = 0x0.000002P-126f;
public static final int MAX_EXPONENT = 127;
public static final int MIN_EXPONENT = -126;
public static final int SIZE = 32;
public static final TClass<TFloat> TYPE = TClass.floatClass();
private float value;
public TFloat(float value) {
this.value = value;
}
public TFloat(double value) {
this((float)value);
}
public TFloat(TString value) throws TNumberFormatException {
this(parseFloat(value));
}
@Override
public int intValue() {
return (int)value;
@ -76,4 +94,141 @@ public class TFloat extends TNumber {
@GeneratedBy(FloatNativeGenerator.class)
public static native boolean isInfinite(float v);
@GeneratedBy(FloatNativeGenerator.class)
private static native float getNaN();
public static float parseFloat(TString string) throws TNumberFormatException {
// TODO: parse infinite and different radix
string = string.trim();
boolean negative = false;
int index = 0;
if (string.charAt(index) == '-') {
++index;
negative = true;
} else if (string.charAt(index) == '+') {
++index;
}
char c = string.charAt(index);
if (c < '0' || c > '9') {
throw new TNumberFormatException();
}
int mantissa = 0;
int exp = 0;
while (string.charAt(index) == '0') {
if (++index == string.length()) {
return 0;
}
}
while (index < string.length()) {
c = string.charAt(index);
if (c < '0' || c > '9') {
break;
}
if (mantissa < 1E8) {
mantissa = mantissa * 10 + (c - '0');
} else {
++exp;
}
++index;
}
if (index < string.length() && string.charAt(index) == '.') {
++index;
boolean hasOneDigit = false;
while (index < string.length()) {
c = string.charAt(index);
if (c < '0' || c > '9') {
break;
}
if (mantissa < 1E38) {
mantissa = mantissa * 10 + (c - '0');
--exp;
}
++index;
hasOneDigit = true;
}
if (!hasOneDigit) {
throw new TNumberFormatException();
}
}
if (index < string.length()) {
c = string.charAt(index);
if (c != 'e' && c != 'E') {
throw new TNumberFormatException();
}
++index;
boolean negativeExp = false;
if (string.charAt(index) == '-') {
++index;
negativeExp = true;
} else if (string.charAt(index) == '+') {
++index;
}
int numExp = 0;
boolean hasOneDigit = false;
while (index < string.length()) {
c = string.charAt(index);
if (c < '0' || c > '9') {
break;
}
numExp = 10 * numExp + (c - '0');
hasOneDigit = true;
++index;
}
if (!hasOneDigit) {
throw new TNumberFormatException();
}
if (negativeExp) {
numExp = -numExp;
}
exp += numExp;
}
if (exp > 38 || exp == 38 && mantissa > 34028234) {
return !negative ? POSITIVE_INFINITY : NEGATIVE_INFINITY;
}
if (negative) {
mantissa = -mantissa;
}
return mantissa * decimalExponent(exp);
}
private static float decimalExponent(int n) {
float d;
if (n < 0) {
d = 0.1f;
n = -n;
} else {
d = 10;
}
float result = 1;
while (n != 0) {
if (n % 2 != 0) {
result *= d;
}
d *= d;
n /= 2;
}
return result;
}
public static TFloat valueOf(TString s) throws TNumberFormatException {
return valueOf(parseFloat(s));
}
public boolean isNaN() {
return isNaN(value);
}
public boolean isInfinite() {
return isInfinite(value);
}
public static int compare(float f1, float f2) {
return f1 > f2 ? 1 : f2 < f1 ? -1 : 0;
}
@Override
public int compareTo(TFloat other) {
return compare(value, other.value);
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.assertEquals;
import org.junit.Test;
/**
*
* @author Alexey Andreev
*/
public class FloatTest {
@Test
public void parsed() {
assertEquals(23, Double.parseDouble("23"), 1E-12);
assertEquals(23, Double.parseDouble("23.0"), 1E-12);
assertEquals(23, Double.parseDouble("23E0"), 1E-12);
assertEquals(23, Double.parseDouble("2.30000E1"), 1E-12);
assertEquals(23, Double.parseDouble("0.23E2"), 1E-12);
assertEquals(23, Double.parseDouble("0.000023E6"), 1E-12);
assertEquals(23, Double.parseDouble("00230000e-4"), 1E-12);
assertEquals(23, Double.parseDouble("2300000000000000000000e-20"), 1E-12);
assertEquals(23, Double.parseDouble("2300000000000000000000e-20"), 1E-12);
}
@Test
public void negativeParsed() {
assertEquals(-23, Double.parseDouble("-23"), 1E-12);
}
@Test
public void zeroParsed() {
assertEquals(0, Double.parseDouble("0.0"), 1E-12);
assertEquals(0, Double.parseDouble("23E-8000"), 1E-12);
assertEquals(0, Double.parseDouble("00000"), 1E-12);
assertEquals(0, Double.parseDouble("00000.0000"), 1E-12);
}
}