Incremental changes

This commit is contained in:
spaceflint 2020-09-10 07:56:54 +03:00
parent 384a5f5182
commit 28a84d4799
31 changed files with 1504 additions and 232 deletions

View File

@ -17,6 +17,7 @@
<Compile Include="src\**\*.cs" />
<CustomAdditionalCompileInputs Include="*.filter" />
<Filter Include="*.filter" />
<Reference Include="System" />
</ItemGroup>
<!-- build Javalib.dll from the Java runtime library -->
<Target Name="CheckJavaHome" BeforeTargets="BuildJavalib">

View File

@ -3,7 +3,6 @@ namespace system
{
public sealed class AppDomain
{
public static AppDomain CurrentDomain
=> System.Threading.LazyInitializer.EnsureInitialized<AppDomain>(ref theInstance);
@ -18,5 +17,71 @@ namespace system
}
private static AppDomain theInstance;
//
// GetAssemblies
//
public System.Reflection.Assembly[] GetAssemblies()
{
var classLoaderObject =
((java.lang.Object) (object) this).getClass().getClassLoader();
InitClassLoaderFields(classLoaderObject);
var domains = (java.util.Set) Util.JavaUnsafe.getObject(
classLoaderObject, _DomainsOffset);
int n = domains.size();
int i = 0;
var assemblies = new System.Reflection.Assembly[n];
for (var it = domains.iterator(); it.hasNext() && i < n; i++)
{
var domain = (java.security.ProtectionDomain) it.next();
assemblies[i] =
system.reflection.RuntimeAssembly.GetAssemblyForDomain(domain);
}
return assemblies;
}
//
// GetClassesInAssembly
//
public java.util.Vector GetAllClasses()
{
var classLoaderObject =
((java.lang.Object) (object) this).getClass().getClassLoader();
InitClassLoaderFields(classLoaderObject);
return (java.util.Vector) Util.JavaUnsafe.getObject(
classLoaderObject, _ClassesOffset);
}
//
// InitClassLoaderFields
//
private void InitClassLoaderFields(java.lang.ClassLoader classLoaderObject)
{
if (_ClassesOffset == -1 || _DomainsOffset == -1)
{
var classLoaderClass =
((java.lang.Object) (object) classLoaderObject).getClass();
for (;;)
{
if (classLoaderClass ==
(java.lang.Class) typeof(java.lang.ClassLoader))
break;
classLoaderClass = classLoaderClass.getSuperclass();
}
_ClassesOffset = Util.JavaUnsafe.objectFieldOffset(
classLoaderClass.getDeclaredField("classes"));
_DomainsOffset = Util.JavaUnsafe.objectFieldOffset(
classLoaderClass.getDeclaredField("domains"));
}
}
[java.attr.RetainType] static long _ClassesOffset = -1;
[java.attr.RetainType] static long _DomainsOffset = -1;
}
}

View File

@ -1427,10 +1427,10 @@ namespace system
(exc) => new System.IndexOutOfRangeException(exc.getMessage())
);
system.Util.DefineException(
/*system.Util.DefineException(
(java.lang.Class) typeof(java.util.ConcurrentModificationException),
(exc) => new System.InvalidOperationException(exc.getMessage())
);
);*/
system.Util.DefineException(
(java.lang.Class) typeof(java.lang.ArrayStoreException),

View File

@ -3,7 +3,8 @@ namespace system
{
public class Boolean : system.ValueType, system.ValueMethod, java.lang.Cloneable,
System.IConvertible
System.IComparable, System.IComparable<bool>,
System.IConvertible, System.IEquatable<bool>
{
[java.attr.RetainType] protected int v;
@ -36,6 +37,33 @@ namespace system
public override string ToString() => Get() != 0 ? "True" : "False";
public string ToString(System.IFormatProvider provider) => ToString();
// System.IEquatable<bool>
public bool Equals(bool v) => (Get() != 0 ? v : (! v));
// System.IComparable
public virtual int CompareTo(object obj)
{
if (obj is Boolean objBoolean)
return CompareTo(objBoolean.Get() != 0 ? true : false);
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}
// System.IComparable<bool>
public int CompareTo(bool b)
{
return (Get() == 0) ? (b ? -1 : 0)
: (b ? 0 : 1);
}
void ValueMethod.Clear() => Set(0);
void ValueMethod.CopyTo(ValueType into) => ((Boolean) into).Set(Get());
@ -63,8 +91,6 @@ namespace system
// CodeNumber.Indirection methods
//
public int Get_U8() => (byte) Get();
public int Get_I8() => Get();
public void Set_I8(int v) => Set(v);
@ -92,8 +118,6 @@ namespace system
// IConvertible
//
public System.TypeCode GetTypeCode() => System.TypeCode.Boolean;
bool System.IConvertible.ToBoolean(System.IFormatProvider provider)
@ -123,11 +147,9 @@ namespace system
System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider)
=> System.Convert.ToDecimal(Get());
System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider)
=> throw new System.InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo_Int32_DateTime"));
string System.IConvertible.ToString(System.IFormatProvider provider)
=> ToString();
=> throw new System.InvalidCastException();
object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider)
=> null;//System.Convert.DefaultToType((System.IConvertible) this, type, provider);
=> system.Convert.DefaultToType((System.IConvertible) this, type, provider);

View File

@ -2,7 +2,8 @@
namespace system
{
public class SByte : system.ValueType, system.ValueMethod,
public class SByte : system.ValueType, system.ValueMethod, java.lang.Cloneable,
System.IComparable, System.IComparable<sbyte>,
System.IConvertible, System.IEquatable<sbyte>, System.IFormattable
{
@ -44,8 +45,31 @@ namespace system
{
if (string.IsNullOrEmpty(format))
return ToString();
return ParseNumbers.FormatNumber(
(java.lang.String) (object) format, provider, java.lang.Integer.valueOf(Get()));
return ParseNumbers.FormatNumber((java.lang.String) (object) format, provider,
java.lang.Integer.valueOf(Get()));
}
public string ToString(string format) => ToString(format, null);
public string ToString(System.IFormatProvider provider) => ToString();
// System.IComparable
public virtual int CompareTo(object obj)
{
if (obj is SByte objSByte)
return CompareTo((sbyte) objSByte.Get());
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}
// System.IComparable<sbyte>
public int CompareTo(sbyte b)
{
var a = Get();
return (a < b ? -1 : a > b ? 1 : 0);
}
@ -76,8 +100,6 @@ namespace system
// CodeNumber.Indirection methods
//
public int Get_U8() => (byte) Get();
public int Get_I8() => (sbyte) Get();
public void Set_I8(int v) => Set((int) ((byte) v | ((uint) Get() & (uint) 0xFFFFFF00)));
@ -105,8 +127,6 @@ namespace system
// IConvertible
//
public virtual System.TypeCode GetTypeCode() => System.TypeCode.SByte;
bool System.IConvertible.ToBoolean(System.IFormatProvider provider)
@ -136,11 +156,9 @@ namespace system
System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider)
=> System.Convert.ToDecimal(Get());
System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider)
=> throw new System.InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo_Int32_DateTime"));
string System.IConvertible.ToString(System.IFormatProvider provider)
=> ToString();
=> throw new System.InvalidCastException();
object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider)
=> null;//System.Convert.DefaultToType((System.IConvertible) this, type, provider);
=> system.Convert.DefaultToType((System.IConvertible) this, type, provider);
@ -173,7 +191,7 @@ namespace system
#pragma warning disable 0659
public class Byte : SByte, System.IEquatable<byte>
public class Byte : SByte, System.IComparable<byte>, System.IEquatable<byte>
{
new public static Byte Box(int v) => new Byte() { v = (sbyte) v };
@ -188,12 +206,26 @@ namespace system
return (objByte != null && objByte.Get() == Get());
}
// System.IEquatable<sbyte>
// System.IEquatable<byte>
public bool Equals(byte v) => v == Get();
public override System.TypeCode GetTypeCode() => System.TypeCode.Byte;
// System.IComparable
public override int CompareTo(object obj)
{
if (obj is Byte objByte)
return CompareTo((byte) objByte.Get());
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}
// System.IComparable<byte>
public int CompareTo(byte v) => CompareTo((sbyte) Get(), (sbyte) v);
public static int CompareTo(sbyte a, sbyte b)
=> a == b ? 0 : (a & 0xFF) < (b & 0xFF) ? -1 : 1;
//

View File

