Răsfoiți Sursa

Lua: New version of Reflect & basic object mgmt

Previous versions of the lua compiler used basic table lookups for
field presence.  In Lua, a null field is by definition undetectable.

I've been putting off this change for some time, but we need to
support detectable null-valued fields for normal Haxe functionality.

The new method encapsulates all anonymous objects in a new method call:

```lua
local some_anon = _G.__anon("field1","value", "field2", null);
--[[  some_anon = {field1 = "value", field2=null, __fields = {field1 = true, field2=true}}; --]]
```

The fields and values are given one after another, and passed into a
special helper __anon method.

This method gathers all the field names into a separate lookup
(enabling null-valued fields), and also sets a __newindex metamethod
that will handle the addition of new fields that occur dynamically in
the runtime.

Note that in the above field2 wouldn't be detected in a nomral lua
table, but we can check for its presence in the __fields table instead.

The IntMap, StringMap, and Reflect classes have been updated
appropriately.
Justin Donaldson 9 ani în urmă
părinte
comite
7816e06bb1
4 a modificat fișierele cu 48 adăugiri și 43 ștergeri
  1. 16 4
      genlua.ml
  2. 8 3
      std/lua/_std/Reflect.hx
  3. 14 20
      std/lua/_std/haxe/ds/IntMap.hx
  4. 10 16
      std/lua/_std/haxe/ds/StringMap.hx

+ 16 - 4
genlua.ml

@@ -696,9 +696,9 @@ and gen_expr ?(local=true) ctx e = begin
 		spr ctx "end"; newline ctx;
 		spr ctx "break end";
 	| TObjectDecl fields ->
-		spr ctx "{ ";
-		concat ctx ", " (fun (f,e) -> print ctx "%s = " (anon_field f); gen_value ctx e) fields;
-		spr ctx "}";
+		spr ctx "_G.__anon(";
+		concat ctx ", " (fun (f,e) -> print ctx "\"%s\", " f; gen_value ctx e) fields;
+		spr ctx ")";
 		ctx.separator <- true
 	| TFor (v,it,e) ->
 		let handle_break = handle_break ctx e in
@@ -1667,7 +1667,19 @@ let generate com =
 
 	spr ctx "pcall(require, 'bit32') pcall(require, 'bit') bit = bit or bit32"; newline ctx;
 	spr ctx "print = print or (function()end)"; newline ctx;
-	newline ctx;
+
+	spr ctx "__anon = function(...)"; newline ctx;
+	spr ctx "   local ret = {__fields = {}};"; newline ctx;
+	spr ctx "   local fld = {...};"; newline ctx;
+	spr ctx "   for i,v in ipairs(fld) do"; newline ctx;
+	spr ctx "	if i % 2 == 1 then "; newline ctx;
+	spr ctx "	    ret.__fields[v] = true;"; newline ctx;
+	spr ctx "	    ret[v] =fld[i+1];"; newline ctx;
+	spr ctx "	end"; newline ctx;
+	spr ctx "   end"; newline ctx;
+	spr ctx "   setmetatable(ret, {__newindex=function(t,k,v) t.__fields[k] = true; rawset(t,k,v); end})"; newline ctx;
+	spr ctx "   return ret; "; newline ctx;
+	spr ctx "end"; newline ctx;
 
 	spr ctx "_hxClasses = {}"; semicolon ctx; newline ctx;
 	let vars = [] in

+ 8 - 3
std/lua/_std/Reflect.hx

