Переглянути джерело

Change String.iterator() to @:using (#8331)

* Revert 1d45ab0419442f9327ee0efe177dc3a4675c5622

* [lua] fix structure access for strings

* [lua] generate string wrapper only for anon/dynamic field access

* genas3 leftovers

* unit tests

* StringTools

* iterators

* add @:using(StringTools) to String

* fix clashes with native strings

* removed @:using(StringTools) from String
Aleksandr Kuzmenko 6 роки тому
батько
коміт
5e1dffef4c

+ 0 - 20
src/generators/genas3.ml

@@ -232,18 +232,6 @@ let open_block ctx =
 	ctx.tabs <- "\t" ^ ctx.tabs;
 	(fun() -> ctx.tabs <- oldt)
 
-(**
-	Returns `true` is `expr` represent a constant string.
-	Recursively looks through casts, metas and parentheses.
-*)
-let rec is_const_string expr =
-	match expr.eexpr with
-		| TConst (TString _) -> true
-		| TCast (e, _) -> is_const_string e
-		| TMeta (_, e) -> is_const_string e
-		| TParenthesis e -> is_const_string e
-		| _ -> false
-
 let parent e =
 	match e.eexpr with
 	| TParenthesis _ -> e
@@ -741,14 +729,6 @@ and gen_expr ctx e =
 		gen_expr ctx f.tf_expr;
 		ctx.in_static <- old;
 		h();
-	| TCall ({ eexpr = TField (e, ((FDynamic "iterator") | (FAnon { cf_name = "iterator" }))) }, []) when is_const_string e ->
-		print ctx "new haxe.iterators.StringIterator(";
-		gen_value ctx e;
-		print ctx ")"
-	| TCall ({ eexpr = TField (e, ((FDynamic "keyValueIterator") | (FAnon { cf_name = "keyValueIterator" }))) }, []) when is_const_string e ->
-		print ctx "new haxe.iterators.StringKeyValueIterator(";
-		gen_value ctx e;
-		print ctx ")"
 	| TCall (v,el) ->
 		gen_call ctx v el e.etype
 	| TArrayDecl el ->

+ 0 - 2
src/generators/gencs.ml

@@ -399,8 +399,6 @@ struct
 					{ e with eexpr = TCall(mk_static_field_access_infer string_ext "fromCharCode" e.epos [], [run cc]) }
 				| TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("charAt" as field) })) }, args )
 				| TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("charCodeAt" as field) })) }, args )
-				| TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("iterator" as field) })) }, args )
-				| TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("keyValueIterator" as field) })) }, args )
 				| TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("indexOf" as field) })) }, args )
 				| TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("lastIndexOf" as field) })) }, args )
 				| TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("split" as field) })) }, args )

+ 1 - 2
src/generators/genjava.ml

@@ -722,8 +722,7 @@ struct
 					let field = field.cf_name in
 					(match field with
 						| "charAt" | "charCodeAt" | "split" | "indexOf"
-						| "lastIndexOf" | "substring" | "substr"
-						| "iterator" | "keyValueIterator" ->
+						| "lastIndexOf" | "substring" | "substr" ->
 							{ e with eexpr = TCall(mk_static_field_access_infer string_ext field e.epos [], [run ef] @ (List.map run args)) }
 						| _ ->
 							{ e with eexpr = TCall(run efield, List.map run args) }

+ 2 - 32
src/generators/genjs.ml

@@ -343,7 +343,6 @@ let is_dynamic_iterator ctx e =
 	let check x =
 		let rec loop t = match follow t with
 			| TInst ({ cl_path = [],"Array" },_)
-			| TInst ({ cl_path = [],"String" },_)
 			| TInst ({ cl_kind = KTypeParameter _}, _)
 			| TAnon _
 			| TDynamic _
@@ -353,33 +352,13 @@ let is_dynamic_iterator ctx e =
 				loop (Abstract.get_underlying_type a tl)
 			| _ -> false
 		in
-		(has_feature ctx "HxOverrides.iter" || has_feature ctx "String.iterator") && loop x.etype
+		has_feature ctx "HxOverrides.iter" && loop x.etype
 	in
 	match e.eexpr with
 	| TField (x,f) when field_name f = "iterator" -> check x
 	| _ ->
 		false
 
-let is_dynamic_key_value_iterator ctx e =
-	let check x =
-		let rec loop t = match follow t with
-			| TInst ({ cl_path = [],"String" },_)
-			| TInst ({ cl_kind = KTypeParameter _}, _)
-			| TAnon _
-			| TDynamic _
-			| TMono _ ->
-				true
-			| TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) ->
-				loop (Abstract.get_underlying_type a tl)
-			| _ ->
-				false
-		in
-		has_feature ctx "String.keyValueIterator" && loop x.etype
-	in
-	match e.eexpr with
-	| TField (x,f) when field_name f = "keyValueIterator" -> check x
-	| _ -> false
-
 let gen_constant ctx p = function
 	| TInt i -> print ctx "%ld" i
 	| TFloat s -> spr ctx s
@@ -483,11 +462,6 @@ let rec gen_call ctx e el in_value =
 		print ctx "$getIterator(";
 		gen_value ctx x;
 		print ctx ")";
-	| TField (x,f), [] when field_name f = "keyValueIterator" && is_dynamic_key_value_iterator ctx e ->
-		add_feature ctx "use.$getKeyValueIterator";
-		print ctx "$getKeyValueIterator(";
-		gen_value ctx x;
-		print ctx ")";
 	| _ ->
 		gen_value ctx e;
 		spr ctx "(";
@@ -1778,11 +1752,7 @@ let generate com =
 		newline ctx;
 	end;
 	if has_feature ctx "use.$getIterator" then begin
-		print ctx "function $getIterator(o) { if( o instanceof Array ) return HxOverrides.iter(o); else if (typeof o == 'string') return HxOverrides.strIter(o); else return o.iterator(); }";
-		newline ctx;
-	end;
-	if has_feature ctx "use.$getKeyValueIterator" then begin
-		print ctx "function $getKeyValueIterator(o) { if (typeof o == 'string') return HxOverrides.strKVIter(o); else return o.keyValueIterator(); }";
+		print ctx "function $getIterator(o) { if( o instanceof Array ) return HxOverrides.iter(o); else return o.iterator(); }";
 		newline ctx;
 	end;
 	if has_feature ctx "use.$bind" then begin

+ 0 - 2
src/generators/genlua.ml

@@ -596,8 +596,6 @@ and is_possible_string_field e field_name=
         | "toString"
         | "substring"
         | "substr"
-        | "iterator"
-        | "keyValueIterator"
         | "charCodeAt" ->
             true
         | _ ->

+ 0 - 2
src/generators/genphp7.ml

@@ -2263,8 +2263,6 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 				| "toString"
 				| "substring"
 				| "substr"
-				| "iterator"
-				| "keyValueIterator"
 				| "charCodeAt" ->
 					self#write ((self#use hxdynamicstr_type_path) ^ "::wrap(");
 					self#write_expr expr;

+ 1 - 1
src/generators/genpy.ml

@@ -1673,7 +1673,7 @@ module Printer = struct
 					"print(str(" ^ (print_expr pctx e) ^ "))"
 			| TField(e1,((FAnon {cf_name = (("split" | "join" | "push" | "map" | "filter") as s)}) | FDynamic (("split" | "join" | "push" | "map" | "filter") as s))), [x] ->
 				Printf.sprintf "HxOverrides.%s(%s, %s)" s (print_expr pctx e1) (print_expr pctx x)
-			| TField(e1,((FAnon {cf_name = (("iterator" | "keyValueIterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift") as s)}) | FDynamic (("iterator" | "keyValueIterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift") as s))), [] ->
+			| TField(e1,((FAnon {cf_name = (("iterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift") as s)}) | FDynamic (("iterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift") as s))), [] ->
 				Printf.sprintf "HxOverrides.%s(%s)" s (print_expr pctx e1)
 			| TField(_, (FStatic({cl_path = ["python"; "_KwArgs"], "KwArgs_Impl_"},{ cf_name="fromT" }))), [e2]  ->
 				let t = match follow call_expr.etype with

+ 1 - 3
src/macro/eval/evalHash.ml

@@ -122,10 +122,8 @@ let key_haxe_zip_Compress = hash "haxe.zip.Compress"
 let key_haxe_zip_Uncompress = hash "haxe.zip.Uncompress"
 let key_done = hash "done"
 let key_eval_toplevel = hash "eval-toplevel"