@ -2,7 +2,8 @@
namespace system
{
public class Char : system.ValueType, system.ValueMethod,
public class Char : system.ValueType, system.ValueMethod, java.lang.Cloneable,
System.IComparable, System.IComparable<char>,
System.IConvertible, System.IEquatable<char>
{
@ -41,13 +42,27 @@ namespace system
public override string ToString() => java.lang.String.valueOf((char) Get());
/*public string ToString(IFormatProvider provider)
{
return java.lang.String.valueOf(Get(this));
}*/
public string ToString(System.IFormatProvider provider) => ToString();
public static string ToString(char c) => java.lang.String.valueOf(c);
// System.IComparable
public virtual int CompareTo(object obj)
{
if (obj is Char objChar)
return CompareTo(objChar.Get());
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}
// System.IComparable<char>
public int CompareTo(char b) => Get() - ((int) b);
//public static char ToUpper(char c, system.globalization.CultureInfo cultureInfo)
public static char ToUpperInvariant(char c) =>
@ -66,8 +81,7 @@ namespace system
static char StringCharAt(string str, int idx)
{
if (str == null)
throw new System.ArgumentNullException();
ThrowHelper.ThrowIfNull(str);
if ((uint) idx >= (uint) str.Length)
throw new System.ArgumentOutOfRangeException();
return str[idx];
@ -97,8 +111,6 @@ namespace system
// CodeNumber.Indirection methods
//
public int Get_U8() => (byte) Get();
public int Get_I8() => Get();
public void Set_I8(int v) => Set(v);
@ -122,8 +134,6 @@ namespace system
// IConvertible
//
public System.TypeCode GetTypeCode() => System.TypeCode.Char;
bool System.IConvertible.ToBoolean(System.IFormatProvider provider)
@ -153,11 +163,9 @@ namespace system
System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider)
=> System.Convert.ToDecimal(Get());
System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider)
=> throw new System.InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo_Int32_DateTime"));
string System.IConvertible.ToString(System.IFormatProvider provider)
=> ToString();
=> throw new System.InvalidCastException();
object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider)
=> null;//System.Convert.DefaultToType((System.IConvertible) this, type, provider);
=> system.Convert.DefaultToType((System.IConvertible) this, type, provider);

View File

@ -2,7 +2,8 @@
namespace system
{
public class Double : system.ValueType, system.ValueMethod,
public class Double : system.ValueType, system.ValueMethod, java.lang.Cloneable,
System.IComparable, System.IComparable<double>,
System.IConvertible, System.IEquatable<double>, System.IFormattable
{
@ -56,6 +57,29 @@ namespace system
(java.lang.String) (object) format, provider, java.lang.Double.valueOf(Get()));
}
public string ToString(string format) => ToString(format, null);
public string ToString(System.IFormatProvider provider) => ToString();
// System.IComparable
public virtual int CompareTo(object obj)
{
if (obj is Double objDouble)
return CompareTo(objDouble.Get());
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}
// System.IComparable<double>
public int CompareTo(double b)
{
var a = Get();
return (a < b ? -1 : a > b ? 1 : 0);
}
void ValueMethod.Clear() => Set(0);
@ -119,8 +143,6 @@ namespace system
// IConvertible
//
public System.TypeCode GetTypeCode() => System.TypeCode.Double;
bool System.IConvertible.ToBoolean(System.IFormatProvider provider)
@ -150,11 +172,9 @@ namespace system
System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider)
=> System.Convert.ToDecimal(Get());
System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider)
=> throw new System.InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo_Int32_DateTime"));
string System.IConvertible.ToString(System.IFormatProvider provider)
=> ToString();
=> throw new System.InvalidCastException();
object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider)
=> null;//System.Convert.DefaultToType((System.IConvertible) this, type, provider);
=> system.Convert.DefaultToType((System.IConvertible) this, type, provider);

View File

@ -121,18 +121,27 @@ namespace system
if (genericObject.TryCast(castToType) != null)
return obj;
if (obj is system.Array.ProxySyncRoot objArray)
{
var proxy = Array.GetProxy(objArray.SyncRoot, castToType, false);
if (proxy != null)
return proxy;
}
obj = objArray.SyncRoot;
}
else
if (obj != null)
{
// handle the cases where ShouldCallGenericCast in GenericUtil
// identifies an interface that should be implemented by an
// array object, or a string
var proxy = Array.GetProxy(obj, castToType, false);
if (proxy != null)
return proxy;
// check if the object (which might not be array or string)
// can actually be cast to the target type
if ( (! castToType.IsGenericType)
&& castToType is RuntimeType castToRuntimeType
&& castToRuntimeType.JavaClassForArray()
.isAssignableFrom(((java.lang.Object) obj).getClass()))
return obj;
}
if (@throw)
ThrowInvalidCastException(obj, castToType);
return null;

View File