@@ -22,11 +22,11 @@
 import lua.Lua;
 import lua.Boot;
 @:coreApi class Reflect {
-	static var hidden = ["__id__", "hx__closures", "super", "__index", "new", "prototype"];
+	static var hidden = ["__id__", "hx__closures", "super", "__index", "new", "prototype", "__fields"];
 
 	public inline static function hasField( o : Dynamic, field : String ) : Bool {
 		// TODO: Lua can't detect fields that are set to null, figure out a workaround.
-		return untyped o[field] != null;
+		return untyped o.__fields != null ? o.__fields[field] != null :  o[field] != null;
 	}
 
 	public static function field( o : Dynamic, field : String ) : Dynamic untyped {
@@ -79,7 +79,11 @@ import lua.Boot;
 	}
 
 	public static function fields( o : Dynamic ) : Array<String> {
-		return lua.PairTools.pairsFold(o, function(a,b,c:Array<String>){
+		if (untyped o.__fields != null) return lua.PairTools.pairsFold(o.__fields, function(a,b,c:Array<String>){
+			c.push(a);
+			return c;
+		}, []);
+		else return lua.PairTools.pairsFold(o, function(a,b,c:Array<String>){
 			if (hidden.indexOf(a) == -1) c.push(cast a);
 			return c;
 		}, []);
@@ -111,6 +115,7 @@ import lua.Boot;
 	public static function deleteField( o : Dynamic, field : String ) : Bool untyped {
 		if( !hasField(o,field) ) return false;
 		o[field] = null;
+		o.__fields[field]=null;
 		return true;
 	}
 

+ 14 - 20
std/lua/_std/haxe/ds/IntMap.hx

@@ -25,51 +25,45 @@ import lua.Lua;
 class IntMap<T> implements haxe.Constraints.IMap<Int,T> {
 
 	private var h : Dynamic;
-	private var k : Dynamic;
 
 	public inline function new() : Void {
 		h = {};
-		k = {};
 	}
 
-	public inline function set( key : Int, value : T ) : Void untyped {
+	public inline function set( key : Int, value : T ) : Void {
 		 h[key] = value;
-		 k[key] = true;
 	}
 
-	public inline function get( key : Int ) : Null<T> untyped {
+	public inline function get( key : Int ) : Null<T> {
 		return h[key];
 	}
 
-	public inline function exists( key : Int ) : Bool untyped {
-		return k[key] != null;
+	public inline function exists( key : Int ) : Bool {
+		return Reflect.hasField(h,cast key);
 	}
 
-	public function remove( key : Int ) : Bool untyped {
-		if ( k[key] == null) return false;
-		k[key] = null;
-		h[key] = null;
+	public function remove( key : Int ) : Bool {
+		if (!Reflect.hasField(h,cast key)) return false;
+		Reflect.deleteField(h, cast key);
 		return true;
 	}
 
-	public function keys() : Iterator<Int> untyped {
-		var cur = Lua.next(k,null);
+	public function keys() : Iterator<Int> {
+		var cur = Reflect.fields(h).iterator();
 		return {
 			next : function() {
-				var ret = cur; 
-				cur =  Lua.next(k, cur);
-				return ret;
+				var ret = cur.next();
+				return cast ret;
 			},
-			hasNext : function() return cur != null
+			hasNext : function() return cur.hasNext()
 		}
 	}
 
 	public function iterator() : Iterator<T> {
-		var ref = h;
 		var it = keys();
 		return untyped {
-			hasNext : function() { return it.hasNext(); },
-			next : function() { var i = it.next(); return h[i]; }
+			hasNext : function() return it.hasNext(),
+			next : function() return h[it.next()]
 		};
 	}
 

+ 10 - 16
std/lua/_std/haxe/ds/StringMap.hx

@@ -25,16 +25,13 @@ import lua.Lua;
 class StringMap<T> implements haxe.Constraints.IMap<String,T> {
 
 	private var h : Dynamic;
-	private var k : Dynamic;
 
 	public inline function new() : Void {
 		h = {};
-		k = {};
 	}
 
 	public inline function set( key : String, value : T ) : Void untyped {
 		 h[key] = value;
-		 k[key] = true;
 	}
 
 	public inline function get( key : String ) : Null<T> untyped {
@@ -42,34 +39,31 @@ class StringMap<T> implements haxe.Constraints.IMap<String,T> {
 	}
 
 	public inline function exists( key : String ) : Bool untyped {
-		return k[key] != null;
+		return Reflect.hasField(h, key);
 	}
 
 	public function remove( key : String ) : Bool untyped {
-		if ( k[key] == null) return false;
-		k[key] = null;
-		h[key] = null;
+		if (!Reflect.hasField(h,key)) return false;
+		Reflect.deleteField(h,key);
 		return true;
 	}
 
-	public function keys() : Iterator<String> untyped {
-		var cur = Lua.next(k,null);
+	public function keys() : Iterator<String> {
+		var cur = Reflect.fields(h).iterator();
 		return {
 			next : function() {
-				var ret = cur; 
-				cur = Lua.next(k, cur);
+				var ret = cur.next();
 				return ret;
 			},
-			hasNext : function() return cur != null
+			hasNext : function() return cur.hasNext()
 		}
 	}
 
 	public function iterator() : Iterator<T> {
-		var ref = h;
 		var it = keys();
-		return untyped {
-			hasNext : function() { return it.hasNext(); },
-			next : function() { var i = it.next(); return h[i]; }
+		return  {
+			hasNext : function() return it.hasNext(),
+			next : function() return h[cast it.next()] 
 		};
 	}