diff --git a/c/vm_instance.c b/c/vm_instance.c index 5ecbdc6..91a2c91 100644 --- a/c/vm_instance.c +++ b/c/vm_instance.c @@ -25,12 +25,12 @@ struct objectref * vm_instance_create(struct vm * vm, const char * class_name) struct objectref * vm_instance_string_from_constant(struct vm * vm, struct constant * constant) { int32_t count = constant->utf8.length; - struct arrayref * arrayref = prim_array_allocate(vm, 1, count); + struct arrayref * arrayref = prim_array_allocate(vm, 2, count); assert(arrayref != nullptr); arrayref->class_entry = nullptr; // byte[] arrayref->length = constant->utf8.length; for (int i = 0; i < constant->utf8.length; i++) { - arrayref->u8[i] = constant->utf8.bytes[i]; + arrayref->u16[i] = constant->utf8.bytes[i]; } struct objectref * objectref = vm_instance_create(vm, "java/lang/String"); diff --git a/classes/java/lang/Character.java b/classes/java/lang/Character.java index 2892c5a..2a7e8e6 100644 --- a/classes/java/lang/Character.java +++ b/classes/java/lang/Character.java @@ -1,4 +1,144 @@ package java.lang; -class Character { +class Character + implements Comparable { + public static final int MAX_RADIX = 36; + + public static final int MAX_VALUE = '\uFFFF'; + + public static final int MIN_RADIX = 2; + + public static final char MIN_VALUE = '\u0000'; + + public static final int SIZE = 16; + + private final char value; + + public Character(char value) { + this.value = value; + } + + public char charValue() { + return value; + } + + public int compareTo(Character anotherCharacter) { + return this.charValue() - anotherCharacter.charValue(); + } + + private static int _digit(char ch) { + if (Character.isDigit(ch)) + return (char)((int)ch - (int)'0'); + if (ch >= 'A' && ch <= 'Z') + return (char)((int)ch - (int)'A' + 10); + if (ch >= 'a' && ch <= 'z') + return (char)((int)ch - (int)'a' + 10); + return -1; + } + + public static int digit(char ch, int radix) { + if (radix < MIN_RADIX || radix > MAX_RADIX) + return -1; + int value = _digit(ch); + return (value < radix) ? value : -1; + } + + public boolean equals(Object obj) { + return obj instanceof Character && value == ((Character)obj).value; + } + + public static char forDigit(int digit, int radix) { + if (digit < 0 || digit > MAX_RADIX) + return '\u0000'; + if (digit < 10) { + return (char)((int)'0' + digit); + } else { + return (char)((int)'a' + digit - 10); + } + } + + public int hashCode() { + return value; + } + + public static boolean isDigit(char ch) { + return ch >= '0' && ch <= '9'; + } + + public static boolean isISOControl(char ch) { + return (ch >= '\u0000' && ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F'); + } + + public static boolean isLowerCase(char ch) { + return + (ch >= 'a' && ch <= 'z') || + (ch >= '\u00DF' && ch <= '\u00F6') || + (ch >= '\u00F8' && ch <= '\u00FF'); + } + + public static boolean isSpaceChar(char ch) { + switch (ch) { + case ' ': return true; + case '\t': return true; + case '\n': return true; + case '\r': return true; + case '\f': return true; + default: return false; + } + } + + public static boolean isUpperCase(char ch) { + return + (ch >= 'A' && ch <= 'Z') || + (ch >= '\u00C0' && ch <= '\u00D6') || + (ch >= '\u00D8' && ch <= '\u00DE'); + } + + public static boolean isWhitespace(char ch) { + switch (ch) { + case ' ': return true; + case '\t': return true; + case '\n': return true; + case '\u000B': return true; + case '\u000C': return true; + case '\r': return true; + case '\u001C': return true; + case '\u001D': return true; + case '\u001E': return true; + case '\u001F': return true; + default: return false; + } + } + + public static char toLowerCase(char ch) { + if (ch >= 'A' && ch <= 'Z') + return (char)((int)ch - (int)'A' + (int)'a'); + if (ch >= '\u00C0' && ch <= '\u00D6') + return (char)((int)ch - (int)'\u00C0' + (int)'\u00E0'); + if (ch >= '\u00D8' && ch <= '\u00DE') + return (char)((int)ch - (int)'\u00D8' + (int)'\u00F8'); + return ch; + } + + public String toString() { + return Character.toString(value); + } + + public static String toString(char c) { + return new String(new char[] { c }); + } + + public static char toUpperCase(char ch) { + if (ch >= 'a' && ch <= 'z') + return (char)((int)ch - (int)'a' + (int)'A'); + if (ch >= '\u00E0' && ch <= '\u00F6') + return (char)((int)ch - (int)'\u00E0' + (int)'\u00C0'); + if (ch >= '\u00F8' && ch <= '\u00FE') + return (char)((int)ch - (int)'\u00F8' + (int)'\u00D8'); + return ch; + } + + public static Character valueOf(char c) { + return new Character(c); + } } diff --git a/classes/java/lang/String.java b/classes/java/lang/String.java index 78f77f0..41ee09c 100644 --- a/classes/java/lang/String.java +++ b/classes/java/lang/String.java @@ -1,30 +1,377 @@ package java.lang; -public class String { - private final byte[] value; + +public final class String + implements Comparable, CharSequence { + + private final char[] value; public String() { - this.value = new byte[0]; + value = new char[0]; + } + + public String(byte[] bytes) { + this(bytes, 0, bytes.length); + } + + public String(byte[] bytes, int offset, int length) { + value = new char[length]; + int i = 0; + while (length > 0) { + value[i] = (char)bytes[offset]; + i += 1; + offset += 1; + length -= 1; + } + } + + public String(char[] value) { + this(value, 0, value.length); + } + + public String(char[] value, int offset, int count) { + this.value = new char[count]; + int i = 0; + while (count > 0) { + this.value[i] = value[offset]; + i += 1; + offset += 1; + count -= 1; + } } public String(String original) { - this.value = original.value; + // shallow copy + value = original.value; } - public String(byte[] value) { - this.value = value; + public char charAt(int index) { + return value[index]; + } + + public int compareTo(String anotherString) { + int length = value.length < anotherString.value.length + ? value.length + : anotherString.value.length; + + for (int k = 0; k < length; k++) { + int difference = value[k] - anotherString.value[k]; + if (difference != 0) + return difference; + } + + return value.length - anotherString.value.length; + } + + public int compareToIgnoreCase(String str) { + int length = value.length < str.value.length + ? value.length + : str.value.length; + + for (int k = 0; k < length; k++) { + char a = Character.toLowerCase(Character.toUpperCase(value[k])); + char b = Character.toLowerCase(Character.toUpperCase(str.value[k])); + int difference = a - b; + if (difference != 0) + return difference; + } + + return value.length - str.value.length; + } + + public String concat(String str) { + if (str.value.length == 0) + return this; + if (value.length == 0) + return str; + int length_a = value.length; + int length_b = str.value.length; + char[] newValue = new char[length_a + length_b]; + for (int i = 0; i < length_a; i++) { + newValue[i] = value[i]; + } + for (int i = 0; i < length_b; i++) { + newValue[length_a + i] = str.value[i]; + } + return new String(newValue); + } + + public boolean contains(CharSequence s) { + return indexOf(s.toString()) != -1; + } + + public boolean contentEquals(CharSequence cs) { + return equals(cs.toString()); + } + + public static String copyValueOf(char[] data) { + return new String(data); + } + + public static String copyValueOf(char[] data, + int offset, + int count) { + return new String(data, offset, count); + } + + public boolean endsWith(String suffix) { + int fromIndex = value.length - suffix.value.length; + return regionMatches(false, fromIndex, suffix, 0, suffix.value.length); + } + + public boolean equals(Object anObject) { + if (anObject == null) + return false; + if (!(anObject instanceof String)) + return false; + String str = (String)anObject; + if (value == str.value) + return true; + if (value.length != str.value.length) + return false; + for (int i = 0; i < value.length; i++) { + if (value[i] != str.value[i]) + return false; + } + return true; + } + + public boolean equalsIgnoreCase(String anotherString) { + if (anotherString == null) + return false; + if (value == anotherString.value) + return true; + if (value.length != anotherString.value.length) + return false; + for (int i = 0; i < value.length; i++) { + char a = Character.toLowerCase(Character.toUpperCase(value[i])); + char b = Character.toLowerCase(Character.toUpperCase(anotherString.value[i])); + if (a != b) + return false; + } + return true; } public byte[] getBytes() { - return this.value; + byte[] bytes = new byte[value.length]; + for (int i = 0; i < value.length; i++) { + bytes[i] = (byte)value[i]; + } + return bytes; + } + + public void getChars(int srcBegin, + int srcEnd, + char[] dst, + int dstBegin) { + if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > value.length || + dstBegin < 0 || (dstBegin + (srcEnd - srcBegin)) > dst.length) + throw new IndexOutOfBoundsException(); + for (int i = 0; i < srcEnd - srcBegin; i++) { + dst[dstBegin + i] = value[srcBegin + i]; + } + } + + public int hashCode() { + int code = 0; + for (int i = 0; i < value.length; i++) { + code = code * 31 + value[i]; + } + return code; + } + + public int indexOf(int ch) { + return indexOf(ch, 0); + } + + public int indexOf(int ch, int fromIndex) { + if (ch > 0xffff) + return -1; + if (fromIndex < 0) + fromIndex = 0; + while (fromIndex < value.length) { + if (value[fromIndex] == ch) + return fromIndex; + fromIndex += 1; + } + return -1; + } + + public int indexOf(String str) { + return indexOf(str, 0); + } + + public int indexOf(String str, int fromIndex) { + if (fromIndex < 0) + fromIndex = 0; + int maxIndex = value.length - str.value.length; + while (fromIndex <= maxIndex) { + if (regionMatches(false, fromIndex, str, 0, str.value.length)) + return fromIndex; + fromIndex += 1; + } + return -1; + } + + public boolean isEmpty() { + return value.length == 0; + } + + public int lastIndexOf(int ch) { + return lastIndexOf(ch, value.length - 1); + } + + public int lastIndexOf(int ch, int fromIndex) { + if (ch > 0xffff) + return -1; + if (fromIndex >= value.length) + fromIndex = value.length - 1; + while (fromIndex >= 0) { + if (value[fromIndex] == ch) + return fromIndex; + fromIndex -= 1; + } + return -1; + } + + public int lastIndexOf(String str) { + return indexOf(str, value.length - 1); + } + + public int lastIndexOf(String str, int fromIndex) { + if (fromIndex >= value.length) + fromIndex = value.length - 1; + while (fromIndex >= 0) { + if (regionMatches(false, fromIndex, str, 0, str.value.length)) + return fromIndex; + fromIndex -= 1; + } + return -1; + } + + public int length() { + return value.length; + } + + public boolean regionMatches(boolean ignoreCase, + int toffset, + String other, + int ooffset, + int len) { + if (toffset < 0 || ooffset < 0 || toffset + len > value.length || ooffset + len > other.value.length) + return false; + + while (len > 0) { + len -= 1; + char a = value[toffset]; + toffset += 1; + char b = other.value[ooffset]; + ooffset += 1; + + if (a != b) { + if (!ignoreCase) + return false; + char a1 = Character.toLowerCase(Character.toUpperCase(a)); + char b1 = Character.toLowerCase(Character.toUpperCase(b)); + if (a1 != b1) + return false; + } + } + return true; + } + + public boolean regionMatches(int toffset, + String other, + int ooffset, + int len) { + return regionMatches(false, toffset, other, ooffset, len); + } + + public String replace(char oldChar, char newChar) { + boolean replaced = false; + char[] newValue = new char[value.length]; + for (int i = 0; i < value.length; i++) { + if (value[i] == oldChar) { + replaced = true; + newValue[i] = newChar; + } else { + newValue[i] = value[i]; + } + } + if (replaced) + return new String(newValue); + else + return this; + } + + public boolean startsWith(String prefix) { + return regionMatches(false, 0, prefix, 0, prefix.value.length); + } + + public boolean startsWith(String prefix, int toffset) { + return regionMatches(false, toffset, prefix, 0, prefix.value.length); + } + + public CharSequence subSequence(int beginIndex, int endIndex) { + return substring(beginIndex, endIndex); + } + + public String substring(int beginIndex) { + return substring(beginIndex, value.length); + } + + public String substring(int beginIndex, int endIndex) { + if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) + throw new IndexOutOfBoundsException(); + int length = endIndex - beginIndex; + return new String(value, beginIndex, length); + } + + public char[] toCharArray() { + char[] array = new char[value.length]; + for (int i = 0; i < value.length; i++) { + array[i] = value[i]; + } + return array; + } + + public String toLowerCase() { + char[] newValue = new char[value.length]; + for (int i = 0; i < value.length; i++) { + newValue[i] = Character.toLowerCase(value[i]); + } + return new String(newValue); } public String toString() { return this; } - public int length() { - return value.length; + public String toUpperCase() { + char[] newValue = new char[value.length]; + for (int i = 0; i < value.length; i++) { + newValue[i] = Character.toUpperCase(value[i]); + } + return new String(newValue); + } + + public String trim() { + if (value.length == 0 || (value[0] > '\u0020' && value[value.length - 1] > '\u0020')) + return this; + + int k = 0; + while (k < value.length - 1) { + if (value[k] > '\u0020') + break; + k += 1; + } + int m = value.length - 1; + while (m >= 0) { + if (value[m] > '\u0020') + break; + m -= 1; + } + return substring(k, m + 1); } public static String valueOf(boolean b) { @@ -32,7 +379,25 @@ public class String { } public static String valueOf(char c) { - return new String(new byte[] { (byte)c }); + return new String(new char[] { c }); + } + + public static String valueOf(char[] data) { + return new String(data, 0, data.length); + } + + public static String valueOf(char[] data, + int offset, + int count) { + return new String(data, offset, count); + } + + public static String valueOf(double d) { + return Double.toString(d); + } + + public static String valueOf(float f) { + return Float.toString(f); } public static String valueOf(int i) { @@ -43,14 +408,6 @@ public class String { return Long.toString(l); } - public static String valueOf(float f) { - return Float.toString(f); - } - - public static String valueOf(double d) { - return Double.toString(d); - } - public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }