ソースを参照

[java/cs] More unit tests fixes - Java target ok on unit tests

Caue Waneck 12 年 前
コミット
4e5f9bfe7d

+ 2 - 1
genjava.ml

@@ -156,9 +156,10 @@ struct
         | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "isNaN"}) ) ->
           mk_static_field_access_infer float_cl "_isNaN" e.epos []
         | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("ffloor" as f) }) ) } as fe), p)
-        | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("fround" as f) }) ) } as fe), p)
         | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("fceil" as f) }) ) } as fe), p) ->
             Type.map_expr run { e with eexpr = TCall({ fe with eexpr = TField(ef, FDynamic (String.sub f 1 (String.length f - 1)))  }, p) }
+        | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("fround") }) ) } as fe), p) ->
+            Type.map_expr run { e with eexpr = TCall({ fe with eexpr = TField(ef, FDynamic "rint")  }, p) }
         | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "floor" }) ) }, _)
         | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "round" }) ) }, _)
         | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "ceil" }) ) }, _) ->

+ 38 - 35
std/StringTools.hx

@@ -22,7 +22,7 @@
 /**
 	This class provides advanced methods on Strings. It is ideally used with
 	'using StringTools' and then acts as an extension to the String class.
-	
+
 	If the first argument to any of the methods is null, the result is
 	unspecified.
 **/
@@ -83,7 +83,7 @@ class StringTools {
 
 	/**
 		Escapes HTML special characters of the string [s].
-		
+
 		The following replacements are made:
 			- & becomes &
 			- < becomes &lt;
@@ -99,10 +99,10 @@ class StringTools {
 
 	/**
 		Unescapes HTML special characters of the string [s].
-		
+
 		This is the inverse operation to htmlEscape, i.e. the following always
 		holds: htmlUnescape(htmlEscape(s)) == s
-		
+
 		The replacements follow:
 			- &amp; becomes &
 			- &lt; becomes <
@@ -116,9 +116,9 @@ class StringTools {
 
 	/**
 		Tells if the string [s] starts with the string [start].
-		
+
 		If [start] is null, the result is unspecified.
-		
+
 		If [start] is the empty String "", the result is true.
 	**/
 	public static #if (cs || java) inline #end function startsWith( s : String, start : String ) : Bool {
@@ -133,9 +133,9 @@ class StringTools {
 
 	/**
 		Tells if the string [s] ends with the string [end].
-		
+
 		If [end] is null, the result is unspecified.
-		
+
 		If [end] is the empty String "", the result is true.
 	**/
 	public static #if (cs || java) inline #end function endsWith( s : String, end : String ) : Bool {
@@ -152,10 +152,10 @@ class StringTools {
 
 	/**
 		Tells if the character in the string [s] at position [pos] is a space.
-		
+
 		A character is considered to be a space character if its character code
 		is 9,10,11,12,13 or 32.
-		
+
 		If [s] is the empty String "", or if pos is not a valid position within
 		[s], the result is false.
 	**/
@@ -166,10 +166,10 @@ class StringTools {
 
 	/**
 		Removes leading space characters of [s].
-		
+
 		This function internally calls isSpace() to decide which characters to
 		remove.
-		
+
 		If [s] is the empty String "" or consists only of space characters, the
 		result is the empty String "".
 	**/
@@ -191,10 +191,10 @@ class StringTools {
 
 	/**
 		Removes trailing space characters of [s].
-		
+
 		This function internally calls isSpace() to decide which characters to
 		remove.
-		
+
 		If [s] is the empty String "" or consists only of space characters, the
 		result is the empty String "".
 	**/
@@ -217,7 +217,7 @@ class StringTools {
 
 	/**
 		Removes leading and trailing space characters of [s].
-		
+
 		This is a convenience function for ltrim(rtrim(s)).
 	**/
 	public #if (cs || java) inline #end static function trim( s : String ) : String {
@@ -229,23 +229,23 @@ class StringTools {
 		return ltrim(rtrim(s));
 		#end
 	}
-	
+
 	/**
 		Concatenates [c] to [s] until [s].length is at least [l].
-		
+
 		If [c] is the empty String "" or if [l] does not exceed [s].length,
 		[s] is returned unchanged.
-		
+
 		If [c].length is 1, the resulting String length is exactly [l].
-		
+
 		Otherwise the length may exceed [l].
-		
+
 		If [c] is null, the result is unspecified.
 	**/
 	public static function lpad( s : String, c : String, l : Int ) : String {
 		if (c.length <= 0)
 			return s;
-			
+
 		while (s.length < l) {
 			s = c + s;
 		}
@@ -254,20 +254,20 @@ class StringTools {
 
 	/**
 		Appends [c] to [s] until [s].length is at least [l].
-		
+
 		If [c] is the empty String "" or if [l] does not exceed [s].length,
 		[s] is returned unchanged.
-		
+
 		If [c].length is 1, the resulting String length is exactly [l].
-		
+
 		Otherwise the length may exceed [l].
-		
+
 		If [c] is null, the result is unspecified.
 	**/
 	public static function rpad( s : String, c : String, l : Int ) : String {
 		if (c.length <= 0)
 			return s;
-			
+
 		while (s.length < l) {
 			s = s + c;
 		}
@@ -277,17 +277,20 @@ class StringTools {
 	/**
 		Replace all occurences of the String [sub] in the String [s] by the
 		String [by].
-		
+
 		If [sub] is the empty String "", [by] is inserted after each character
 		of [s]. If [by] is also the empty String "", [s] remains unchanged.
-		
+
 		This is a convenience function for [s].split([sub]).join([by]).
-		
+
 		If [sub] or [by] are null, the result is unspecified.
 	**/
-	public #if (java || cs) inline #end static function replace( s : String, sub : String, by : String ) : String {
+	public #if cs inline #end static function replace( s : String, sub : String, by : String ) : String {
 		#if java
-		return untyped s.replace(sub, by);
+		if (sub.length == 0)
+			return s.split(sub).join(by);
+		else
+			return untyped s.replace(sub, by);
 		#elseif cs
 		return untyped s.Replace(sub, by);
 		#else
@@ -297,7 +300,7 @@ class StringTools {
 
 	/**
 		Encodes [n] into a hexadecimal representation.
-		
+
 		If [digits] is specified, the resulting String is padded with "0" until
 		its length equals [digits].
 	**/
@@ -322,11 +325,11 @@ class StringTools {
 
 	/**
 		Returns the character code at position [index] of String [s].
-		
+
 		This method is faster than String.charCodeAt() on most platforms.
 		However, unlike String.charCodeAt(), the result is unspecified if
 		[index] is negative or exceeds [s].length.
-		
+
 		This operation is not guaranteed to work if [s] contains the \0
 		character. The method isEof() can be used to check for that.
 	**/
@@ -378,7 +381,7 @@ class StringTools {
 	#if java
 	private static inline function _charAt(str:String, idx:Int):java.StdTypes.Char16 return untyped str._charAt(idx);
 	#end
-	
+
 	#if neko
 	private static var _urlEncode = neko.Lib.load("std","url_encode",1);
 	private static var _urlDecode = neko.Lib.load("std","url_decode",1);

+ 2 - 2
std/cs/_std/Array.hx

@@ -154,7 +154,7 @@ import cs.NativeArray;
 		}
 
 		__a[length] = x;
-		return length++;
+		return ++length;
 	}
 
 	/**
@@ -419,7 +419,7 @@ import cs.NativeArray;
 
 		return false;
 	}
-	
+
 	public function map<S>( f : T -> S ) : Array<S> {
 		var ret = [];
 		for (elt in this)

+ 62 - 6
std/cs/_std/EReg.hx

@@ -70,7 +70,7 @@ import cs.system.text.regularExpressions.Regex;
 	}
 
 	public function matchedPos() : { pos : Int, len : Int } {
-		return { pos : sub +  m.Index, len : m.Length };
+		return { pos : sub + m.Index, len : m.Length };
 	}
 
 	public function matchSub( s : String, pos : Int, len : Int = -1):Bool {
@@ -88,11 +88,67 @@ import cs.system.text.regularExpressions.Regex;
 		return untyped [s.Substring(0, m.Index), s.Substring(m.Index + m.Length)];
 	}
 
-	public function replace( s : String, by : String ) : String {
-		if (isGlobal)
-			return regex.Replace(s, by);
-		var m = regex.Match(s);
-		return untyped (s.Substring(0, m.Index) + by + s.Substring(m.Index + m.Length));
+	inline function start(group:Int)
+	{
+		return m.Groups[group].Index + sub;
+	}
+
+	inline function len(group:Int)
+	{
+		return m.Groups[group].Length;
+	}
+
+	public function replace( s : String, by : String ) : String
+	{
+      var b = new StringBuf();
+      var pos = 0;
+      var len = s.length;
+      var a = by.split("$");
+      var first = true;
+      do {
+        if( !matchSub(s,pos,len) )
+          break;
+        var p = matchedPos();
+        if( p.len == 0 && !first ) {
+          if( p.pos == s.length )
+            break;
+          p.pos += 1;
+        }
+        b.addSub(s,pos,p.pos-pos);
+        if( a.length > 0 )
+          b.add(a[0]);
+        var i = 1;
+        while( i < a.length ) {
+          var k = a[i];
+          var c = k.charCodeAt(0);
+          // 1...9
+          if( c >= 49 && c <= 57 ) {
+						try {
+							var ppos = start( c-48 ), plen = this.len( c-48 );
+							b.addSub(s, ppos, plen);
+						}
+						catch(e:Dynamic)
+						{
+							b.add("$");
+							b.add(k);
+						}
+          } else if( c == null ) {
+            b.add("$");
+            i++;
+            var k2 = a[i];
+            if( k2 != null && k2.length > 0 )
+              b.add(k2);
+          } else
+            b.add("$"+k);
+          i++;
+        }
+        var tot = p.pos + p.len - pos;
+        pos += tot;
+        len -= tot;
+        first = false;
+      } while( isGlobal );
+      b.addSub(s,pos,len);
+      return b.toString();
 	}
 
 	public function map( s : String, f : EReg -> String ) : String {

+ 7 - 1
std/cs/_std/Type.hx

@@ -159,7 +159,13 @@ import cs.internal.Runtime;
 		}
 	}
 
-
+	@:functionCode('
+		if (name == "Bool") return typeof(bool);
+		System.Type t = resolveClass(name);
+		if (t != null && (t.BaseType.Equals(typeof(System.Enum)) || t.BaseType.Equals(haxe.lang.Enum)))
+			return t;
+		return null;
+	')
 	public static function resolveEnum( name : String ) : Enum<Dynamic> untyped
 	{
 		if (name == "Bool") return Bool;

+ 1 - 1
std/cs/internal/StringExt.hx

@@ -28,7 +28,7 @@ private typedef NativeString = String;
 
 	@:functionCode('
 			if ( ((uint) index) >= me.Length)
-				return null;
+				return "";
 			else
 				return new string(me[index], 1);
 	')

+ 2 - 2
std/java/_std/Array.hx

@@ -158,7 +158,7 @@ import java.NativeArray;
 		}
 
 		__a[length] = x;
-		return this.length++;
+		return ++this.length;
 	}
 
 	/**
@@ -450,7 +450,7 @@ import java.NativeArray;
 			next:function() return __a[i++]
 		};
 	}
-	
+
 	public function map<S>( f : T -> S ) : Array<S> {
 		var ret = [];
 		for (elt in this)

+ 62 - 17
std/java/_std/EReg.hx

@@ -50,8 +50,7 @@ import java.util.regex.Regex;
 	Strings. Have a look at the tutorial on haXe website to learn
 	how to use them.
 **/
-@:coreApi
-class EReg {
+@:coreType class EReg {
 
 	private var pattern:String;
 	private var matcher:Matcher;
@@ -199,21 +198,67 @@ class EReg {
 		}
 	}
 
-	/**
-		Replaces a pattern by another string. The [by] format can
-		contains [$1] to [$9] that will correspond to groups matched
-		while replacing. [$$] means the [$] character.
-	**/
-	public function replace( s : String, by : String ) : String {
-		var matcher = matcher;
-		matcher.reset(s);
-		if (isGlobal)
-		{
-			return matcher.replaceAll(by);
-		} else {
-			matcher.find();
-			return untyped (s.substring(0, matcher.start()) + by + s.substring(matcher.end(), s.length));
-		}
+	inline function start(group:Int)
+	{
+		return matcher.start(group) + sub;
+	}
+
+	inline function len(group:Int)
+	{
+		return matcher.end(group) - matcher.start(group);
+	}
+
+	public function replace( s : String, by : String ) : String
+	{
+      var b = new StringBuf();
+      var pos = 0;
+      var len = s.length;
+      var a = by.split("$");
+      var first = true;
+      do {
+        if( !matchSub(s,pos,len) )
+          break;
+        var p = matchedPos();
+        if( p.len == 0 && !first ) {
+          if( p.pos == s.length )
+            break;
+          p.pos += 1;
+        }
+        b.addSub(s,pos,p.pos-pos);
+        if( a.length > 0 )
+          b.add(a[0]);
+        var i = 1;
+        while( i < a.length ) {
+          var k = a[i];
+          var c = k.charCodeAt(0);
+          // 1...9
+          if( c >= 49 && c <= 57 ) {
+						try {
+							var ppos = start( c-48 ), plen = this.len( c-48 );
+							b.addSub(s, ppos, plen);
+						}
+						catch(e:Dynamic)
+						{
+							b.add("$");
+							b.add(k);
+						}
+          } else if( c == null ) {
+            b.add("$");
+            i++;
+            var k2 = a[i];
+            if( k2 != null && k2.length > 0 )
+              b.add(k2);
+          } else
+            b.add("$"+k);
+          i++;
+        }
+        var tot = p.pos + p.len - pos;
+        pos += tot;
+        len -= tot;
+        first = false;
+      } while( isGlobal );
+      b.addSub(s,pos,len);
+      return b.toString();
 	}
 
 	/**

+ 1 - 1
std/java/_std/Std.hx

@@ -53,7 +53,7 @@ import java.internal.Exceptions;
 	}
 
 	public static function string( s : Dynamic ) : String {
-		return cast s;
+		return cast(s, String) + "";
 	}
 
 	public static inline function int( x : Float ) : Int {

+ 7 - 0
std/java/_std/Type.hx

@@ -116,6 +116,13 @@
 	}
 
 
+	@:functionCode('
+		if ("Bool".equals(name)) return boolean.class;
+		Class r = resolveClass(name);
+		if (r != null && (r.getSuperclass() == java.lang.Enum.class || r.getSuperclass() == haxe.lang.Enum.class))
+			return r;
+		return null;
+	')
 	public static function resolveEnum( name : String ) : Enum<Dynamic> untyped
 	{
 		if (name == "Bool") return Bool;

+ 222 - 28
std/java/internal/StringExt.hx

@@ -19,40 +19,234 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-package java.internal;
import java.internal.Function;

private typedef NativeString = String;

@:keep @:nativeGen @:native("haxe.lang.StringExt") private class StringExt
-{

	@:functionCode('
-			if ( index >= me.length() || index < 0 )
				return null;
			else
				return java.lang.Character.toString(me.charAt(index));
	')
	public static function charAt(me:NativeString, index:Int):NativeString
	{
		return null;
	}
+package java.internal;
+import java.internal.Function;
+
+private typedef NativeString = String;
+
+@:keep @:nativeGen @:native("haxe.lang.StringExt") private class StringExt
+{
+
 	@:functionCode('
-			if ( index >= me.length() || index < 0 )
				return null;
			else
				return me.codePointAt(index);
	')
	public static function charCodeAt(me:NativeString, index:Int):Null<Int>
	{
		return null;
	}
+			if ( index >= me.length() || index < 0 )
+				return "";
+			else
+				return java.lang.Character.toString(me.charAt(index));
+	')
+	public static function charAt(me:NativeString, index:Int):NativeString
+	{
+		return null;
+	}
+
 	@:functionCode('
-			int sIndex = (startIndex != null ) ? (haxe.lang.Runtime.toInt(startIndex)) : 0;
			if (sIndex >= me.length() || sIndex < 0)
				return -1;
			return me.indexOf(str, sIndex);
	')
	public static function indexOf(me:NativeString, str:NativeString, ?startIndex:Int):Int
	{
		return -1;
	}
+			if ( index >= me.length() || index < 0 )
+				return null;
+			else
+				return me.codePointAt(index);
+	')
+	public static function charCodeAt(me:NativeString, index:Int):Null<Int>
+	{
+		return null;
+	}
+
 	@:functionCode('
-			int sIndex = (startIndex != null ) ? (haxe.lang.Runtime.toInt(startIndex)) : (me.length() - 1);
			if (sIndex > me.length() || sIndex < 0)
				sIndex = me.length() - 1;
			else if (sIndex < 0)
				return -1;
			return me.lastIndexOf(str, sIndex);
	')
	public static function lastIndexOf(me:NativeString, str:NativeString, ?startIndex:Int):Int
	{
		return -1;
	}
+			int sIndex = (startIndex != null ) ? (haxe.lang.Runtime.toInt(startIndex)) : 0;
+			if (sIndex >= me.length() || sIndex < 0)
+				return -1;
+			return me.indexOf(str, sIndex);
+	')
+	public static function indexOf(me:NativeString, str:NativeString, ?startIndex:Int):Int
+	{
+		return -1;
+	}
+
 	@:functionCode('
-			Array<java.lang.String> ret = new Array<java.lang.String>();
-			int slen = delimiter.length();
			if (slen == 0)
			{
				int len = me.length();
				for (int i = 0; i < len; i++)
				{
					ret.push(me.substring(i, i + 1));
				}
			} else {
				int start = 0;
				int pos = me.indexOf(delimiter, start);
-				while (pos >= 0)
				{
					ret.push(me.substring(start, pos));
-					start = pos + slen;
					pos = me.indexOf(delimiter, start);
				}
-				ret.push(me.substring(start));
			}
			return ret;
	')
	public static function split(me:NativeString, delimiter:NativeString):Array<NativeString>
	{
		return null;
	}
+			int sIndex = (startIndex != null ) ? (haxe.lang.Runtime.toInt(startIndex)) : (me.length() - 1);
+			if (sIndex > me.length() || sIndex < 0)
+				sIndex = me.length() - 1;
+			else if (sIndex < 0)
+				return -1;
+			return me.lastIndexOf(str, sIndex);
+	')
+	public static function lastIndexOf(me:NativeString, str:NativeString, ?startIndex:Int):Int
+	{
+		return -1;
+	}
+
 	@:functionCode('
-			int meLen = me.length();
			int targetLen = meLen;
			if (len != null)
			{
				targetLen = haxe.lang.Runtime.toInt(len);
				if (targetLen == 0)
					return "";
				if( pos != 0 && targetLen < 0 ){
					return "";
				}
			}
-			if( pos < 0 ){
				pos = meLen + pos;
				if( pos < 0 ) pos = 0;
			} else if( targetLen < 0 ){
				targetLen = meLen + targetLen - pos;
			}

			if( pos + targetLen > meLen ){
				targetLen = meLen - pos;
			}

			if ( pos < 0 || targetLen <= 0 ) return "";
-			return me.substring(pos, pos + targetLen);
	')
	public static function substr(me:NativeString, pos:Int, ?len:Int):NativeString
	{
		return null;
	}
+			Array<java.lang.String> ret = new Array<java.lang.String>();
+
+			int slen = delimiter.length();
+			if (slen == 0)
+			{
+				int len = me.length();
+				for (int i = 0; i < len; i++)
+				{
+					ret.push(me.substring(i, i + 1));
+				}
+			} else {
+				int start = 0;
+				int pos = me.indexOf(delimiter, start);
+
+				while (pos >= 0)
+				{
+					ret.push(me.substring(start, pos));
+
+					start = pos + slen;
+					pos = me.indexOf(delimiter, start);
+				}
+
+				ret.push(me.substring(start));
+			}
+			return ret;
+	')
+	public static function split(me:NativeString, delimiter:NativeString):Array<NativeString>
+	{
+		return null;
+	}
+
 	@:functionCode('
-		int endIdx;
		int len = me.length();
		if ( endIndex == null) {
			endIdx = len;
		} else if ( (endIdx = haxe.lang.Runtime.toInt(endIndex)) < 0 ) {
			endIdx = 0;
		} else if ( endIdx > len ) {
			endIdx = len;
		}
-		if ( startIndex < 0 ) {
			startIndex = 0;
		} else if ( startIndex > len ) {
			startIndex = len;
		}
-		if ( startIndex > endIdx ) {
			int tmp = startIndex;
			startIndex = endIdx;
			endIdx = tmp;
		}
-		return me.substring(startIndex, endIdx);
-	')
	public static function substring(me:NativeString, startIndex:Int, ?endIndex:Int):NativeString
	{
		return null;
	}
+			int meLen = me.length();
+			int targetLen = meLen;
+			if (len != null)
+			{
+				targetLen = haxe.lang.Runtime.toInt(len);
+				if (targetLen == 0)
+					return "";
+				if( pos != 0 && targetLen < 0 ){
+					return "";
+				}
+			}
+
+			if( pos < 0 ){
+				pos = meLen + pos;
+				if( pos < 0 ) pos = 0;
+			} else if( targetLen < 0 ){
+				targetLen = meLen + targetLen - pos;
+			}
+
+			if( pos + targetLen > meLen ){
+				targetLen = meLen - pos;
+			}
+
+			if ( pos < 0 || targetLen <= 0 ) return "";
+
+			return me.substring(pos, pos + targetLen);
+	')
+	public static function substr(me:NativeString, pos:Int, ?len:Int):NativeString
+	{
+		return null;
+	}
+
 	@:functionCode('
-			return me.toLowerCase();
	')
	public static function toLowerCase(me:NativeString):NativeString
	{
		return null;
	}
+		int endIdx;
+		int len = me.length();
+		if ( endIndex == null) {
+			endIdx = len;
+		} else if ( (endIdx = haxe.lang.Runtime.toInt(endIndex)) < 0 ) {
+			endIdx = 0;
+		} else if ( endIdx > len ) {
+			endIdx = len;
+		}
+
+		if ( startIndex < 0 ) {
+			startIndex = 0;
+		} else if ( startIndex > len ) {
+			startIndex = len;
+		}
+
+		if ( startIndex > endIdx ) {
+			int tmp = startIndex;
+			startIndex = endIdx;
+			endIdx = tmp;
+		}
+
+		return me.substring(startIndex, endIdx);
+
+	')
+	public static function substring(me:NativeString, startIndex:Int, ?endIndex:Int):NativeString
+	{
+		return null;
+	}
+
 	@:functionCode('
-			return me.toUpperCase();
	')
	public static function toUpperCase(me:NativeString):NativeString
	{
		return null;
	}
-	public static function toNativeString(me:NativeString):NativeString
	{
		return me;
	}
+			return me.toLowerCase();
+	')
+	public static function toLowerCase(me:NativeString):NativeString
+	{
+		return null;
+	}
+
 	@:functionCode('
-		return java.lang.Character.toString( (char) code );
	')
	public static function fromCharCode(code:Int):NativeString
	{
		return null;
	}
}

@:keep @:nativeGen @:native('haxe.lang.StringRefl') private class StringRefl
-{
	public static var fields = ["length", "toUpperCase", "toLowerCase", "charAt", "charCodeAt", "indexOf", "lastIndexOf", "split", "substr", "substring"];
-	public static function handleGetField(str:NativeString, f:NativeString, throwErrors:Bool):Dynamic
	{
		switch(f)
		{
			case "length": return str.length;
			case "toUpperCase", "toLowerCase", "charAt", "charCodeAt", "indexOf", "lastIndexOf", "split", "substr", "substring":
				return new Closure(str, f);
			default:
				if (throwErrors)
					throw "Field not found: '" + f + "' in String";
				else
					return null;
		}
	}
-	public static function handleCallField(str:NativeString, f:NativeString, args:Array<Dynamic>):Dynamic
	{
		var _args:Array<Dynamic> = [str];
		if (args == null)
			args = _args;
		else
			args = _args.concat(args);
-		return Runtime.slowCallField(StringExt, f, args);
	}
}

@:keep @:native('haxe.lang.NativeString') private extern class JavaString
{
	//name collides with Haxe's
	function _charAt(idx:Int):java.StdTypes.Char16;
	function codePointAt(idx:Int):Int;
	function codePointBefore(idx:Int):Int;
	function codePointCount(begin:Int, end:Int):Int;
	function offsetByCodePoints(index:Int, codePointOffset:Int):Int;
	function getChars(srcBegin:Int, srcEnd:Int, dst:java.NativeArray<java.StdTypes.Char16>, dstBegin:Int):Void;
-	function startsWith(prefix:String):Bool;
	function endsWith(suffix:String):Bool;
	function _indexOf(str:String, fromIndex:Int):Int;
	function _lastIndexOf(str:String, fromIndex:Int):Int;
	function _substring(begin:Int, end:Int):String;
	function replace(old:String, nw:String):String;
	function _split(regex:String):java.NativeArray<String>;
	function trim():String;
}
+			return me.toUpperCase();
+	')
+	public static function toUpperCase(me:NativeString):NativeString
+	{
+		return null;
+	}
+
+	public static function toNativeString(me:NativeString):NativeString
+	{
+		return me;
+	}
+
+	@:functionCode('
+		return java.lang.Character.toString( (char) code );
+	')
+	public static function fromCharCode(code:Int):NativeString
+	{
+		return null;
+	}
+}
+
+@:keep @:nativeGen @:native('haxe.lang.StringRefl') private class StringRefl
+{
+	public static var fields = ["length", "toUpperCase", "toLowerCase", "charAt", "charCodeAt", "indexOf", "lastIndexOf", "split", "substr", "substring"];
+
+	public static function handleGetField(str:NativeString, f:NativeString, throwErrors:Bool):Dynamic
+	{
+		switch(f)
+		{
+			case "length": return str.length;
+			case "toUpperCase", "toLowerCase", "charAt", "charCodeAt", "indexOf", "lastIndexOf", "split", "substr", "substring":
+				return new Closure(str, f);
+			default:
+				if (throwErrors)
+					throw "Field not found: '" + f + "' in String";
+				else
+					return null;
+		}
+	}
+
+	public static function handleCallField(str:NativeString, f:NativeString, args:Array<Dynamic>):Dynamic
+	{
+		var _args:Array<Dynamic> = [str];
+		if (args == null)
+			args = _args;
+		else
+			args = _args.concat(args);
+
+		return Runtime.slowCallField(StringExt, f, args);
+	}
+}
+
+@:keep @:native('haxe.lang.NativeString') private extern class JavaString
+{
+	//name collides with Haxe's
+	function _charAt(idx:Int):java.StdTypes.Char16;
+	function codePointAt(idx:Int):Int;
+	function codePointBefore(idx:Int):Int;
+	function codePointCount(begin:Int, end:Int):Int;
+	function offsetByCodePoints(index:Int, codePointOffset:Int):Int;
+	function getChars(srcBegin:Int, srcEnd:Int, dst:java.NativeArray<java.StdTypes.Char16>, dstBegin:Int):Void;
+
+
+	function startsWith(prefix:String):Bool;
+	function endsWith(suffix:String):Bool;
+	function _indexOf(str:String, fromIndex:Int):Int;
+	function _lastIndexOf(str:String, fromIndex:Int):Int;
+	function _substring(begin:Int, end:Int):String;
+	function replace(old:String, nw:String):String;
+	function _split(regex:String):java.NativeArray<String>;
+	function trim():String;
+}

+ 3 - 3
tests/unit/TestJava.hx

@@ -157,7 +157,7 @@ class TestJava extends Test
 		eq(child.someField("test") , 2);
 		eq(child.someField(Bytes.ofString("a")), 2);
 		eq(child.someField(22.2), 3);
-		eq(new ChildJava(25).i, 25);
+		eq(new ChildJava(25).i, 26);
 
 		var child:OverloadedInterface = child;
 		eq(child.someField("test"), 2);
@@ -168,7 +168,7 @@ class TestJava extends Test
 		eq(child.someField(true), -1);
 
 		var child:ChildJava2<ChildJava2<Dynamic>> = new ChildJava2(22.5);
-		eq(child.i, 22);
+		eq(child.i, 23);
 		eq(child.someField(22.5), 50);
 		eq(child.someField(child), child);
 		eq(child.someField(ChildJava2), 51);
@@ -222,7 +222,7 @@ class TestJava extends Test
 	function testNameClash()
 	{
 		eq(Base._nameClash(null), -1);
-		eq(new Base().nameClash(), 2);
+		eq(new Base().nameClash(), 1);
 		eq(new Base().varNameClash(1), 1);
 		eq(Base._varNameClash(10.4), 10.4);
 

+ 1 - 1
tests/unit/unitstd/EReg.unit.hx

@@ -96,4 +96,4 @@ pos.len == 2;
 ~/href="(.*?)"/g.replace('lead href="foo" href="bar" trail',"$1") == "lead foo bar trail";
 ~/href="(.*?)"/g.replace('lead href="foo" href="bar" trail',"$$$1$$") == "lead $foo$ $bar$ trail";
 ~/href="(.*?)"/g.replace('lead href="foo" href="bar" trail',"$$$2$$") == "lead $$2$ $$2$ trail";
-#end
+#end