-let key_haxe_iterators_string_iterator = hash "haxe.iterators.StringIterator"
-let key_haxe_iterators_string_key_value_iterator = hash "haxe.iterators.StringKeyValueIterator"
 let key_haxe_iterators_map_key_value_iterator = hash "haxe.iterators.MapKeyValueIterator"
 let key_sys_net_Mutex = hash "sys.thread.Mutex"
 let key_sys_net_Lock = hash "sys.thread.Lock"
 let key_sys_net_Tls = hash "sys.thread.Tls"
-let key_sys_net_Deque = hash "sys.thread.Deque"
+let key_sys_net_Deque = hash "sys.thread.Deque"

+ 0 - 20
src/macro/eval/evalStdLib.ml

@@ -2158,24 +2158,6 @@ module StdString = struct
 		else vint (char_at this i)
 	)
 
-	let iterator = vifun0 (fun vthis ->
-		let ctx = get_ctx() in
-		let path = key_haxe_iterators_string_iterator in
-		let vit = encode_instance path in
-		let fnew = get_instance_constructor ctx path null_pos in
-		ignore(call_value_on vit (Lazy.force fnew) [vthis]);
-		vit
-	)
-
-	let keyValueIterator = vifun0 (fun vthis ->
-		let ctx = get_ctx() in
-		let path = key_haxe_iterators_string_key_value_iterator in
-		let vit = encode_instance path in
-		let fnew = get_instance_constructor ctx path null_pos in
-		ignore(call_value_on vit (Lazy.force fnew) [vthis]);
-		vit
-	)
-
 	let fromCharCode = vfun1 (fun i ->
 		let i = decode_int i in
 		try
@@ -3522,8 +3504,6 @@ let init_standard_library builtins =
 	] [
 		"charAt",StdString.charAt;
 		"charCodeAt",StdString.charCodeAt;
-		"iterator",StdString.iterator;
-		"keyValueIterator",StdString.keyValueIterator;
 		"indexOf",StdString.indexOf;
 		"lastIndexOf",StdString.lastIndexOf;
 		"split",StdString.split;

+ 0 - 26
std/String.hx

@@ -19,10 +19,6 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 /**
 	The basic String class.
 
@@ -77,28 +73,6 @@ extern class String {
 	**/
 	function charCodeAt( index : Int) : Null<Int>;
 
-	/**
-		Returns an iterator of the char codes.
-
-		Note that char codes may differ across platforms because of different
-		internal encoding of strings in different of runtimes.
-		For the consistent cross-platform UTF8 char codes see `haxe.iterators.StringIteratorUnicode`.
-	**/
-	@:pure @:runtime inline function iterator() : StringIterator {
-		return new StringIterator(this);
-	}
-
-	/**
-		Returns an iterator of the char indexes and codes.
-
-		Note that char codes may differ across platforms because of different
-		internal encoding of strings in different of runtimes.
-		For the consistent cross-platform UTF8 char codes see `haxe.iterators.StringKeyValueIteratorUnicode`.
-	**/
-	@:pure @:runtime inline function keyValueIterator() : StringKeyValueIterator {
-		return new StringKeyValueIterator(this);
-	}
-
 	/**
 		Returns the position of the leftmost occurrence of `str` within `this`
 		String.

+ 31 - 4
std/StringTools.hx

@@ -19,6 +19,14 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
+
+import haxe.iterators.StringIterator;
+import haxe.iterators.StringKeyValueIterator;
+
+#if cpp
+using cpp.NativeString;
+#end
+
 /**
 	This class provides advanced methods on Strings. It is ideally used with
 	`using StringTools` and then acts as an [extension](https://haxe.org/manual/lf-static-extension.html)
@@ -27,9 +35,6 @@
 	If the first argument to any of the methods is null, the result is
 	unspecified.
 **/
-#if cpp
-using cpp.NativeString;
-#end
 class StringTools {
 	/**
 		Encode an URL by using the standard format.
@@ -333,7 +338,7 @@ class StringTools {
 		#if cs
 		return untyped s.Trim();
 		#elseif java
-		return untyped s.trim();
+		return (cast s : java.NativeString).trim();
 		#else
 		return ltrim(rtrim(s));
 		#end
@@ -490,6 +495,28 @@ class StringTools {
 		#end
 	}
 
+	/**
+		Returns an iterator of the char codes.
+
+		Note that char codes may differ across platforms because of different
+		internal encoding of strings in different runtimes.
+		For the consistent cross-platform UTF8 char codes see `haxe.iterators.StringIteratorUnicode`.
+	**/
+	public static inline function iterator( s : String ) : StringIterator {
+		return new StringIterator(s);
+	}
+
+	/**
+		Returns an iterator of the char indexes and codes.
+
+		Note that char codes may differ across platforms because of different
+		internal encoding of strings in different of runtimes.
+		For the consistent cross-platform UTF8 char codes see `haxe.iterators.StringKeyValueIteratorUnicode`.
+	**/
+	public static inline function keyValueIterator( s : String ) : StringKeyValueIterator {
+		return new StringKeyValueIterator(s);
+	}
+
 	/**
 		Tells if `c` represents the end-of-file (EOF) character.
 	**/

+ 0 - 11
std/cs/_std/String.hx

@@ -21,9 +21,6 @@
  */
 import cs.StdTypes;
 
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 @:coreApi extern class String implements ArrayAccess<Char16> {
 
 	@:overload private static function Compare(s1:String, s2:String):Int;
@@ -55,14 +52,6 @@ import haxe.iterators.StringKeyValueIterator;
 
 	function toString() : String;
 
-	@:pure @:runtime inline function iterator() : StringIterator {
-		return new StringIterator(this);
-	}
-
-	@:pure @:runtime inline function keyValueIterator() : StringKeyValueIterator {
-		return new StringKeyValueIterator(this);
-	}
-
 	static function fromCharCode( code : Int ) : String;
 
 	private function IndexOf(value:String, startIndex:Int, comparisonType:cs.system.StringComparison):Int;

+ 0 - 14
std/cs/internal/StringExt.hx

@@ -20,11 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 package cs.internal;
-
 import cs.internal.Function;
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 private typedef NativeString = cs.system.String;
 
 @:keep @:nativeGen @:native("haxe.lang.StringExt") class StringExt
@@ -197,16 +193,6 @@ private typedef NativeString = cs.system.String;
 		return cs.system.Char.ConvertFromUtf32(code);
 		// return new NativeString( cast(code,cs.StdTypes.Char16), 1 );
 	}
-
-	public static function iterator(me:String):StringIterator
-	{
-		return new StringIterator(me);
-	}
-
-	public static function keyValueIterator(me:String):StringKeyValueIterator
-	{
-		return new StringKeyValueIterator(me);
-	}
 }
 
 @:keep @:nativeGen @:native('haxe.lang.StringRefl') class StringRefl

+ 1 - 11
std/flash/Boot.hx

@@ -21,9 +21,6 @@
  */
 package flash;
 
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 #if !as3
 @:keep private class RealBoot extends Boot {
 	#if swc
@@ -245,14 +242,6 @@ class Boot extends flash.display.MovieClip {
 	}
 
 	static function __init__() untyped {
-		String.prototype.iterator = function() : StringIterator {
-			var s : String = __this__;
-			return new StringIterator(s);
-		}
-		String.prototype.keyValueIterator = function() : StringKeyValueIterator {
-			var s : String = __this__;
-			return new StringKeyValueIterator(s);
-		}
 		var aproto = Array.prototype;
 		aproto.copy = function() {
 			return __this__.slice();
@@ -348,4 +337,5 @@ class Boot extends flash.display.MovieClip {
 			return Std.int(x);
 		};
 	}
+
 }

+ 2 - 2
std/flash/_std/EReg.hx

@@ -78,12 +78,12 @@
 	public function split( s : String ) : Array<String> {
 		// we can't use directly s.split because it's ignoring the 'g' flag
 		var d = "#__delim__#";
-		var s : String = (cast s).replace(r, d);
+		var s : String = (s:Dynamic).replace(r, d);
 		return s.split(d);
 	}
 
 	public function replace( s : String, by : String ) : String {
-		return (cast s).replace(r,by);
+		return (s:Dynamic).replace(r,by);
 	}
 
 	public function map( s : String, f : EReg -> String ) : String {

+ 0 - 11
std/flash/_std/String.hx

@@ -20,9 +20,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 @:coreApi
 extern class String {
 
@@ -39,14 +36,6 @@ extern class String {
 	function substring( startIndex : Int, ?endIndex : Int ) : String;
 	function toString() : String;
 
-	@:pure @:runtime inline function iterator() : StringIterator {
-		return new StringIterator(this);
-	}
-
-	@:pure @:runtime inline function keyValueIterator() : StringKeyValueIterator {
-		return new StringKeyValueIterator(this);
-	}
-
 	@:pure static inline function fromCharCode( code : Int ) : String untyped {
 		return code < 0x10000 ? String["fromCharCode"](code) : flash.Boot.fromCodePoint(code);
 	}

+ 2 - 14
std/hl/_std/String.hx

@@ -19,10 +19,6 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 @:coreApi
 class String {
 
@@ -172,14 +168,6 @@ class String {
 		return this;
 	}
 
-	public inline function iterator() : StringIterator {
-		return new StringIterator(this);
-	}
-
-	public inline function keyValueIterator() : StringKeyValueIterator {
-		return new StringKeyValueIterator(this);
-	}
-
 	public static function fromCharCode( code : Int ) : String {
 		if( code >= 0 && code < 0x10000 ) {
 			if( code >= 0xD800 && code <= 0xDFFF ) throw "Invalid unicode char " + code;
@@ -211,9 +199,9 @@ class String {
 		if( s == null )
 			return hl.Api.comparePointer(this, v);
 		#if (hl_ver >= version("1.10"))
-		var v = bytes.compare16(s.bytes, length < s.length ? length : s.length);		
+		var v = bytes.compare16(s.bytes, length < s.length ? length : s.length);
 		#else
-		var v = bytes.compare(0, s.bytes, 0, (length < s.length ? length : s.length) << 1);		
+		var v = bytes.compare(0, s.bytes, 0, (length < s.length ? length : s.length) << 1);
 		#end
 		return v == 0 ? length - s.length : v;
 	}

+ 0 - 11
std/java/_std/String.hx

@@ -20,9 +20,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 @:coreApi extern class String implements java.lang.CharSequence {
 
 	var length(default,null) : Int;
@@ -52,14 +49,6 @@ import haxe.iterators.StringKeyValueIterator;
 
 	function toString() : String;
 
-	@:pure @:runtime inline function iterator() : StringIterator {
-		return new StringIterator(this);
-	}
-
-	@:pure @:runtime inline function keyValueIterator() : StringKeyValueIterator {
-		return new StringKeyValueIterator(this);
-	}
-
 	private function compareTo( anotherString : String ) : Int;
 
 	private function codePointAt( idx : Int ) : Int;

+ 0 - 12
std/java/internal/StringExt.hx

@@ -21,8 +21,6 @@
  */
 package java.internal;
 import java.internal.Function;
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
 
 private typedef NativeString = String;
 
@@ -201,16 +199,6 @@ private typedef NativeString = String;
 	{
 		return new String(java.lang.Character.toChars(code));
 	}
-
-	public static function iterator(me:NativeString):StringIterator
-	{
-		return new StringIterator(me);
-	}
-
-	public static function keyValueIterator(me:NativeString):StringKeyValueIterator
-	{
-		return new StringKeyValueIterator(me);
-	}
 }
 
 @:keep @:nativeGen @:native('haxe.lang.StringRefl') private class StringRefl

+ 0 - 14
std/js/_std/HxOverrides.hx

@@ -19,10 +19,6 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 @:noDoc
 class HxOverrides {
 
@@ -146,16 +142,6 @@ class HxOverrides {
 		};
 	}
 
-	@:ifFeature("String.iterator")
-	static function strIter( s : String ) : StringIterator {
-		return new StringIterator(s);
-	}
-
-	@:ifFeature("String.keyValueIterator")
-	static function strKVIter( s : String ) : StringKeyValueIterator {
-		return new StringKeyValueIterator(s);
-	}
-
 	static function __init__() untyped {
 #if (js_es < 5)
 		__feature__('HxOverrides.indexOf', if( Array.prototype.indexOf ) __js__("HxOverrides").indexOf = function(a,o,i) return Array.prototype.indexOf.call(a, o, i));

+ 1 - 1
std/js/_std/Reflect.hx

@@ -28,7 +28,7 @@
 
 	@:pure
 	public static function field( o : Dynamic, field : String ) : Dynamic {
-		return try o[cast field] catch( e : Dynamic ) null;
+		try return o[cast field] catch( e : Dynamic ) return null;
 	}
 
 	public inline static function setField( o : Dynamic, field : String, value : Dynamic ) : Void {

+ 0 - 14
std/js/_std/String.hx

@@ -19,10 +19,6 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 @:coreApi extern class String {
 	var length(default,null) : Int;
 
@@ -40,16 +36,6 @@ import haxe.iterators.StringKeyValueIterator;
 		return @:privateAccess HxOverrides.cca(this, index);
 	}
 
-	@:pure @:runtime inline function iterator() : StringIterator {
-		untyped __define_feature__("String.iterator", {});
-		return new StringIterator(this);
-	}
-
-	@:pure @:runtime inline function keyValueIterator() : StringKeyValueIterator {
-		untyped __define_feature__("String.keyValueIterator", {});
-		return new StringKeyValueIterator(this);
-	}
-
 	@:pure inline function substr( pos : Int, ?len : Int ) : String {
 		return @:privateAccess HxOverrides.substr(this, pos, len);
 	}

+ 0 - 11
std/jvm/_std/String.hx

@@ -20,9 +20,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 @:coreApi
 @:native("java.lang.String")
 extern class String implements java.lang.CharSequence {
@@ -68,14 +65,6 @@ extern class String implements java.lang.CharSequence {
 
 	function toString() : String;
 
-	@:pure @:runtime inline function iterator() : StringIterator {
-		return new StringIterator(this);
-	}
-
-	@:pure @:runtime inline function keyValueIterator() : StringKeyValueIterator {
-		return new StringKeyValueIterator(this);
-	}
-
 	private function compareTo( anotherString : String ) : Int;
 
 	private function codePointAt( idx : Int ) : Int;

+ 0 - 10
std/lua/_std/String.hx

@@ -23,8 +23,6 @@
 import lua.Lua;
 import lua.Table;
 import lua.Boot;
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
 
 #if lua_vanilla
 	typedef BaseString = lua.NativeStringTools;
@@ -124,14 +122,6 @@ class String {
 		return BaseString.byte(this,index+1);
 	}
 
-	@:runtime public inline function iterator() : StringIterator {
-		return new StringIterator(this);
-	}
-
-	@:runtime public inline function keyValueIterator() : StringKeyValueIterator {
-		return new StringKeyValueIterator(this);
-	}
-
 	public inline function substr( pos : Int, ?len : Int ) : String {
 		if (len == null || len > pos + this.length) len = this.length;
 		else if (len < 0) len = length + len;

+ 0 - 12
std/neko/_std/String.hx

@@ -19,10 +19,6 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 @:coreApi final class String {
 
 	static var __is_String = true;
@@ -61,14 +57,6 @@ import haxe.iterators.StringKeyValueIterator;
 		}
 	}
 
-	public inline function iterator() : StringIterator {
-		return new StringIterator(this);
-	}
-
-	public inline function keyValueIterator() : StringKeyValueIterator {
-		return new StringKeyValueIterator(this);
-	}
-
 	public function indexOf( str : String, ?startIndex : Int ) : Int {
 		untyped {
 			var l = __dollar__ssize(this.__s);

+ 0 - 10
std/php/Boot.hx

@@ -22,8 +22,6 @@
 package php;
 
 import haxe.PosInfos;
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
 import haxe.extern.EitherType;
 
 using php.Global;
@@ -738,14 +736,6 @@ private class HxString {
 		return char == '' ? null : Boot.unsafeOrd(char);
 	}
 
-	public static function iterator( str:String ):StringIterator {
-		return new StringIterator(str);
-	}
-
-	public static function keyValueIterator( str:String ):StringKeyValueIterator {
-		return new StringKeyValueIterator(str);
-	}
-
 	public static function indexOf( str:String, search:String, startIndex:Int = null ) : Int {
 		if (startIndex == null) {
 			startIndex = 0;

+ 1 - 11
std/php/_std/String.hx

@@ -20,9 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-import php.Global;
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
+import php.*;
 
 @:coreApi extern class String {
 
@@ -44,14 +42,6 @@ import haxe.iterators.StringKeyValueIterator;
 
 	@:pure function charCodeAt( index : Int) : Null<Int>;
 
-	@:pure @:runtime inline function iterator() : StringIterator {
-		return new StringIterator(this);
-	}
-
-	@:pure @:runtime inline function keyValueIterator() : StringKeyValueIterator {
-		return new StringKeyValueIterator(this);
-	}
-
 	@:pure function indexOf( str : String, ?startIndex : Int ) : Int;
 
 	@:pure function lastIndexOf( str : String, ?startIndex : Int ) : Int;

+ 24 - 0
std/php/_std/StringTools.hx

@@ -21,6 +21,8 @@
  */
 
 import php.*;
+import haxe.iterators.StringIterator;
+import haxe.iterators.StringKeyValueIterator;
 
 @:coreApi class StringTools {
 
@@ -120,6 +122,28 @@ import php.*;
 		return Boot.unsafeOrd(char);
 	}
 
+	/**
+		Returns an iterator of the char codes.
+
+		Note that char codes may differ across platforms because of different
+		internal encoding of strings in different runtimes.
+		For the consistent cross-platform UTF8 char codes see `haxe.iterators.StringIteratorUnicode`.
+	**/
+	public static inline function iterator( s : String ) : StringIterator {
+		return new StringIterator(s);
+	}
+
+	/**
+		Returns an iterator of the char indexes and codes.
+
+		Note that char codes may differ across platforms because of different
+		internal encoding of strings in different of runtimes.
+		For the consistent cross-platform UTF8 char codes see `haxe.iterators.StringKeyValueIteratorUnicode`.
+	**/
+	public static inline function keyValueIterator( s : String ) : StringKeyValueIterator {
+		return new StringKeyValueIterator(s);
+	}
+
 	@:noUsing public static inline function isEof( c : Int ) : Bool {
 		return c == 0;
 	}

+ 0 - 6
std/python/Boot.hx

@@ -30,8 +30,6 @@ import python.internal.HxException;
 import python.internal.AnonObject;
 import python.internal.UBuiltins;
 import python.lib.Inspect;
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
 
 import python.Syntax;
 
@@ -313,10 +311,6 @@ class Boot {
 					createClosure(o, StringImpl.charAt);
 				case "charCodeAt":
 					createClosure(o, StringImpl.charCodeAt);
-				case "iterator":
-					createClosure(o, StringImpl.iterator);
-				case "keyValueIterator":
-					createClosure(o, StringImpl.keyValueIterator);
 				case "indexOf":
 					createClosure(o, StringImpl.indexOf);
 				case "lastIndexOf":

+ 0 - 11
std/python/_std/String.hx

@@ -22,9 +22,6 @@
 #if !macro
 import python.internal.StringImpl;
 #end
-import haxe.iterators.StringIterator;
-import haxe.iterators.StringKeyValueIterator;
-
 @:coreApi
 @:native("str")
 extern class String {
@@ -50,14 +47,6 @@ extern class String {
 		return StringImpl.charCodeAt(this, index);
 	}
 
-	@:runtime public inline function iterator() : StringIterator {
-		return new StringIterator(this);
-	}
-
-	@:runtime public inline function keyValueIterator() : StringKeyValueIterator {
-		return new StringKeyValueIterator(this);
-	}
-
 	inline function indexOf( str : String, ?startIndex : Int ) : Int {
 		return StringImpl.indexOf(this, str, startIndex);
 	}

+ 1 - 11
std/python/internal/HxOverrides.hx

@@ -35,22 +35,12 @@ class HxOverrides {
 	// we need to modify the transformer to call Reflect directly
 
 	@:ifFeature("dynamic_read.iterator", "anon_optional_read.iterator", "anon_read.iterator")
-	static public function iterator(x:Any):Any {
+	static public function iterator(x) {
 		if (Boot.isArray(x)) {
 			return (x:Array<Dynamic>).iterator();
 		}
-		if (Boot.isString(x)) {
-			return new haxe.iterators.StringIterator(x);
-		}
 		return Syntax.callField(x, "iterator");
 	}
-	@:ifFeature("dynamic_read.keyValueIterator", "anon_optional_read.keyValueIterator", "anon_read.keyValueIterator")
-	static public function keyValueIterator(x:Any):Any {
-		if (Boot.isString(x)) {
-			return new haxe.iterators.StringKeyValueIterator(x);
-		}
-		return Syntax.callField(x, "keyValueIterator");
-	}
 	@:ifFeature("dynamic_binop_==", "dynamic_binop_!=")
 	static function eq( a:Dynamic, b:Dynamic ) : Bool {
 		if (Boot.isArray(a) || Boot.isArray(b)) {

+ 0 - 10
std/python/internal/StringImpl.hx

@@ -43,16 +43,6 @@ class StringImpl {
 		return if (index < 0 || index >= s.length) "" else Syntax.arrayAccess(s,index);
 	}
 
-	@:ifFeature("dynamic_read.iterator", "anon_optional_read.iterator", "python.internal.StringImpl.iterator")
-	public static inline function iterator(s:String) {
-		return new haxe.iterators.StringIterator(s);
-	}
-
-	@:ifFeature("dynamic_read.keyValueIterator", "anon_optional_read.keyValueIterator", "python.internal.StringImpl.keyValueIterator")
-	public static inline function keyValueIterator(s:String) {
-		return new haxe.iterators.StringKeyValueIterator(s);
-	}
-
 	@:ifFeature("dynamic_read.lastIndexOf", "anon_optional_read.lastIndexOf", "python.internal.StringImpl.lastIndexOf")
 	public static inline function lastIndexOf(s:String, str:String, ?startIndex:Int):Int {
 		if (startIndex == null) {

+ 0 - 28
tests/unit/src/unitstd/String.unit.hx

@@ -167,34 +167,6 @@ String.fromCharCode(65) == "A";
 ("3" > "11") == true;
 (" 3" < "3") == true;
 
-// iterators
-var s = 'zя𠜎';
-#if !(target.unicode)
-var expectedCodes = [122, 209, 143, 240, 160, 156, 142];
-#elseif utf16
-var expectedCodes = [122, 1103, 55361, 57102];
-#else
-var expectedCodes = [122, 1103, 132878];
-#end
-var expectedKeys = [for(i in 0...expectedCodes.length) i];
-function testCodes(codes:Array<Int>, ?pos:haxe.PosInfos) {
-	aeq(expectedCodes, codes, pos);
-}
-function testKeyCodes(keyCodes:Array<Array<Int>>, ?pos:haxe.PosInfos) {
-	aeq(expectedKeys, keyCodes.map(a -> a[0]), pos);
-	aeq(expectedCodes, keyCodes.map(a -> a[1]), pos);
-}
-// iterator
-testCodes([for(c in s) c]);
-testCodes([for(c in (s:Iterable<Int>)) c]);
-var iterator:Iterator<Int> = (s:Dynamic).iterator();
-testCodes([for(c in iterator) c]);
-// keyValueIterator
-testKeyCodes([for(i => c in s) [i, c]]);
-testKeyCodes([for(i => c in (s:KeyValueIterable<Int,Int>)) [i, c]]);
-var iterator:KeyValueIterator<Int,Int> = (s:Dynamic).keyValueIterator();
-testKeyCodes([for(i => c in iterator) [i, c]]);
-
 // string comparison (see #8332)
 ("a" < "b") == true;
 ("a" <= "b") == true;

+ 18 - 1
tests/unit/src/unitstd/StringTools.unit.hx

@@ -147,4 +147,21 @@ StringTools.isEof( -1) == true;
 // how do I test this here?
 #else
 StringTools.isEof(0) == true;
-#end
+#end
+
+// iterators via @:using
+var s = 'zя𠜎';
+#if !(target.unicode)
+var expectedCodes = [122, 209, 143, 240, 160, 156, 142];
+#elseif utf16
+var expectedCodes = [122, 1103, 55361, 57102];
+#else
+var expectedCodes = [122, 1103, 132878];
+#end
+var expectedKeys = [for(i in 0...expectedCodes.length) i];
+// iterator()
+aeq(expectedCodes, [for(c in StringTools.iterator(s)) c]);
+// keyValueIterator()
+var keyCodes = [for(i => c in StringTools.keyValueIterator(s)) [i, c]];
+aeq(expectedKeys, keyCodes.map(a -> a[0]));
+aeq(expectedCodes, keyCodes.map(a -> a[1]));