@ -44,6 +44,21 @@ namespace system.globalization {
JavaBreakIter = java.text.BreakIterator.getCharacterInstance(locale);
}
//
// Equals
//
public override bool Equals(object other)
=> other is CompareInfo otherCompareInfo && Name == otherCompareInfo.Name;
public override int GetHashCode() => Name.GetHashCode();
public string Name => CultureInfoRef.Name;
public override string ToString() => "CompareInfo - " + CultureInfoRef.ToString();
//
// GetCompareInfo
//
@ -57,12 +72,6 @@ namespace system.globalization {
public static CompareInfo InvariantCompareInfo
=> system.globalization.CultureInfo.InvariantCulture.CompareInfo;
//
//
//
public override string ToString() => "CompareInfo - " + CultureInfoRef.ToString();
//
@ -95,6 +104,166 @@ namespace system.globalization {
return true;
}
//
// Compare (public API)
//
public virtual int Compare(string string1, string string2)
=> CompareString(string1, 0, -1, string2, 0, -1, CompareOptions.None);
public virtual int Compare(string string1, string string2, CompareOptions options)
=> CompareString(string1, 0, -1, string2, 0, -1, options);
public virtual int Compare(string string1, int offset1, string string2, int offset2)
=> CompareString(string1, offset1, -1, string2, offset2, -1, CompareOptions.None);
public virtual int Compare(string string1, int offset1, string string2, int offset2,
CompareOptions options)
=> CompareString(string1, offset1, -1, string2, offset2, -1, options);
public virtual int Compare(string string1, int offset1, int length1,
string string2, int offset2, int length2)
{
if (length1 < 0 || length2 < 0)
throw new ArgumentOutOfRangeException();
return CompareString(string1, offset1, length1, string2, offset2, length2, CompareOptions.None);
}
public virtual int Compare(string string1, int offset1, int length1,
string string2, int offset2, int length2,
CompareOptions options)
{
if (length1 < 0 || length2 < 0)
throw new ArgumentOutOfRangeException();
return CompareString(string1, offset1, length1, string2, offset2, length2, options);
}
//
// CompareString (internal method)
//
private int CompareString(string string1, int offset1, int length1,
string string2, int offset2, int length2,
CompareOptions options)
{
if (offset1 < 0 || offset2 < 0)
throw new ArgumentOutOfRangeException();
int endOffset1 = GetEndOffset(string1, offset1, length1);
int endOffset2 = GetEndOffset(string2, offset2, length2);
if (string1 == null)
return (string2 == null) ? 0 : -1;
else if (string2 == null)
return 1;
if ((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) != 0)
{
bool ignoreCase;
if (options == CompareOptions.Ordinal)
ignoreCase = false;
else if (options == CompareOptions.OrdinalIgnoreCase)
ignoreCase = true;
else
throw new System.ArgumentException();
return CompareStringOrdinal(string1, offset1, endOffset1,
string2, offset2, endOffset2,
ignoreCase);
}
else
{
return CompareStringCulture(string1, offset1, endOffset1,
string2, offset2, endOffset2,
CompareOptionsToCollatorMask(options));
}
static int GetEndOffset(string str, int ofs, int len)
{
if (str == null)
{
if (ofs == 0 && len <= 0)
return -1;
}
else
{
int strLen = ((java.lang.String) (object) str).length();
if (len == -1)
{
if (ofs < strLen)
return strLen;
}
else if ((ofs += len) <= strLen)
return ofs;
}
throw new ArgumentOutOfRangeException();
}
}
//
// CompareStringOrdinal (internal method)
//
private static int CompareStringOrdinal(string string1, int index1, int endIndex1,
string string2, int index2, int endIndex2,
bool ignoreCase)
{
var str1 = (java.lang.String) (object)
(((java.lang.String) (object) string1).substring(index1, endIndex1));
var str2 = (java.lang.String) (object)
(((java.lang.String) (object) string2).substring(index2, endIndex2));
return ignoreCase ? str1.compareToIgnoreCase(str2) : str1.compareTo(str2);
}
//
// CompareStringCulture (internal method)
//
private int CompareStringCulture(string string1, int index1, int endIndex1,
string string2, int index2, int endIndex2,
uint mask)
{
// create iterators for the two strings. see also IndexOfStringCulture
var iterator1 = new Iterator(this, mask,
new java.text.StringCharacterIterator(
string1, index1, endIndex1, index1));
var iterator2 = new Iterator(this, mask,
new java.text.StringCharacterIterator(
string2, index2, endIndex2, index2));
for (;;)
{
var order1 = iterator1.Next();
var order2 = iterator2.Next();
if (order1 == null)
return (order2 == null) ? 0 : -1;
else if (order2 == null)
return 1;
int n1 = order1.Length;
int n2 = order2.Length;
int n = (n1 <= n2) ? n1 : n2;
for (int i = 0; i < n; i++)
{
int o1 = order1[i];
int o2 = order2[i];
if (o1 != o2)
return o1 - o2;
if (o1 == 0)
break;
}
if (n1 != n2)
return n1 - n2;
}
}
//
// IndexOf (char, public API)
//
@ -255,12 +424,12 @@ namespace system.globalization {
//
public static int IndexOfString(string source, string value, int startIndex,
CompareOptions options, CompareInfo compareInfo)
CompareOptions options, CompareInfo compareInfo)
{
ThrowHelper.ThrowIfNull(source);
int sourceLength = ((java.lang.String) (object) source).length();
if (startIndex >= sourceLength)
if (startIndex < 0 || startIndex >= sourceLength)
throw new System.ArgumentOutOfRangeException();
if (options == CompareOptions.Ordinal)
@ -620,7 +789,7 @@ namespace system.globalization {
int sourceLength = ((java.lang.String) (object) source).length();
if (! haveStartIndex)
startIndex = sourceLength - 1;
else if (startIndex >= sourceLength)
else if (startIndex < 0 || startIndex >= sourceLength)
throw new System.ArgumentOutOfRangeException();
if (options == CompareOptions.Ordinal)
@ -1359,7 +1528,7 @@ namespace system.globalization {
else if (small.sequence[S] == 0)
{
// if the small sequence ends before the large sequence,
// this cannot be a made. this is to correctly emulate
// this cannot be a match. this is to correctly emulate
// the .Net comparison, where, for example, a search for
// just "A" cannot match the (AE) symbol.

View File

@ -8,6 +8,7 @@ namespace system.globalization {
[java.attr.RetainType] java.util.Locale JavaLocale;
[java.attr.RetainType] volatile CompareInfo CompareInfoRef;
[java.attr.RetainType] volatile TextInfo TextInfoRef;
@ -42,6 +43,7 @@ namespace system.globalization {
}
JavaLocale = locale;
CompareInfoRef = new CompareInfo(this, JavaLocale);
TextInfoRef = new TextInfo(this, JavaLocale);
}
@ -92,6 +94,8 @@ namespace system.globalization {
public virtual CompareInfo CompareInfo => CompareInfoRef;
public virtual TextInfo TextInfo => TextInfoRef;
public static CultureInfo CurrentCulture
=> system.threading.Thread.CurrentThread.CurrentCulture;

View File

@ -0,0 +1,85 @@
using System;
using System.Runtime.Serialization;
namespace system.globalization {
[Serializable]
public class TextInfo : ICloneable, IDeserializationCallback
{
[java.attr.RetainType] CultureInfo CultureInfoRef;
[java.attr.RetainType] java.util.Locale JavaLocale;
//
// called by CultureInfo
//
public TextInfo(CultureInfo cultureInfo, java.util.Locale locale)
{
CultureInfoRef = cultureInfo;
JavaLocale = locale;
}
//
//
//
public static TextInfo CurrentTextInfo
=> system.threading.Thread.CurrentThread.CurrentCulture.TextInfo;
public static TextInfo InvariantTextInfo
=> system.globalization.CultureInfo.InvariantCulture.TextInfo;
//
// ToLower, ToUpper, ToTitleCase
//
public virtual char ToLower(char c)
=> ((java.lang.String) (object)
((java.lang.String) (object) java.lang.String.valueOf(c))
.toLowerCase(JavaLocale)).charAt(0);
public virtual string ToLower(string s)
=> ((java.lang.String) (object) s).toLowerCase(JavaLocale);
public virtual char ToUpper(char c)
=> ((java.lang.String) (object)
((java.lang.String) (object) java.lang.String.valueOf(c))
.toUpperCase(JavaLocale)).charAt(0);
public virtual string ToUpper(string s)
=> ((java.lang.String) (object) s).toUpperCase(JavaLocale);
public virtual char ToTitleCase(string s)
{
// java.lang.Character.toTitleCase(java.lang.String.toUpperCase(locale))
throw new System.PlatformNotSupportedException();
}
//
// Equals
//
public override bool Equals(object other)
=> other is TextInfo otherTextInfo && CultureName == otherTextInfo.CultureName;
public override int GetHashCode() => CultureName.GetHashCode();
public string CultureName => CultureInfoRef.Name;
public override string ToString() => "TextInfo - " + CultureInfoRef.ToString();
public bool IsReadOnly => true;
public virtual object Clone() => MemberwiseClone();
//
//
//
void IDeserializationCallback.OnDeserialization(object sender)
=> throw new PlatformNotSupportedException();
}
}

View File

@ -2,7 +2,7 @@
namespace system
{
public class Int16 : system.ValueType, system.ValueMethod,
public class Int16 : system.ValueType, system.ValueMethod, java.lang.Cloneable,
System.IComparable, System.IComparable<short>,
System.IConvertible, System.IEquatable<short>, System.IFormattable
{
@ -58,17 +58,17 @@ namespace system
// System.IComparable
public virtual int CompareTo(object obj)
{
if (object.ReferenceEquals(obj, null))
return 1;
if (obj is Int16 objInt16)
return CompareTo((short) objInt16.Get());
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}
// System.IComparable<short>
public int CompareTo(short b)
{
int a = Get();
var a = Get();
return (a < b ? -1 : a > b ? 1 : 0);
}
@ -215,10 +215,10 @@ namespace system
// System.IComparable
public override int CompareTo(object obj)
{
if (object.ReferenceEquals(obj, null))
return 1;
if (obj is UInt16 objUInt16)
return CompareTo((ushort) objUInt16.Get());
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}

View File

@ -2,7 +2,7 @@
namespace system
{
public class Int32 : system.ValueType, system.ValueMethod,
public class Int32 : system.ValueType, system.ValueMethod, java.lang.Cloneable,
System.IComparable, System.IComparable<int>,
System.IConvertible, System.IEquatable<int>, System.IFormattable
{
@ -58,20 +58,22 @@ namespace system
public string ToString(System.IFormatProvider provider) => ToString();
// System.IComparable
public virtual int CompareTo(object obj)
{
if (object.ReferenceEquals(obj, null))
return 1;
if (obj is Int32 objInt32)
return CompareTo((int) objInt32.Get());
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}
// System.IComparable<int>
public int CompareTo(int b)
{
int a = Get();
var a = Get();
return (a < b ? -1 : a > b ? 1 : 0);
}
@ -151,8 +153,6 @@ namespace system
// CodeNumber.Indirection methods
//
public int Get_U8() => (byte) Get();
public int Get_I8() => (sbyte) Get();
public void Set_I8(int v) => Set((int) ((byte) v | ((uint) Get() & (uint) 0xFFFFFF00)));
@ -176,8 +176,6 @@ namespace system
// IConvertible
//
public virtual System.TypeCode GetTypeCode() => System.TypeCode.Int32;
bool System.IConvertible.ToBoolean(System.IFormatProvider provider)
@ -273,10 +271,10 @@ namespace system
// System.IComparable
public override int CompareTo(object obj)
{
if (object.ReferenceEquals(obj, null))
return 1;
if (obj is UInt32 objUInt32)
return CompareTo((uint) objUInt32.Get());
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}

View File

@ -2,7 +2,8 @@
namespace system
{
public class Int64 : system.ValueType, system.ValueMethod,
public class Int64 : system.ValueType, system.ValueMethod, java.lang.Cloneable,
System.IComparable, System.IComparable<long>,
System.IConvertible, System.IEquatable<long>, System.IFormattable
{
@ -63,6 +64,25 @@ namespace system
// System.IComparable
public virtual int CompareTo(object obj)
{
if (obj is Int64 objInt64)
return CompareTo((long) objInt64.Get());
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}
// System.IComparable<long>
public int CompareTo(long b)
{
var a = Get();
return (a < b ? -1 : a > b ? 1 : 0);
}
public static long OverflowAdd(long a, long b)
{
long c = a + b;
@ -123,8 +143,6 @@ namespace system
// CodeNumber.Indirection methods
//
public int Get_U8() => (byte) Get();
public int Get_I8() => (sbyte) Get();
public void Set_I8(int v) => Set((int) ((byte) v | ((ulong) Get() & (ulong) 0xFFFFFFFFFFFFFF00)));
@ -148,8 +166,6 @@ namespace system
// IConvertible
//
public virtual System.TypeCode GetTypeCode() => System.TypeCode.Int64;
bool System.IConvertible.ToBoolean(System.IFormatProvider provider)
@ -227,12 +243,14 @@ namespace system
public static int Size => 8;
public static readonly IntPtr Zero = new IntPtr(0);
new public static IntPtr Box(long v) => new IntPtr(v);
}
#pragma warning disable 0659
public class UInt64 : Int64, System.IEquatable<ulong>
public class UInt64 : Int64, System.IComparable<ulong>, System.IEquatable<ulong>
{
new public static UInt64 Box(long v) => new UInt64() { v = v };
@ -255,8 +273,17 @@ namespace system
public override System.TypeCode GetTypeCode() => System.TypeCode.UInt64;
//public int CompareTo(ulong v) => java.lang.Long.compareUnsigned(Get(), (long) v);
// System.IComparable
public override int CompareTo(object obj)
{
if (obj is UInt64 objUInt64)
return CompareTo((ulong) objUInt64.Get());
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}
// System.IComparable<ulong>
public int CompareTo(ulong v) => CompareTo(Get(), (long) v);
public static int CompareTo(long a, long b)
@ -368,4 +395,19 @@ namespace system
}
public class UIntPtr : UInt64
{
public UIntPtr(int v) => this.v = v;
public UIntPtr(long v) => this.v = v;
public static int Size => 8;
public static readonly UIntPtr Zero = new UIntPtr(0);
new public static UIntPtr Box(long v) => new UIntPtr(v);
}
}

View File

@ -0,0 +1,8 @@
namespace system.reflection
{
public struct CustomAttributeTypedArgument { }
}

View File

@ -1,6 +1,5 @@
using System;
using System.Reflection;
using System.Globalization;
using System.Runtime.Serialization;
@ -11,65 +10,93 @@ namespace system.reflection
public class RuntimeAssembly : System.Reflection.Assembly, ISerializable
{
private java.security.CodeSource JavaCodeSource;
[java.attr.RetainType] private java.security.ProtectionDomain JavaDomain;
private System.Reflection.Module[] theModule;
private static java.util.concurrent.ConcurrentHashMap _DomainToAssemblyMap;
//
//
//
protected RuntimeAssembly(java.security.CodeSource codeSource)
private RuntimeAssembly(java.security.ProtectionDomain domain)
{
JavaCodeSource = codeSource;
JavaDomain = domain;
}
//
//
// GetAssemblyForDomain
//
public static RuntimeAssembly GetExecutingAssembly(ref system.threading.StackCrawlMark stackMark)
public static System.Reflection.Assembly GetAssemblyForDomain(
java.security.ProtectionDomain domain)
{
if (domain == null)
throw new DllNotFoundException();
var map = System.Threading.LazyInitializer
.EnsureInitialized<java.util.concurrent.ConcurrentHashMap>(
ref _DomainToAssemblyMap);
var assembly = (RuntimeAssembly) map.get(domain);
if (assembly == null)
{
var newAssembly = new RuntimeAssembly(domain);
assembly = (RuntimeAssembly)
map.putIfAbsent(domain, newAssembly) ?? newAssembly;
}
return assembly;
}
//
// GetExecutingAssembly
//
public static RuntimeAssembly GetExecutingAssembly(
ref system.threading.StackCrawlMark stackMark)
{
java.security.ProtectionDomain domain = null;
var stackTrace = (new java.lang.Throwable()).getStackTrace();
foreach (var stackElem in stackTrace)
{
var clsnm = stackElem.getClassName();
if (! clsnm.StartsWith("system.reflection."))
return GetAssemblyForClass(java.lang.Class.forName(clsnm));
}
throw new DllNotFoundException();
}
static RuntimeAssembly GetAssemblyForClass(java.lang.Class cls)
{
var jar = cls?.getProtectionDomain()?.getCodeSource();
if (jar != null)
{
var map = System.Threading.LazyInitializer
.EnsureInitialized<java.util.concurrent.ConcurrentHashMap>(
ref _CodeSourceToAssemblyMap);
var assembly = (RuntimeAssembly) map.get(jar);
if (assembly == null)
{
var newAssembly = new RuntimeAssembly(jar);
assembly = (RuntimeAssembly) map.putIfAbsent(jar, newAssembly) ?? newAssembly;
domain = java.lang.Class.forName(clsnm)?.getProtectionDomain();
break;
}
return assembly;
}
throw new DllNotFoundException();
return (RuntimeAssembly) GetAssemblyForDomain(domain);
}
private static java.util.concurrent.ConcurrentHashMap _CodeSourceToAssemblyMap;
//
// GetModules
//
public override System.Reflection.Module[] GetModules(bool getResourceModules)
{
return System.Threading.LazyInitializer
.EnsureInitialized<System.Reflection.Module[]>(ref theModule, () =>
{
var mod = (System.Reflection.Module) (object)
(new RuntimeModule() { JavaDomain = JavaDomain });
return new System.Reflection.Module[] { mod };
});
}
//
//
// GetName
//
public override System.Reflection.AssemblyName GetName(bool copiedName)
{
var name = new System.Reflection.AssemblyName(JavaCodeSource.getLocation().getFile());
var name = new System.Reflection.AssemblyName(
JavaDomain.getCodeSource().getLocation().getFile());
name.Version = new Version();
return name;
}
//
// nInit
//
[java.attr.RetainName]
public static void nInit(System.Reflection.AssemblyName thisAssemblyName,
out RuntimeAssembly assembly,

View File

@ -4,10 +4,38 @@ using System.Runtime.InteropServices;
namespace system.reflection
{
public abstract class Module { }
public sealed class RuntimeModule
public abstract class Module
{
public abstract System.Type[] GetTypes();
}
public sealed class RuntimeModule : Module
{
[java.attr.RetainType] public java.security.ProtectionDomain JavaDomain;
public override System.Type[] GetTypes()
{
for (;;)
{
try
{
var types = new System.Collections.Generic.List<System.Type>();
var iterator = AppDomain.CurrentDomain.GetAllClasses().iterator();
while (iterator.hasNext())
{
var cls = (java.lang.Class) iterator.next();
if (cls.getProtectionDomain() == JavaDomain)
types.Add(system.RuntimeType.GetType(cls));
}
return types.ToArray();
}
catch (java.util.ConcurrentModificationException)
{
}
}
}
public MetadataImport MetadataImport => _MetadataImport;
public StructLayoutAttribute StructLayoutAttribute => _StructLayoutAttribute;

View File

@ -16,6 +16,9 @@ namespace system.runtime.compilerservices {
return 0;
}
public static int GetHashCode(object o)
=> (o != null) ? o.GetHashCode() : 0;
}
}

View File

@ -2,7 +2,8 @@
namespace system
{
public class Single : system.ValueType, system.ValueMethod,
public class Single : system.ValueType, system.ValueMethod, java.lang.Cloneable,
System.IComparable, System.IComparable<float>,
System.IConvertible, System.IEquatable<float>, System.IFormattable
{
@ -44,7 +45,7 @@ namespace system
// System.IEquatable<double>
// System.IEquatable<float>
public bool Equals(float v) => v == Get();
// System.IFormattable
@ -56,6 +57,29 @@ namespace system
(java.lang.String) (object) format, provider, java.lang.Float.valueOf(Get()));
}
public string ToString(string format) => ToString(format, null);
public string ToString(System.IFormatProvider provider) => ToString();
// System.IComparable
public virtual int CompareTo(object obj)
{
if (obj is Single objSingle)
return CompareTo(objSingle.Get());
else if (object.ReferenceEquals(obj, null))
return 1;
throw new System.ArgumentException();
}
// System.IComparable<float>
public int CompareTo(float b)
{
var a = Get();
return (a < b ? -1 : a > b ? 1 : 0);
}
void ValueMethod.Clear() => Set(0);
@ -84,8 +108,6 @@ namespace system
// IConvertible
//
public System.TypeCode GetTypeCode() => System.TypeCode.Single;
bool System.IConvertible.ToBoolean(System.IFormatProvider provider)
@ -115,11 +137,9 @@ namespace system
System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider)
=> System.Convert.ToDecimal(Get());
System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider)
=> throw new System.InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo_Int32_DateTime"));
string System.IConvertible.ToString(System.IFormatProvider provider)
=> ToString();
=> throw new System.InvalidCastException();
object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider)
=> null;//System.Convert.DefaultToType((System.IConvertible) this, type, provider);
=> system.Convert.DefaultToType((System.IConvertible) this, type, provider);

View File

@ -52,36 +52,56 @@ namespace system
return new string(buffer);
}
//
// ToLower, ToUpper
//
public static string ToLower(string self)
=> system.globalization.TextInfo.CurrentTextInfo.ToLower(self);
public static string ToLowerInvariant(string self)
=> system.globalization.TextInfo.InvariantTextInfo.ToLower(self);
public static string ToUpper(string self)
=> system.globalization.TextInfo.CurrentTextInfo.ToUpper(self);
public static string ToUpperInvariant(string self)
=> system.globalization.TextInfo.InvariantTextInfo.ToUpper(self);
//
// Concat object
//
static void AppendIfNotNull(java.lang.StringBuilder sb, object obj)
{
if (obj is string)
{
sb.append((string) obj);
}
else if (obj != null)
{
var str = obj.ToString();
if (str != null)
sb.append(str);
}
}
public static string Concat(object[] objs)
{
if (objs == null)
throw new System.ArgumentNullException();
ThrowHelper.ThrowIfNull(objs);
var sb = new java.lang.StringBuilder();
int n = objs.Length;
for (int i = 0; i < n; i++)
{
var o = objs[i];
if (o != null)
sb.append(o.ToString());
}
foreach (var obj in objs)
AppendIfNotNull(sb, obj);
return sb.ToString();
}
public static string Concat(object objA, object objB, object objC, object objD)
{
var sb = new java.lang.StringBuilder();
if (objA != null)
sb.append(objA.ToString());
if (objB != null)
sb.append(objB.ToString());
if (objC != null)
sb.append(objC.ToString());
if (objC != null)
sb.append(objD.ToString());
AppendIfNotNull(sb, objA);
AppendIfNotNull(sb, objB);
AppendIfNotNull(sb, objC);
AppendIfNotNull(sb, objD);
return sb.ToString();
}
@ -96,32 +116,22 @@ namespace system
// Concat string
//
public static string Concat(params string[] strs)
public static string Concat(string[] strs)
{
if (strs == null)
throw new System.ArgumentNullException();
ThrowHelper.ThrowIfNull(strs);
var sb = new java.lang.StringBuilder();
int n = strs.Length;
for (int i = 0; i < n; i++)
{
var s = strs[i];
if (s != null)
sb.append(s);
}
foreach (var str in strs)
AppendIfNotNull(sb, str);
return sb.ToString();
}
public static string Concat(string strA, string strB, string strC, string strD)
{
var sb = new java.lang.StringBuilder();
if (strA != null)
sb.append(strA);
if (strB != null)
sb.append(strB);
if (strC != null)
sb.append(strC);
if (strD != null)
sb.append(strD);
AppendIfNotNull(sb, strA);
AppendIfNotNull(sb, strB);
AppendIfNotNull(sb, strC);
AppendIfNotNull(sb, strD);
return sb.ToString();
}
@ -134,47 +144,184 @@ namespace system
// Concat enumerator
//
#if false
[java.attr.RetainName]
public static string Concat<T>(System.Collections.Generic.IEnumerable<T> enumerable)
{
if (enumerable == null)
throw new System.ArgumentNullException();
ThrowHelper.ThrowIfNull(enumerable);
var sb = new java.lang.StringBuilder();
using (var enumerator = enumerable.GetEnumerator())
{
while (enumerator.MoveNext())
{
var e = enumerator.Current;
if (e != null)
{
string s = e.ToString();
if (s != null)
sb.append(s);
}
}
}
foreach (var obj in enumerable)
AppendIfNotNull(sb, obj);
return sb.ToString();
}
//[java.attr.RetainName]
public static string Concat(System.Collections.Generic.IEnumerable<string> enumerable)
=> Concat<string>(enumerable);
//
// Split
//
public static string[] Split(string str, char[] separator)
=> InternalSplit((java.lang.String) (object) str, separator, System.Int32.MaxValue, System.StringSplitOptions.None);
public static string[] Split(string str, string[] separator)
=> InternalSplit((java.lang.String) (object) str, separator, System.Int32.MaxValue, System.StringSplitOptions.None);
public static string[] Split(string str, char[] separator, int count)
=> InternalSplit((java.lang.String) (object) str, separator, count, System.StringSplitOptions.None);
public static string[] Split(string str, string[] separator, int count)
=> InternalSplit((java.lang.String) (object) str, separator, count, System.StringSplitOptions.None);
public static string[] Split(string str, char[] separator, System.StringSplitOptions options)
=> InternalSplit((java.lang.String) (object) str, separator, System.Int32.MaxValue, options);
public static string[] Split(string str, string[] separator, System.StringSplitOptions options)
=> InternalSplit((java.lang.String) (object) str, separator, System.Int32.MaxValue, options);
public static string[] Split(string str, char[] separator, int count, System.StringSplitOptions options)
=> InternalSplit((java.lang.String) (object) str, separator, count, options);
public static string[] Split(string str, string[] separator, int count, System.StringSplitOptions options)
=> InternalSplit((java.lang.String) (object) str, separator, count, options);
private static string[] InternalSplit(java.lang.String str,
object separator, int count,
System.StringSplitOptions options)
{
if (enumerable == null)
throw new System.ArgumentNullException();
var sb = new java.lang.StringBuilder();
using (var enumerator = enumerable.GetEnumerator())
if (count < 0)
throw new System.ArgumentOutOfRangeException();
bool omit = (options == System.StringSplitOptions.None) ? false
: (options == System.StringSplitOptions.RemoveEmptyEntries) ? true
: throw new System.ArgumentException();
var emptyArray = new string[0];
if (count == 0)
return emptyArray;
int length = str.length();
var list = new java.util.ArrayList();
if (separator is char[] charSeparator)
SplitCharacter(str, length, list, count, omit, charSeparator);
else if (separator is java.lang.String[] strSeparator)
SplitString(str, length, list, count, omit, strSeparator);
else // assuming separator is null
SplitWhiteSpace(str, length, list, count, omit);
return (string[]) list.toArray(emptyArray);
}
private static void SplitWhiteSpace(java.lang.String str, int length,
java.util.ArrayList list, int maxCount,
bool omit)
{
int listCount = 0;
int lastIndex = -1;
for (int index = 0; index < length; index++)
{
while (enumerator.MoveNext())
if (! Char.IsWhiteSpace(str.charAt(index)))
continue;
if (index == ++lastIndex && omit)
continue;
if (++listCount == maxCount)
{
var s = enumerator.Current;
if (s != null)
sb.append(s);
list.add(str.substring(lastIndex));
return;
}
list.add(str.substring(lastIndex, index));
lastIndex = index;
}
if (length != ++lastIndex || ! omit)
list.add(str.substring(lastIndex));
}
private static void SplitCharacter(java.lang.String str, int length,
java.util.ArrayList list, int maxCount,
bool omit, char[] anyOf)
{
int listCount = 0;
int lastIndex = -1;
for (int index = 0; index < length; index++)
{
if (! CharAtIsAnyOf(str, index, anyOf))
continue;
if (index == ++lastIndex && omit)
continue;
if (++listCount == maxCount)
{
list.add(str.substring(lastIndex));
return;
}
list.add(str.substring(lastIndex, index));
lastIndex = index;
}
if (length != ++lastIndex || ! omit)
list.add(str.substring(lastIndex));
}
private static void SplitString(java.lang.String str, int length,
java.util.ArrayList list, int maxCount,
bool omit, java.lang.String[] anyOfStr)
{
int anyOfNum = anyOfStr.Length;
char[] anyOfChar = new char[anyOfNum];
for (int index = 0; index < anyOfNum; index++)
{
var s = anyOfStr[index];
anyOfChar[index] =
(s != null && s.length() > 0) ? s.charAt(index) : '\0';
}
int listCount = 0;
int lastIndex = 0;
for (int index = 0; index < length; )
{
int len = StrAtIsAnyOf(str, index, anyOfNum, anyOfChar, anyOfStr);
if (len == -1)
index++;
else
{
if (index != lastIndex || ! omit)
{
if (++listCount == maxCount)
{
list.add(str.substring(lastIndex));
return;
}
list.add(str.substring(lastIndex, index));
}
lastIndex = (index += len);
}
}
return sb.ToString();
if (length != lastIndex || ! omit)
list.add(str.substring(lastIndex));
}
private static bool CharAtIsAnyOf(java.lang.String str, int idx, char[] anyOf)
{
char ch1 = str.charAt(idx);
foreach (var ch2 in anyOf)
if (ch2 == ch1)
return true;
return false;
}
private static int StrAtIsAnyOf(java.lang.String str, int idx, int anyOfNum,
char[] anyOfChar, java.lang.String[] anyOfStr)
{
char ch = str.charAt(idx);
for (int i = 0; i < anyOfNum; i++)
{
if (anyOfChar[i] == ch)
{
int len = anyOfStr[i].length();
if (str.regionMatches(idx, anyOfStr[i], 0, len))
return len;
}
}
return -1;
}
#endif
//
// Join
@ -208,6 +355,56 @@ namespace system
});
}
//
// Replace
//
public static string Replace(java.lang.String str, char oldChar, char newChar)
=> str.replace(oldChar, newChar);
public static string Replace(java.lang.String str, string oldStr, string newStr)
{
ThrowHelper.ThrowIfNull(oldStr);
int lenOld = ((java.lang.String) (object) oldStr).length();
if (lenOld == 0)
throw new System.ArgumentException();
int idx1 = str.indexOf(oldStr, 0);
if (idx1 == -1)
return (string) (object) str;
int idx0 = 0;
int len = str.length();
var sb = new java.lang.StringBuilder();
for (;;)
{
sb.append(str.substring(idx0, idx1));
if (newStr != null)
sb.append(newStr);
if ( (idx0 = idx1 + lenOld) >= len
|| (idx1 = str.indexOf(oldStr, idx0)) == -1)
{
sb.append(str.substring(idx0));
return sb.ToString();
}
}
}
//
// Copy
//
public static string Copy(java.lang.String str)
{
ThrowHelper.ThrowIfNull(str);
return java.lang.String.valueOf(str.toCharArray());
}
public static string Intern(java.lang.String str)
{
ThrowHelper.ThrowIfNull(str);
return str.intern();
}
//
// CopyTo
//
@ -215,8 +412,7 @@ namespace system
public static void CopyTo(java.lang.String str, int sourceIndex,
char[] destination, int destinationIndex, int count)
{
if (destination == null)
throw new System.ArgumentNullException();
ThrowHelper.ThrowIfNull(destination);
if ( count < 0 || sourceIndex < 0 || destinationIndex < 0
|| count > str.length() - sourceIndex
|| destinationIndex > destination.Length - count)
@ -276,6 +472,196 @@ namespace system
//
// CompareOrdinal
//
public static int CompareOrdinal(java.lang.String strA, java.lang.String strB)
{
if (object.ReferenceEquals(strA, strB))
return 0;
if (strA == null)
return -1;
if (strB == null)
return 1;
return strA.compareTo(strB);
}
public static int CompareOrdinal(java.lang.String strA, int indexA,
java.lang.String strB, int indexB, int length)
{
if (object.ReferenceEquals(strA, strB))
return 0;
if (strA == null)
return -1;
if (strB == null)
return 1;
int endIndexA, endIndexB;
if ( indexA < 0 || (endIndexA = indexA + length) > strA.length()
|| indexB < 0 || (endIndexB = indexB + length) > strB.length())
throw new System.ArgumentOutOfRangeException();
return ((java.lang.String) (object) strA.substring(indexA, endIndexA))
.compareTo((java.lang.String) (object) strB.substring(indexB, endIndexB));
}
//
// Compare without length
//
public static int Compare(string strA, string strB)
=> system.globalization.CompareInfo.CurrentCompareInfo.Compare(strA, strB,
System.Globalization.CompareOptions.None);
public static int Compare(string strA, string strB, bool ignoreCase)
=> system.globalization.CompareInfo.CurrentCompareInfo.Compare(strA, strB,
ignoreCase ? System.Globalization.CompareOptions.IgnoreCase
: System.Globalization.CompareOptions.None);
public static int Compare(string strA, string strB, System.StringComparison option)
{
var (compareInfo, compareOption) = StringComparisonToCompareArguments(option);
return compareInfo.Compare(strA, strB, compareOption);
}
public static int Compare(string strA, string strB,
bool ignoreCase, System.Globalization.CultureInfo culture)
=> culture.CompareInfo.Compare(strA, strB,
ignoreCase ? System.Globalization.CompareOptions.IgnoreCase
: System.Globalization.CompareOptions.None);
public static int Compare(string strA, string strB,
System.Globalization.CultureInfo culture,
System.Globalization.CompareOptions options)
=> culture.CompareInfo.Compare(strA, strB, options);
//
// Compare with length
//
public static int Compare(string strA, int indexA, string strB, int indexB, int length)
=> Compare(strA, indexA, strB, indexB, length,
system.globalization.CompareInfo.CurrentCompareInfo,
System.Globalization.CompareOptions.None);
public static int Compare(string strA, int indexA, string strB, int indexB, int length,
bool ignoreCase)
=> Compare(strA, indexA, strB, indexB, length,
system.globalization.CompareInfo.CurrentCompareInfo,
System.Globalization.CompareOptions.IgnoreCase);
public static int Compare(string strA, int indexA, string strB, int indexB, int length,
System.StringComparison comparisonType)
{
var (compareInfo, compareOption) = StringComparisonToCompareArguments(comparisonType);
return Compare(strA, indexA, strB, indexB, length, compareInfo, compareOption);
}
public static int Compare(string strA, int indexA, string strB, int indexB, int length,
bool ignoreCase, system.globalization.CultureInfo culture)
=> Compare(strA, indexA, strB, indexB, length, culture.CompareInfo,
ignoreCase ? System.Globalization.CompareOptions.IgnoreCase
: System.Globalization.CompareOptions.None);
public static int Compare(string strA, int indexA, string strB, int indexB, int length,
system.globalization.CultureInfo culture,
System.Globalization.CompareOptions options)
=> Compare(strA, indexA, strB, indexB, length, culture.CompareInfo, options);
private static int Compare(string strA, int indexA, string strB, int indexB, int length,
system.globalization.CompareInfo compareInfo,
System.Globalization.CompareOptions compareOptions)
{
int lengthA = length;
if (strA != null)
{
int maxlenA = ((java.lang.String) (object) strA).length() - indexA;
if (maxlenA < lengthA)
lengthA = maxlenA;
}
int lengthB = length;
if (strB != null)
{
int maxlenB = ((java.lang.String) (object) strB).length() - indexB;
if (maxlenB < lengthB)
lengthB = maxlenB;
}
return compareInfo.Compare(
strA, indexA, lengthA, strB, indexB, lengthB, compareOptions);
}
//
// IndexOfAny, LastIndexOfAny
//
public static int IndexOfAny(java.lang.String str, char[] anyOf)
=> InternalIndexOfAny(str, anyOf, 1, /* index */ true, 0,
/* count */ false, 0);
public static int IndexOfAny(java.lang.String str, char[] anyOf, int startIndex)
=> InternalIndexOfAny(str, anyOf, 1, /* index */ true, startIndex,
/* count */ false, 0);
public static int IndexOfAny(java.lang.String str, char[] anyOf, int startIndex, int count)
=> InternalIndexOfAny(str, anyOf, 1, /* index */ true, startIndex,
/* count */ true, count);
public static int LastIndexOfAny(java.lang.String str, char[] anyOf)
=> InternalIndexOfAny(str, anyOf, -1, /* index */ false, 0,
/* count */ false, 0);
public static int LastIndexOfAny(java.lang.String str, char[] anyOf, int startIndex)
=> InternalIndexOfAny(str, anyOf, -1, /* index */ true, startIndex,
/* count */ false, 0);
public static int LastIndexOfAny(java.lang.String str, char[] anyOf, int startIndex, int count)
=> InternalIndexOfAny(str, anyOf, -1, /* index */ true, startIndex,
/* count */ true, count);
private static int InternalIndexOfAny(java.lang.String str, char[] anyOf, int dir,
bool haveStartIndex, int startIndex,
bool haveCount, int count)
{
ThrowHelper.ThrowIfNull(anyOf);
int length = str.length();
if (haveCount && count < 0)
throw new System.ArgumentOutOfRangeException();
int endIndex;
if (dir == 1)
{
// IndexOfAny
endIndex = haveCount ? (startIndex + count) : length;
if (startIndex < 0 || endIndex > length)
throw new System.ArgumentOutOfRangeException();
}
else
{
// LastIndexOfAny
if (! haveStartIndex)
startIndex = length - 1;
endIndex = haveCount ? (startIndex - count + 1) : 0;
if (endIndex < 0 || startIndex >= length)
throw new System.ArgumentOutOfRangeException();
}
for (int index = startIndex; index != endIndex; index += dir)
{
if (CharAtIsAnyOf(str, index, anyOf))
return index;
}
return -1;
}
//
// IndexOf (char, ordinal)
//
@ -475,9 +861,6 @@ namespace system
//
// IndexOfAny
//
@ -501,18 +884,46 @@ namespace system
public static bool StartsWith(java.lang.String str, string pfx)
{
if (pfx == null)
throw new System.ArgumentNullException();
ThrowHelper.ThrowIfNull(pfx);
return str.startsWith(pfx);
}
public static bool EndsWith(java.lang.String str, string sfx)
{
if (sfx == null)
throw new System.ArgumentNullException();
ThrowHelper.ThrowIfNull(sfx);
return str.endsWith(sfx);
}
//
// Contains
//
public static bool Contains(java.lang.String large, char small)
=> large.indexOf(small, 0) >= 0;
public static bool Contains(java.lang.String large, string small)
=> large.indexOf(small, 0) >= 0;
public static bool Contains(string large, char small, System.StringComparison option)
{
var (compareInfo, compareOption) = StringComparisonToCompareArguments(option);
return system.globalization.CompareInfo.IndexOfChar(
large, small, 0, compareOption, compareInfo) >= 0;
}
public static bool Contains(string large, string small, System.StringComparison option)
{
var (compareInfo, compareOption) = StringComparisonToCompareArguments(option);
return system.globalization.CompareInfo.IndexOfString(
large, small, 0, compareOption, compareInfo) >= 0;
}
//
//
//
@ -521,6 +932,18 @@ namespace system
public static bool IsNullOrEmpty(java.lang.String str) => (str == null || str.length() == 0);
public static bool IsNullOrWhiteSpace(java.lang.String str)
{
if (str != null)
{
int n = str.length();
for (int i = 0; i < n; i++)
if (! Char.IsWhiteSpace(str.charAt(i)))
return false;
}
return true;
}
public static char[] ToCharArray(java.lang.String str) => str.toCharArray();
//
@ -582,28 +1005,74 @@ namespace system
public static object CreateWrapper(object maybeString, System.Type castToType)
{
if ( maybeString is java.lang.String
if ( maybeString is string reallyString
&& ( object.ReferenceEquals(castToType, cachedComparableString)
|| object.ReferenceEquals(castToType, cachedEquatableString)))
|| object.ReferenceEquals(castToType, cachedEquatableString)
|| object.ReferenceEquals(castToType, cachedIComparable)
|| object.ReferenceEquals(castToType, cachedIConvertible)))
{
return new Wrapper(maybeString);
return new Wrapper(reallyString);
}
return null;
}
[java.attr.RetainType] private static readonly System.Type cachedComparableString;
[java.attr.RetainType] private static readonly System.Type cachedEquatableString;
[java.attr.RetainType] private static readonly System.Type cachedIComparable;
[java.attr.RetainType] private static readonly System.Type cachedIConvertible;
class Wrapper : System.IComparable<string>, System.IEquatable<string>
class Wrapper : System.IComparable<string>, System.IEquatable<string>,
System.IComparable, System.IConvertible
{
[java.attr.RetainType] private java.lang.String str;
public Wrapper(object _s) => str = (java.lang.String) (object) _s;
// CompareTo implementation is wrong, should be culture sensitive
[java.attr.RetainType] private string str;
public Wrapper(string _s) => str = _s;
// generic CompareTo implementation is culture sensitive
public int CompareTo(string other)
=> str.compareTo((java.lang.String) (object) other);
=> system.String.Compare(str, other);
// Equals is not sensitive to culture or case
public bool Equals(string other)
=> str.@equals((java.lang.String) (object) other);
=> ((java.lang.String) (object) str).@equals(
(java.lang.String) (object) other);
// non-generic CompareTo implementation is culture sensitive
public int CompareTo(object other)
{
return (other is string ostr) ? system.String.Compare(str, ostr)
: (other == null) ? 1
: throw new System.ArgumentException();
}
// IConvertible
public string ToString(System.IFormatProvider provider) => str;
public System.TypeCode GetTypeCode() => System.TypeCode.String;
bool System.IConvertible.ToBoolean(System.IFormatProvider provider)
=> System.Convert.ToBoolean(str, provider);
char System.IConvertible.ToChar(System.IFormatProvider provider)
=> System.Convert.ToChar(str, provider);
sbyte System.IConvertible.ToSByte(System.IFormatProvider provider)
=> System.Convert.ToSByte(str, provider);
byte System.IConvertible.ToByte(System.IFormatProvider provider)
=> System.Convert.ToByte(str, provider);
short System.IConvertible.ToInt16(System.IFormatProvider provider)
=> System.Convert.ToInt16(str, provider);
ushort System.IConvertible.ToUInt16(System.IFormatProvider provider)
=> System.Convert.ToUInt16(str, provider);
int System.IConvertible.ToInt32(System.IFormatProvider provider)
=> System.Convert.ToInt16(str, provider);
uint System.IConvertible.ToUInt32(System.IFormatProvider provider)
=> System.Convert.ToUInt32(str, provider);
long System.IConvertible.ToInt64(System.IFormatProvider provider)
=> System.Convert.ToInt64(str, provider);
ulong System.IConvertible.ToUInt64(System.IFormatProvider provider)
=> System.Convert.ToUInt64(str, provider);
float System.IConvertible.ToSingle(System.IFormatProvider provider)
=> System.Convert.ToSingle(str, provider);
double System.IConvertible.ToDouble(System.IFormatProvider provider)
=> System.Convert.ToDouble(str, provider);
System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider)
=> System.Convert.ToDecimal(str, provider);
System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider)
=> System.Convert.ToDateTime(str, provider);
object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider)
=> system.Convert.DefaultToType((System.IConvertible) this, type, provider);
}
@ -623,6 +1092,8 @@ namespace system
cachedComparableString = typeof(System.IComparable<string>);
cachedEquatableString = typeof(System.IEquatable<string>);
cachedIComparable = typeof(System.IComparable);
cachedIConvertible = typeof(System.IConvertible);
}
}
@ -661,8 +1132,12 @@ namespace java.lang
public abstract string toUpperCase(java.util.Locale locale);
public abstract string toLowerCase(java.util.Locale locale);
public abstract int compareTo(java.lang.String other);
public abstract int compareToIgnoreCase(java.lang.String other);
public abstract bool equals(java.lang.String other);
public abstract string intern();
public abstract string replace(char oldChar, char newChar);
[java.attr.Discard] extern public static string format(string fmt, object[] args);
[java.attr.Discard] extern public static string valueOf(char c);
[java.attr.Discard] extern public static string valueOf(char[] data);
}
}

