Browse Source

fixed memory leak with PHP closures
fixed wrong scope in closures

Franco Ponticelli 17 years ago
parent
commit
3276f7e170
6 changed files with 231 additions and 87 deletions
  1. 2 1
      doc/CHANGES.txt
  2. 24 9
      genphp.ml
  3. 20 2
      std/List.hx
  4. 1 4
      std/Reflect.hx
  5. 146 43
      std/php/Boot.hx
  6. 38 28
      std/php/PhpXml__.hx

+ 2 - 1
doc/CHANGES.txt

@@ -40,7 +40,8 @@ TODO inlining : substitute class+function type parameters in order to have fully
 	fixed duplicate fields in Type.getInstanceFields on subclass
 	fixed duplicate fields in Type.getInstanceFields on subclass
 	Enum is no longer defined inside Type but is standalone class
 	Enum is no longer defined inside Type but is standalone class
 	fixed Date.getDay on Neko/Windows (use %w instead of %u)
 	fixed Date.getDay on Neko/Windows (use %w instead of %u)
-
+	fixed memory leak with PHP closures
+	fixed wrong scope in closures
 2008-07-28: 2.0
 2008-07-28: 2.0
 	fixed current package bug in inherited constructor type
 	fixed current package bug in inherited constructor type
 	delayed type-parameter constraints check (allow mutual rec extends for SPOD)
 	delayed type-parameter constraints check (allow mutual rec extends for SPOD)

+ 24 - 9
genphp.ml

@@ -406,7 +406,7 @@ let s_funarg ctx arg t p c =
 			print ctx "%s%s$%s" byref (escphp ctx.quotes) arg;
 			print ctx "%s%s$%s" byref (escphp ctx.quotes) arg;
 		| _ ->
 		| _ ->
 			if cl.cl_kind = KNormal && not cl.cl_extern then
 			if cl.cl_kind = KNormal && not cl.cl_extern then
-				print ctx "/*%s*/ %s%s$%s" (s_path ctx cl.cl_path cl.cl_extern p) byref (escphp ctx.quotes) arg
+				print ctx "%s%s$%s" byref (escphp ctx.quotes) arg
 			else begin
 			else begin
 				print ctx "%s%s$%s" byref (escphp ctx.quotes) arg;
 				print ctx "%s%s$%s" byref (escphp ctx.quotes) arg;
 			end)
 			end)
@@ -913,14 +913,18 @@ and gen_inline_function ctx f params p =
 		print ctx "%s\"%s%s\" => &%s$%s" pq n pq pq n;
 		print ctx "%s\"%s%s\" => &%s$%s" pq n pq pq n;
 	) old_li;
 	) old_li;
 
 
-	print ctx "), %s\"" pq;
-	ctx.quotes <- ctx.quotes + 1;
+	print ctx "), null, array(";
+(*	ctx.quotes <- ctx.quotes + 1; *)
 	concat ctx "," (fun (arg,o,t) ->
 	concat ctx "," (fun (arg,o,t) ->
+		let arg = define_local ctx arg in
+		print ctx "'%s'" arg;
+	(*
 		let arg = define_local ctx arg in
 		let arg = define_local ctx arg in
 		s_funarg ctx arg t p o;
 		s_funarg ctx arg t p o;
+		*)
 	) f.tf_args;
 	) f.tf_args;
-	ctx.quotes <- ctx.quotes - 1;
-	print ctx "%s\", %s\"" pq pq;
+(*	ctx.quotes <- ctx.quotes - 1; *)
+	print ctx "), %s\"" pq;
 	ctx.quotes <- ctx.quotes + 1;
 	ctx.quotes <- ctx.quotes + 1;
 	gen_expr ctx (fun_block ctx f p);
 	gen_expr ctx (fun_block ctx f p);
 	ctx.quotes <- ctx.quotes - 1;
 	ctx.quotes <- ctx.quotes - 1;
@@ -965,6 +969,13 @@ and gen_expr ctx e =
 		| TFun (args,_) -> print ctx "%s::%s" (s_path ctx en.e_path en.e_extern e.epos) (s_ident s)
 		| TFun (args,_) -> print ctx "%s::%s" (s_path ctx en.e_path en.e_extern e.epos) (s_ident s)
 		| _ -> print ctx "%s::%s$%s" (s_path ctx en.e_path en.e_extern e.epos) (escphp ctx.quotes) (s_ident s))
 		| _ -> print ctx "%s::%s$%s" (s_path ctx en.e_path en.e_extern e.epos) (escphp ctx.quotes) (s_ident s))
 	| TArray (e1,e2) ->
 	| TArray (e1,e2) ->
+		(*
+		spr ctx "php_Boot::__byref__array_get(";
+		gen_value ctx e1;
+		spr ctx ", ";
+		gen_value ctx e2;
+		spr ctx ")";
+		*)
 		(match e1.eexpr with
 		(match e1.eexpr with
 		| TCall _ ->
 		| TCall _ ->
 			spr ctx "php_Boot::__byref__array_get(";
 			spr ctx "php_Boot::__byref__array_get(";
@@ -1201,15 +1212,19 @@ and gen_expr ctx e =
 				let name = f.cf_name in
 				let name = f.cf_name in
 				match f.cf_expr with
 				match f.cf_expr with
 				| Some { eexpr = TFunction fd } ->
 				| Some { eexpr = TFunction fd } ->
-					print ctx "$this->%s = php_Boot::__closure(array(\"__this\" => &$this), \"" name;
-					ctx.quotes <- ctx.quotes + 1;
+					print ctx "$this->%s = php_Boot::__closure(array(), $this, array(" name;
+(*					ctx.quotes <- ctx.quotes + 1; *)
 					concat ctx "," (fun (arg,o,t) ->
 					concat ctx "," (fun (arg,o,t) ->
+						let arg = define_local ctx arg in
+						print ctx "'%s'" arg;
+					(*
 					let arg = define_local ctx arg in
 					let arg = define_local ctx arg in
 					  s_funarg ctx arg t e.epos o;
 					  s_funarg ctx arg t e.epos o;
+					  *)
 					) fd.tf_args;
 					) fd.tf_args;
-					ctx.quotes <- ctx.quotes - 1;
+(*					ctx.quotes <- ctx.quotes - 1; *)
 
 
-					print ctx "\", \"";
+					print ctx "), \"";
 					let old = ctx.in_value in
 					let old = ctx.in_value in
 					ctx.in_value <- Some name;
 					ctx.in_value <- Some name;
 					ctx.quotes <- ctx.quotes + 1;
 					ctx.quotes <- ctx.quotes + 1;

+ 20 - 2
std/List.hx

@@ -84,7 +84,7 @@ class List<T> {
 		#if php
 		#if php
 		untyped __php__("$this->h =& $x");
 		untyped __php__("$this->h =& $x");
 		if( q == null )
 		if( q == null )
-			untyped __php__("$this->q =& $x");		
+			untyped __php__("$this->q =& $x");
 		#else
 		#else
 		h = x;
 		h = x;
 		if( q == null )
 		if( q == null )
@@ -163,7 +163,7 @@ class List<T> {
 			}
 			}
 			untyped __php__("$prev =& $l");
 			untyped __php__("$prev =& $l");
 			untyped __php__("$l =& $l[1]");
 			untyped __php__("$l =& $l[1]");
-		}		
+		}
 		#else
 		#else
 		var l = h;
 		var l = h;
 		while( l != null ) {
 		while( l != null ) {
@@ -188,6 +188,23 @@ class List<T> {
 		Returns an iterator on the elements of the list.
 		Returns an iterator on the elements of the list.
 	**/
 	**/
 	public function iterator() : Iterator<T> {
 	public function iterator() : Iterator<T> {
+#if php
+		var it = null;
+		it = untyped {
+			h : h,
+			hasNext : function() {
+				return it.h != null;
+			},
+			next : function() {
+				if( it.h == null )
+					return null;
+				var x = it.h[0];
+				it.h = it.h[1];
+				return x;
+			}
+		};
+		return cast it;
+#else
 		return cast {
 		return cast {
 			h : h,
 			h : h,
 			hasNext : function() {
 			hasNext : function() {
@@ -203,6 +220,7 @@ class List<T> {
 				}
 				}
 			}
 			}
 		}
 		}
+#end
 	}
 	}
 
 
 	/**
 	/**

+ 1 - 4
std/Reflect.hx

@@ -350,10 +350,7 @@ class Reflect {
 		#elseif flash
 		#elseif flash
 			return function() { return f(untyped __arguments__); };
 			return function() { return f(untyped __arguments__); };
 		#elseif php
 		#elseif php
-			return function() {
-				var args = untyped __call__("func_get_args");
-				return f(args);
-			};
+			untyped __php__("return array(new _lambda(array('f' => &$f), null, array('args'), 'return call_user_func_array($f, array($args));'), 'makeArgs')");
 		#else
 		#else
 			return null;
 			return null;
 		#end
 		#end

+ 146 - 43
std/php/Boot.hx

@@ -8,33 +8,23 @@ class Boot {
 
 
 	static public function __anonymous(?p : Dynamic) : Dynamic {
 	static public function __anonymous(?p : Dynamic) : Dynamic {
 		untyped __php__("$o = new Anonymous();
 		untyped __php__("$o = new Anonymous();
-		if(is_array($p)) {
-			foreach($p as $k => $v) {
+		if(is_array($p))
+			foreach($p as $k => $v)
 				$o->$k = $v;
 				$o->$k = $v;
-			}
-		}
 		return $o");
 		return $o");
 	}
 	}
 
 
 	static private var __cid = 0;
 	static private var __cid = 0;
-	static public var __scopes = [];
-	static public function __closure(locals : ArrayAccess<Dynamic>, params : String, body : String) : String {
-		var cid = __cid++;
-		var n = "__closure__"+cid+"__";
-		untyped __php__("php_Boot::$__scopes[$n] = array('scope' => null, 'locals' => $locals)");
-		var f : String = untyped __call__(
-			"create_function",
-			params,
-			"$__this =& php_Boot::$__scopes['"+n+"']['scope'];\nforeach(array_keys(php_Boot::$__scopes['"+n+"']['locals']) as ${'%k'}) ${${'%k'}} =& php_Boot::$__scopes['"+n+"']['locals'][${'%k'}];\n"+body);
-		var nl = "__"+f.substr(1)+"__";
-		untyped __php__("php_Boot::$__scopes[$nl] =& php_Boot::$__scopes[$n]");
-		return f;
+
+	static public function __closure(locals : ArrayAccess<Dynamic>, scope : Dynamic, params : Dynamic, body : String) : Void {
+		untyped __php__("return array(new _lambda($locals, $scope, $params, $body), 'execute'.count($params))");
 	}
 	}
 
 
-	static public function __is_lambda(s : String) : Bool {
-		return untyped __call__("is_string", s) && s.substr(0, 8) == __call__("chr", 0) + "lambda_";
+	static public function __is_lambda(s : Dynamic) : Bool {
+		return untyped (__call__("is_string", s) && s.substr(0, 8) == __call__("chr", 0) + "lambda_") || (__call__("is_array", s) && __call__("count", s) > 0 && __call__("is_a", s[0], "php_Lambda"));
 	}
 	}
 
 
+
 	static public function __array() : Dynamic {
 	static public function __array() : Dynamic {
 		return untyped __call__("func_get_args");
 		return untyped __call__("func_get_args");
 	}
 	}
@@ -237,15 +227,24 @@ class Boot {
 					return php.Boot.__len(o);
 					return php.Boot.__len(o);
 				else {
 				else {
 					switch(field) {
 					switch(field) {
-						case 'charAt':      return php.Boot.__closure(__php__("array('o' => $o)"), '$index', 'return substr($o, $index,1 );');
-						case 'charCodeAt':  return php.Boot.__closure(__php__("array('o' => $o)"), '$index', 'return ord(substr($o, $index, 1));');
-						case 'indexOf':     return php.Boot.__closure(__php__("array('o' => $o)"), '$value,$startIndex', 'return php_Boot::__index_of($o, $value, $startIndex);');
-						case 'lastIndexOf': return php.Boot.__closure(__php__("array('o' => $o)"), '$value,$startIndex', 'return php_Boot::__last_index_of($o, $value, $startIndex);');
-						case 'split':       return php.Boot.__closure(__php__("array('o' => $o)"), '$delimiter', 'return explode($delimiter, $o);');
-						case 'substr':      return php.Boot.__closure(__php__("array('o' => $o)"), '$pos,$len', 'return php_Boot::__substr($o, $pos, $len);');
-						case 'toUpperCase': return php.Boot.__closure(__php__("array('o' => $o)"), '', 'return strtoupper($o);');
-						case 'toLowerCase': return php.Boot.__closure(__php__("array('o' => $o)"), '', 'return strtolower($o);');
-						case 'toString':    return php.Boot.__closure(__php__("array('o' => $o)"), '', 'return $o;');
+						case 'charAt':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('index'), 'return substr($o,$index,1);')");
+						case 'charCodeAt':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('index'), 'return ord(substr($o, $index, 1));')");
+						case 'indexOf':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('value','startIndex'), 'return php_Boot::__index_of($o, $value, $startIndex);')");
+						case 'lastIndexOf':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('value','startIndex'), 'return php_Boot::__last_index_of($o, $value, $startIndex);')");
+						case 'split':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('delimiter'), 'return explode($delimiter, $o);')");
+						case 'substr':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('pos','len'), 'return php_Boot::__substr($o, $pos, $len);')");
+						case 'toUpperCase':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array(), 'return strtoupper($o);')");
+						case 'toLowerCase':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array(), 'return strtolower($o);')");
+						case 'toString':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array(), 'return $o;')");
 					}
 					}
 					return null;
 					return null;
 				}
 				}
@@ -254,21 +253,36 @@ class Boot {
 					return php.Boot.__len(o);
 					return php.Boot.__len(o);
 				else
 				else
 					switch(field) {
 					switch(field) {
-						case 'concat':   return php.Boot.__closure(__php__("array('o' => &$o)"), '$a', 'return array_merge($o, $a);');
-						case 'join':     return php.Boot.__closure(__php__("array('o' => &$o)"), '$sep', 'return join($sep, $o);');
-						case 'pop':      return php.Boot.__closure(__php__("array('o' => &$o)"), '', 'return array_pop($o);');
-						case 'push':     return php.Boot.__closure(__php__("array('o' => &$o)"), '$x', 'return array_push($o, $x);');
-						case 'reverse':  return php.Boot.__closure(__php__("array('o' => &$o)"), '', 'return rsort($o);');
-						case 'shift':    return php.Boot.__closure(__php__("array('o' => &$o)"), '', 'return array_shift($o);');
-						case 'slice':    return php.Boot.__closure(__php__("array('o' => &$o)"), '$pos,$end', 'return php_Boot::__array_slice(array(&$o), $pos, $end);');
-						case 'sort':     return php.Boot.__closure(__php__("array('o' => &$o)"), '$f', 'return php_Boot::__array_sort($o, $f);');
-						case 'splice':   return php.Boot.__closure(__php__("array('o' => &$o)"), '$pos,$len', 'return php_Boot::__array_splice(array(&$o), $pos, $len);');
-						case 'toString': return php.Boot.__closure(__php__("array('o' => &$o)"), '', 'return "[".join(", ", $o)."]";');
-						case 'unshift':  return php.Boot.__closure(__php__("array('o' => &$o)"), '$x', 'return array_unshift($o, $x);');
-						case 'insert':   return php.Boot.__closure(__php__("array('o' => &$o)"), '$pos,$x', 'return php_Boot::__array_insert(array(&$o), $pos, $x);');
-						case 'remove':   return php.Boot.__closure(__php__("array('o' => &$o)"), '$x', 'return php_Boot::__array_remove(array(&$o), $x);');
-						case 'iterator': return php.Boot.__closure(__php__("array('o' => &$o)"), '', 'return new HArrayIterator($o);');
-						case 'copy':     return php.Boot.__closure(__php__("array('o' => $o)"), '', 'return $o;');
+						case 'concat':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('a'), 'return array_merge($o, $a);')");
+						case 'join':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('sep'), 'return join($sep,$o);')");
+						case 'pop':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array(), 'return array_pop($o);')");
+						case 'push':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('x'), 'return array_push($o,$x);')");
+						case 'reverse':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array(), 'return  rsort($o);')");
+						case 'shift':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array(), 'return array_shift($o);')");
+						case 'slice':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('pos','end'), 'return php_Boot::__array_slice(array(&$o), $pos, $end);')");
+						case 'sort':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('f'), 'return php_Boot::__array_sort($o,$f);')");
+						case 'splice':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('pos','len'), 'return php_Boot::__array_splice(array(&$o), $pos, $len);')");
+						case 'toString':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array(), 'return \"[\".join(\", \", $o).\"]\";')");
+						case 'unshift':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('x'), 'return array_unshift($o,$x);')");
+						case 'insert':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('pos','x'), 'return php_Boot::__array_insert(array(&$o), $pos, $x);')");
+						case 'remove':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array('x'), 'return php_Boot::__array_remove(array(&$o), $x);')");
+						case 'iterator':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array(), 'return new HArrayIterator($o);')");
+						case 'copy':
+							__php__("return php_Boot::__closure(array('o' => &$o), null, array(), 'return $o;')");
 					}
 					}
 				return null;
 				return null;
 			} else if(__php__("property_exists($o, $field)")) {
 			} else if(__php__("property_exists($o, $field)")) {
@@ -317,7 +331,9 @@ class Boot {
 	}
 	}
 
 
 	static public function __byref__array_get(byref__o : Dynamic, index : Dynamic) {
 	static public function __byref__array_get(byref__o : Dynamic, index : Dynamic) {
-		return untyped byref__o[index];
+		var r = null;
+		untyped __php__("if(isset($byref__o[$index])) $r =& $byref__o[$index]");
+		return r;
 	}
 	}
 
 
 	static private var __resources = [];
 	static private var __resources = [];
@@ -382,11 +398,23 @@ set_exception_handler(array('php_Boot', '__exception_handler'));
 class Anonymous extends stdClass{
 class Anonymous extends stdClass{
 	public function __call($m, $a) {
 	public function __call($m, $a) {
 		$v = $this->$m;
 		$v = $this->$m;
+/*
+		if(is_array($v) && is_a($v[0], '_lambda') && $v[0]->scope == null) {
+			$v[0]->scope =& $this;
+		}
+*/
+		/*
 		if(is_string($v) && substr($v, 0, 8) == chr(0).'lambda_') {
 		if(is_string($v) && substr($v, 0, 8) == chr(0).'lambda_') {
 			$nl = '__'.substr($v, 1).'__';
 			$nl = '__'.substr($v, 1).'__';
 			php_Boot::$__scopes[$nl]['scope'] =& $this;
 			php_Boot::$__scopes[$nl]['scope'] =& $this;
 		}
 		}
+		*/
 		try {
 		try {
+			/*
+			if(is_array($v) && is_a($v[0], '_lambda') && is_callable($v)) {
+				return call_user_func_array($v[1], $a);
+			}
+			*/
 			return call_user_func_array($v, $a);
 			return call_user_func_array($v, $a);
 		} catch(Exception $e) {
 		} catch(Exception $e) {
 			throw new HException('Unable to call «'.$m.'»');
 			throw new HException('Unable to call «'.$m.'»');
@@ -519,6 +547,81 @@ class HException extends Exception {
 	}
 	}
 }
 }
 
 
+class _lambda {
+	public function __construct($locals, $scope, $args, $body) {
+		$this->locals = $locals;
+		$this->scope = $scope;
+		$this->args = $args;
+		$this->body = $body;
+	}
+	public $locals;
+	public $scope;
+	public $args;
+	public $body;
+
+	public $params = array();
+	public function execute() {
+		$__this =& $this->scope;
+		foreach(array_keys($this->locals) as ${'%k'})
+			${${'%k'}} =& $this->locals[${'%k'}];
+		for(${'%i'} = 0; ${'%i'} < count($this->args); ${'%i'}++)
+			${$this->args[${'%i'}]} =& $this->params[${'%i'}];
+		return eval($this->body);
+	}
+
+	public function makeArgs() {
+		$this->params = array(func_get_args());
+		return $this->execute();
+	}
+
+	public function execute0() {
+		$this->params = array();
+		return $this->execute();
+	}
+
+	public function execute1(&$_1) {
+		if($this->scope == null) $this->scope= &$_1;
+		$this->params = array(&$_1);
+		return $this->execute();
+	}
+
+	public function execute2(&$_1, &$_2) {
+		if($this->scope == null) $this->scope= &$_1;
+		$this->params = array(&$_1, &$_2);
+		return $this->execute();
+	}
+
+	public function execute3(&$_1, &$_2, &$_3) {
+		if($this->scope == null) $this->scope= &$_1;
+		$this->params = array(&$_1, &$_2, &$_3);
+		return $this->execute();
+	}
+
+	public function execute4(&$_1, &$_2, &$_3, &$_4) {
+		if($this->scope == null) $this->scope= &$_1;
+		$this->params = array(&$_1, &$_2, &$_3, &$_4);
+		return $this->execute();
+	}
+
+	public function execute5(&$_1, &$_2, &$_3, &$_4, &$_5) {
+		if($this->scope == null) $this->scope= &$_1;
+		$this->params = array(&$_1, &$_2, &$_3, &$_4, &$_5);
+		return $this->execute();
+	}
+
+	public function execute6(&$_1, &$_2, &$_3, &$_4, &$_5, &$_6) {
+		if($this->scope == null) $this->scope= &$_1;
+		$this->params = array(&$_1, &$_2, &$_3, &$_4, &$_5, &$_6);
+		return $this->execute();
+	}
+
+	public function execute7(&$_1, &$_2, &$_3, &$_4, &$_5, &$_6, &$_7) {
+		if($this->scope == null) $this->scope= &$_1;
+		$this->params = array(&$_1, &$_2, &$_3, &$_4, &$_5, &$_6, &$_7);
+		return $this->execute();
+	}
+}
+
 class enum {
 class enum {
 	public function __construct($tag, $index, $params = null) { $this->tag = $tag; $this->index = $index; $this->params = $params; }
 	public function __construct($tag, $index, $params = null) { $this->tag = $tag; $this->index = $index; $this->params = $params; }
 	public $tag;
 	public $tag;

+ 38 - 28
std/php/PhpXml__.hx

@@ -209,82 +209,92 @@ class PhpXml__ {
 
 
 	public function iterator() : Iterator<PhpXml__> {
 	public function iterator() : Iterator<PhpXml__> {
 		if( _children == null ) throw "bad nodetype";
 		if( _children == null ) throw "bad nodetype";
-		return untyped {
+		var me = this;
+		var it = null;
+		it = untyped {
 			cur: 0,
 			cur: 0,
-			x: this._children,
+			x: me._children,
 			hasNext : function(){
 			hasNext : function(){
-				return this.cur < __call__("count", this.x);
+				return it.cur < __call__("count", it.x);
 			},
 			},
 			next : function(){
 			next : function(){
-				return this.x[this.cur++];
+				return it.x[it.cur++];
 			}
 			}
 		}
 		}
+		return cast it;
 	}
 	}
 
 
-	public function elements(){
+	public function elements() : Iterator<PhpXml__> {
 		if( _children == null ) throw "bad nodetype";
 		if( _children == null ) throw "bad nodetype";
-		return untyped {
+		var me = this;
+		var it = null;
+		it =  untyped {
 			cur: 0,
 			cur: 0,
-			x: this._children,
+			x: me._children,
 			hasNext : function() {
 			hasNext : function() {
-				var k = this.cur;
-				var l = __call__("count", this.x);
+				var k = it.cur;
+				var l = __call__("count", it.x);
 				while( k < l ) {
 				while( k < l ) {
 
 
-					if( this.x[k].nodeType == Xml.Element )
-						untyped __php__("break");
+					if( it.x[k].nodeType == Xml.Element )
+						__php__("break");
 					k += 1;
 					k += 1;
 				}
 				}
-				this.cur = k;
+				it.cur = k;
 				return k < l;
 				return k < l;
 			},
 			},
 			next : function() {
 			next : function() {
-				var k = this.cur;
-				var l = __call__("count", this.x);
+				var k = it.cur;
+				var l = __call__("count", it.x);
 				while( k < l ) {
 				while( k < l ) {
-					var n = this.x[k];
+					var n = it.x[k];
 					k += 1;
 					k += 1;
 					if( n.nodeType == Xml.Element ) {
 					if( n.nodeType == Xml.Element ) {
-						this.cur = k;
+						it.cur = k;
 						return n;
 						return n;
 					}
 					}
 				}
 				}
 				return null;
 				return null;
 			}
 			}
 		}
 		}
+		return cast it;
 	}
 	}
 
 
-	public function elementsNamed( name : String ) {
+	public function elementsNamed( name : String ) : Iterator<PhpXml__> {
 		if( _children == null ) throw "bad nodetype";
 		if( _children == null ) throw "bad nodetype";
-		return untyped {
+
+		var me = this;
+		var it = null;
+		it =  untyped {
 			cur: 0,
 			cur: 0,
-			x: this._children,
+			x: me._children,
 			hasNext : function() {
 			hasNext : function() {
-				var k = this.cur;
-				var l = __call__("count", this.x);
+				var k = it.cur;
+				var l = __call__("count", it.x);
 				while( k < l ) {
 				while( k < l ) {
-					var n = this.x[k];
+					var n = it.x[k];
 					if( n.nodeType == Xml.Element && n._nodeName == name )
 					if( n.nodeType == Xml.Element && n._nodeName == name )
-						untyped __php__("break");
+						__php__("break");
 					k++;
 					k++;
 				}
 				}
-				this.cur = k;
+				it.cur = k;
 				return k < l;
 				return k < l;
 			},
 			},
 			next : function() {
 			next : function() {
-				var k = this.cur;
-				var l = __call__("count", this.x);
+				var k = it.cur;
+				var l = __call__("count", it.x);
 				while( k < l ) {
 				while( k < l ) {
-					var n = this.x[k];
+					var n = it.x[k];
 					k++;
 					k++;
 					if( n.nodeType == Xml.Element && n._nodeName == name ) {
 					if( n.nodeType == Xml.Element && n._nodeName == name ) {
-						this.cur = k;
+						it.cur = k;
 						return n;
 						return n;
 					}
 					}
 				}
 				}
 				return null;
 				return null;
 			}
 			}
 		}
 		}
+		return cast it;
 	}
 	}
 
 
 	public function firstChild() : PhpXml__ {
 	public function firstChild() : PhpXml__ {