View File

@ -15,7 +15,7 @@ namespace system.text.regularexpressions
groupCollection = new GroupCollection(this, matcher, input);
}
private Match() : base(0, "", 0, 0)
private Match() : base(-1, "", -1, -1)
{
groupCollection = new GroupCollection(this, null, null);
}

View File

@ -16,6 +16,49 @@ namespace system.text.regularexpressions
JavaPattern = java.util.regex.Pattern.compile(pattern);
}
public Regex(string pattern, System.Text.RegularExpressions.RegexOptions options)
{
int flags = 0;
if ((options & System.Text.RegularExpressions.RegexOptions.CultureInvariant) != 0)
options &= ~System.Text.RegularExpressions.RegexOptions.CultureInvariant;
else
{
flags |= java.util.regex.Pattern.UNICODE_CASE
| java.util.regex.Pattern.CANON_EQ;
}
if ((options & System.Text.RegularExpressions.RegexOptions.IgnoreCase) != 0)
{
options &= ~System.Text.RegularExpressions.RegexOptions.IgnoreCase;
flags |= java.util.regex.Pattern.CASE_INSENSITIVE;
}
if ((options & System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace) != 0)
{
options &= ~System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace;
flags |= java.util.regex.Pattern.COMMENTS;
}
if ((options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0)
{
options &= ~System.Text.RegularExpressions.RegexOptions.Multiline;
flags |= java.util.regex.Pattern.MULTILINE;
}
if ((options & System.Text.RegularExpressions.RegexOptions.Singleline) != 0)
{
options &= ~System.Text.RegularExpressions.RegexOptions.Singleline;
flags |= java.util.regex.Pattern.DOTALL;
}
options &= ~System.Text.RegularExpressions.RegexOptions.Compiled;
if (options != 0)
throw new System.ArgumentOutOfRangeException();
JavaPattern = java.util.regex.Pattern.compile(pattern);
}
//
// Match
//
@ -35,6 +78,50 @@ namespace system.text.regularexpressions
public static MatchCollection Matches(string input, string pattern)
=> new Regex(pattern).Matches(input);
//
// IsMatch
//
public bool IsMatch(string input)
=> Match(input).Success;
//
// Escape
//
public static string Escape(string str)
{
int idx1 = str.IndexOfAny(EscapeChars);
if (idx1 == -1)
return str;
int idx0 = 0;
int len = ((java.lang.String) (object) str).length();
var sb = new java.lang.StringBuilder();
for (;;)
{
sb.append(((java.lang.String) (object) str).substring(idx0, idx1));
sb.append('\\');
var ch = ((java.lang.String) (object) str).charAt(idx1);
if (ch == '\u0009') ch = 't';
else if (ch == '\u000A') ch = 'n';
else if (ch == '\u000C') ch = 'f';
else if (ch == '\u000D') ch = 'r';
sb.append(ch);
if ( (idx0 = idx1 + 1) >= len
|| (idx1 = str.IndexOfAny(EscapeChars, idx0)) == -1)
{
sb.append(((java.lang.String) (object) str).substring(idx0));
return sb.ToString();
}
}
}
[java.attr.RetainType] private static readonly char[] EscapeChars = {
'\u0009', '\u000A', '\u000C', '\u000D', '\u0020', // spaces
'#', '$', '(', ')', '*', '+', '.', '?', '[', '\\', '^', '{', '|' };
// |{^\[?.+*)($# SPC(32)TAB(9)0x000D,0x000C, 0x000A,0x0009
//
// ISerializable
//

View File

@ -4,3 +4,5 @@ System.Collections.Generic.Stack`1
System.Collections.Generic.Queue`1
System.ComponentModel.CategoryAttribute
System.Text.RegularExpressions.RegexOptions

View File

@ -644,6 +644,29 @@ namespace SpaceFlint.CilToJava
public static void FixNameForVirtualToStaticCall(JavaMethodRef method, CilType callClass)
{
// this method is called from CodeCall.ConvertVirtualToStaticCall,
// which converts a virtual call to a static call by inserting an
// initial 'this' parameter.
// if the target method was altered by AppendMethodNameSuffix,
// then we also have to insert the name for that initial 'this'.
string name = method.Name;
int idx = name.IndexOf(CilMain.OPEN_PARENS);
if (idx != -1)
{
string newName = name.Substring(0, idx)
+ CilMain.OPEN_PARENS
+ callClass.JavaName.Replace('.', '-')
+ CilMain.CLOSE_PARENS
+ name.Substring(idx);
method.Name = newName;
}
}
internal static bool CompareMethods(MethodDefinition m1, MethodDefinition m2)
{
if (m1.Name != m2.Name)

View File

@ -272,7 +272,8 @@ namespace SpaceFlint.CilToJava
else
{
if ( elemType.PrimitiveType == TypeCode.Int16
&& arrayType.PrimitiveType == TypeCode.Char)
&& ( arrayType.PrimitiveType == TypeCode.Char
|| arrayType.PrimitiveType == TypeCode.UInt16))
{
// ldelem.i2 with a char[] array, should be 'caload' not 'saload'
elemType = arrayType.AdjustRank(-arrayType.ArrayRank);
@ -358,7 +359,8 @@ namespace SpaceFlint.CilToJava
else
{
if ( elemType.PrimitiveType == TypeCode.Int16
&& arrayType.PrimitiveType == TypeCode.Char)
&& ( arrayType.PrimitiveType == TypeCode.Char
|| arrayType.PrimitiveType == TypeCode.UInt16))
{
// stelem.i2 with a char[] array, should be 'castore' not 'sastore'
elemType = arrayType.AdjustRank(-arrayType.ArrayRank);

View File

@ -398,6 +398,9 @@ namespace SpaceFlint.CilToJava
parameters[0].Type = JavaType.ObjectType;
}
else
CilMethod.FixNameForVirtualToStaticCall(tempMethod, callClass);
code.NewInstruction(0xB8 /* invokestatic */,
new JavaType(0, 0, callClass.JavaName), tempMethod);

View File

@ -748,9 +748,15 @@ namespace SpaceFlint.CilToJava
}
}
}
else
stackMap.ResetLocalsInFrame((ushort) inst.Offset, resetLocals);
if (inst.OpCode.Code >= Code.Ceq && inst.OpCode.Code <= Code.Clt_Un)
{
stackMap.ResetLocalsInFrame((ushort) inst.Offset, resetLocals);
// also reset the additional frame created while processing
// 'ceq'-type instructions, see also method Compare() above
stackMap.ResetLocalsInFrame(
(ushort) (inst.Offset + 1), resetLocals);
}
inst = inst.Next;

View File

@ -267,12 +267,22 @@ namespace SpaceFlint.CilToJava
{
var dataType = CilType.From(typeRef);
var stackTop1 = (CilType) code.StackMap.PopStack(CilMain.Where);
var stackTop2 = (CilType) code.StackMap.PopStack(CilMain.Where);
if (CodeSpan.LoadStore(false, stackTop2, null, dataType, code))
var valueType = (CilType) code.StackMap.PopStack(CilMain.Where);
var intoType = (CilType) code.StackMap.PopStack(CilMain.Where);
if (CodeSpan.LoadStore(false, intoType, null, dataType, code))
return;
code.StackMap.PushStack(stackTop2);
code.StackMap.PushStack(stackTop1);
if ( (! dataType.IsReference)
&& intoType is BoxedType intoBoxedType
&& dataType.PrimitiveType == intoBoxedType.UnboxedType.PrimitiveType)
{
// 'stobj primitive' with a primitive value on the stack
intoBoxedType.SetValueOV(code);
return;
}
code.StackMap.PushStack(intoType);
code.StackMap.PushStack(valueType);
GenericUtil.ValueCopy(dataType, code, true);
code.StackMap.PopStack(CilMain.Where);

View File

@ -768,13 +768,25 @@ namespace SpaceFlint.CilToJava
if (fromType.Equals(intoType))
return false; // no, if same type (by value)
// if casting to one of the non-generic types of that a string
// implements, and the source is either a string or an object
bool fromTypeIsObjectType = fromType.Equals(JavaType.ObjectType);
if ( (fromTypeIsObjectType || fromType.Equals(JavaType.StringType))
&& ( intoType.JavaName == "system.IComparable"
|| intoType.JavaName == "system.IConvertible"))
{
return true;
}
// if casting to one of the types that any array should implememt,
// and the castee is an array, or 'object', or one of those types,
// then always call TestCast/CallCast, because we might have to
// create a helper proxy for an array object
bool fromTypeMayBeArray = ( fromType.ArrayRank != 0
|| fromType.Equals(JavaType.ObjectType)
bool fromTypeMayBeArray = ( fromTypeIsObjectType
|| fromType.ArrayRank != 0
|| IsArray(fromType.JavaName));
return (fromTypeMayBeArray && IsArray(intoType.JavaName));

View File

@ -6,19 +6,102 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Tests
{
[TestClass]
public class TestCompareInfo : BaseTest
public class TestString : BaseTest
{
public override void TestMain()
{
TestIndexOf1();
TestSplit();
TestIndexOf();
TestCompare();
TestCast("Test");
}
//
//
//
static void TestIndexOf1()
void TestSplit()
{
// This example demonstrates the String() methods that use
// the StringSplitOptions enumeration.
string s1 = ",ONE,,TWO,,,THREE,,";
string s2 = "[stop]" +
"ONE[stop][stop]" +
"TWO[stop][stop][stop]" +
"THREE[stop][stop]";
char[] charSeparators = new char[] {','};
string[] stringSeparators = new string[] {"[stop]"};
string[] result;
// ------------------------------------------------------------------------------
// Split a string delimited by characters.
// ------------------------------------------------------------------------------
// Display the original string and delimiter characters.
Console.WriteLine("String = \"{0}\" Delimiter = '{1}'", s1, charSeparators[0]);
// Split a string delimited by characters and return all elements.
Console.Write("Split by char, omit=0: ");
result = s1.Split(charSeparators, StringSplitOptions.None);
Show(result);
// Split a string delimited by characters and return all non-empty elements.
Console.Write("Split by char, omit=1: ");
result = s1.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
Show(result);
// Split the original string into the string and empty string before the
// delimiter and the remainder of the original string after the delimiter.
Console.Write("Split by char, omit=0, lim=2: ");
result = s1.Split(charSeparators, 2, StringSplitOptions.None);
Show(result);
// Split the original string into the string after the delimiter and the
// remainder of the original string after the delimiter.
Console.Write("Split by char, omit=1, lim=2: ");
result = s1.Split(charSeparators, 2, StringSplitOptions.RemoveEmptyEntries);
Show(result);
// ------------------------------------------------------------------------------
// Split a string delimited by another string.
// ------------------------------------------------------------------------------
// Display the original string and delimiter string.
Console.WriteLine("String = \"{0}\" Delimiter = \"{1}\"", s2, stringSeparators[0]);
// Split a string delimited by another string and return all elements.
Console.Write("Split by str, omit=0: ");
result = s2.Split(stringSeparators, StringSplitOptions.None);
Show(result);
// Split the original string at the delimiter and return all non-empty elements.
Console.Write("Split by str, omit=1: ");
result = s2.Split(stringSeparators, StringSplitOptions.RemoveEmptyEntries);
Show(result);
// Split the original string into the empty string before the
// delimiter and the remainder of the original string after the delimiter.
Console.Write("Split by str, omit=0, lim=2: ");
result = s2.Split(stringSeparators, 2, StringSplitOptions.None);
Show(result);
// Split the original string into the string after the delimiter and the
// remainder of the original string after the delimiter.
Console.Write("Split by str, omit=1, lim=2: ");
result = s2.Split(stringSeparators, 2, StringSplitOptions.RemoveEmptyEntries);
Show(result);
// Display the array of separated strings using a local function
void Show(string[] entries)
{
Console.Write("{0} results: ", entries.Length);
foreach (string entry in entries)
{
Console.Write("<{0}>", entry);
}
Console.WriteLine();
}
}
static void TestIndexOf()
{
// based on examples in documentation page for
// System.Globalization.CompareInfo.IndexOf methods
@ -109,14 +192,44 @@ namespace Tests
PrintMarker( " Ü : ", -1, myComp.LastIndexOf( myStr, 'Ü', iS, CompareOptions.IgnoreCase ) );
PrintMarker( " ü : ", -1, myComp.LastIndexOf( myStr, 'ü', iS, CompareOptions.IgnoreCase ) );
Console.WriteLine();
static void PrintMarker( String Prefix, int First, int Last ) {
if (First > -1) Console.Write($"\t\tFirst({First})");
if (Last > -1) Console.Write($"\t\tLast({First})");
if (First < 0 && Last < 0)
Console.Write($"\t\tNone\t");
}
}
public static void PrintMarker( String Prefix, int First, int Last ) {
if (First > -1) Console.Write($"\t\tFirst({First})");
if (Last > -1) Console.Write($"\t\tLast({First})");
if (First < 0 && Last < 0)
Console.Write($"\t\tNone\t");
void TestCompare()
{
// Defines the strings to compare.
String myStr1 = "My Uncle Bill's clients";
String myStr2 = "My uncle bill's clients";
// Creates a CompareInfo that uses the InvariantCulture.
CompareInfo myComp = CultureInfo.InvariantCulture.CompareInfo;
// Compares two strings using myComp.
Console.WriteLine( "Comparing \"{0}\" and \"{1}\"", myStr1, myStr2 );
Console.WriteLine( " With no CompareOptions : {0}", myComp.Compare( myStr1, myStr2 ) );
Console.WriteLine( " With None : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.None ) );
Console.WriteLine( " With Ordinal : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.Ordinal ) );
//Console.WriteLine( " With StringSort : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.StringSort ) );
Console.WriteLine( " With IgnoreCase : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.IgnoreCase ) );
//Console.WriteLine( " With IgnoreSymbols : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.IgnoreSymbols ) );
//Console.WriteLine( " With IgnoreCase and IgnoreSymbols : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols ) );
}
void TestCast(object str)
{
Console.WriteLine("Convertible? " + ((str as IConvertible) != null)
+ " Comparable? " + ((str as IComparable) != null));
}
}
}

View File

@ -93,5 +93,3 @@ Here are some known differences, deficiencies and incompatibilities of the Blueb
- Standard numeric format strings are supported, but a custom format, or an `IFormatProvider` which also implements `NumberFormatInfo` will cause `ToString` functions to throw an exception.
- Non-ordinal, culture-dependant string comparisons and casing are not 100% same, because of differences between Windows NLS and the `java.text` package.
- `String` is not castable to `IConvertible` or to the non-generic `IComparable` interface.