Browse Source

[lua] refactor runtime tostring to separate lua file

Justin Donaldson 5 years ago
parent
commit
0bab113dc0

+ 6 - 3
src/generators/genlua.ml

@@ -1965,13 +1965,16 @@ let generate com =
         print ctx "%s\n" file_content;
         print ctx "%s\n" file_content;
     in
     in
 
 
-    (* table-to-array helper *)
+    (* base table-to-array helpers and metatables *)
     print_file (Common.find_file com "lua/_lua/_hx_tab_array.lua");
     print_file (Common.find_file com "lua/_lua/_hx_tab_array.lua");
 
 
-    (* lua workarounds for basic anonymous object functionality *)
+    (* base lua "toString" functionality for haxe objects*)
+    print_file (Common.find_file com "lua/_lua/_hx_tostring.lua");
+
+    (* base lua metatables for prototypes, inheritance, etc. *)
     print_file (Common.find_file com "lua/_lua/_hx_anon.lua");
     print_file (Common.find_file com "lua/_lua/_hx_anon.lua");
 
 
-    (* class reflection metadata *)
+    (* base runtime class stubs for haxe value types (Int, Float, etc) *)
     print_file (Common.find_file com "lua/_lua/_hx_classes.lua");
     print_file (Common.find_file com "lua/_lua/_hx_classes.lua");
 
 
     let include_files = List.rev com.include_files in
     let include_files = List.rev com.include_files in

+ 0 - 104
std/lua/Boot.hx

@@ -153,110 +153,6 @@ class Boot {
 			throw "Cannot cast " + Std.string(o) + " to " + Std.string(t);
 			throw "Cannot cast " + Std.string(o) + " to " + Std.string(t);
 	}
 	}
 
 
-	/**
-		Helper method to generate a string representation of an enum
-	**/
-	static function printEnum(o:Array<Dynamic>, s:String) {
-		if (o.length == 2) {
-			return o[0];
-		} else {
-			// parameterized enums are arrays
-			var str = o[0] + "(";
-			s += "\t";
-			for (i in 2...o.length) {
-				if (i != 2)
-					str += "," + __string_rec(o[i], s);
-				else
-					str += __string_rec(o[i], s);
-			}
-			return str + ")";
-		}
-	}
-
-	/**
-		Helper method to generate a string representation of a class
-	**/
-	static inline function printClass(c:Table<String, Dynamic>, s:String):String {
-		return '{${printClassRec(c, '', s)}}';
-	}
-
-	/**
-		Helper method to generate a string representation of a class
-	**/
-	static function printClassRec(c:Table<String, Dynamic>, result = '', s:String):String {
-		var f = Boot.__string_rec;
-		untyped __lua__("for k,v in pairs(c) do if result ~= '' then result = result .. ', ' end result = result .. k .. ':' .. f(v, s.. '\t') end");
-		return result;
-	}
-
-	/**
-		Generate a string representation for arbitrary object.
-	**/
-	@:ifFeature("has_enum")
-	static function __string_rec(o:Dynamic, s:String = "") {
-		if (s.length >= 5)
-			return "<...>";
-		return switch (untyped __type__(o)) {
-			case "nil": "null";
-			case "number": {
-					if (o == std.Math.POSITIVE_INFINITY)
-						"Infinity";
-					else if (o == std.Math.NEGATIVE_INFINITY)
-						"-Infinity";
-					else if (o == 0)
-						"0";
-					else if (o != o)
-						"NaN";
-					else
-						untyped tostring(o);
-				}
-			case "boolean": untyped tostring(o);
-			case "string": o;
-			case "userdata": {
-					var mt = lua.Lua.getmetatable(o);
-					if (mt != null && mt.__tostring != null) {
-						lua.Lua.tostring(o);
-					} else {
-						"<userdata>";
-					}
-				}
-			case "function": "<function>";
-			case "thread": "<thread>";
-			case "table": {
-					if (o.__enum__ != null)
-						printEnum(o, s);
-					else if (o.toString != null && !isArray(o))
-						o.toString();
-					else if (isArray(o)) {
-						var o2:Array<Dynamic> = untyped o;
-						if (s.length > 5)
-							"[...]"
-						else
-							'[${[for (i in o2) __string_rec(i, s + 1)].join(",")}]';
-					} else if (o.__class__ != null)
-						printClass(o, s + "\t");
-					else {
-						var fields = fieldIterator(o);
-						var buffer:Table<Int, String> = Table.create();
-						var first = true;
-						Table.insert(buffer, "{ ");
-						for (f in fields) {
-							if (first)
-								first = false;
-							else
-								Table.insert(buffer, ", ");
-							Table.insert(buffer, '${Std.string(f)} : ${untyped __string_rec(o[f], s + "\t")}');
-						}
-						Table.insert(buffer, " }");
-						Table.concat(buffer, "");
-					}
-				};
-			default: {
-					throw "Unknown Lua type";
-					null;
-				}
-		}
-	}
 
 
 	/**
 	/**
 		Define an array from the given table
 		Define an array from the given table

+ 2 - 2
std/lua/_lua/_hx_anon.lua

@@ -1,5 +1,5 @@
 local function _hx_obj_newindex(t,k,v) t.__fields__[k] = true; rawset(t,k,v); end
 local function _hx_obj_newindex(t,k,v) t.__fields__[k] = true; rawset(t,k,v); end
-local _hx_obj_mt = {__newindex=_hx_anon_newindex}
+local _hx_obj_mt = {__newindex=_hx_obj_newindex, __tostring=_hx_tostring}
 local function _hx_a(...)
 local function _hx_a(...)
   local __fields__ = {};
   local __fields__ = {};
   local ret = {__fields__ = __fields__};
   local ret = {__fields__ = __fields__};
@@ -24,5 +24,5 @@ local function _hx_o(obj)
 end
 end
 
 
 local function _hx_new(prototype)
 local function _hx_new(prototype)
-  return setmetatable({__fields__ = {}}, {__newindex=_hx_anon_newindex, __index=prototype})
+  return setmetatable({__fields__ = {}}, {__newindex=_hx_anon_newindex, __index=prototype, __tostring=_hx_tostring})
 end
 end

+ 17 - 9
std/lua/_lua/_hx_tab_array.lua

@@ -1,12 +1,20 @@
-local _hx_array_mt = {
-  __newindex = function(t,k,v)
-    local len = t.length
-    t.length =  k >= len and (k + 1) or len
-    rawset(t,k,v)
-  end
+_hx_array_mt = {
+    __newindex = function(t,k,v)
+        local len = t.length
+        t.length =  k >= len and (k + 1) or len
+        rawset(t,k,v)
+    end
 }
 }
 
 
-local function _hx_tab_array(tab,length)
-  tab.length = length
-  return setmetatable(tab, _hx_array_mt)
+function _hx_is_array(o)
+    return type(o) == "table"
+        and o.__enum__ == nil
+        and getmetatable(o) == _hx_array_mt
+end
+
+
+
+function _hx_tab_array(tab, length)
+    tab.length = length
+    return setmetatable(tab, _hx_array_mt)
 end
 end

+ 93 - 0
std/lua/_lua/_hx_tostring.lua

@@ -0,0 +1,93 @@
+local _hx_hidden = {__id__=true, hx__closures=true, super=true, prototype=true, __fields__=true, __ifields__=true, __class__=true, __properties__=true}
+
+function _hx_print_class(obj, depth)
+    local first = true
+    local result = ''
+    for k,v in pairs(obj) do
+        if first then
+            result = result .. ','
+            first = false
+        end
+        if _hx_hidden[k] == nil then
+            result = result .. k .. ':' .. _hx_tostring(v, depth+1)
+        end
+    end
+    return result
+end
+
+function _hx_print_enum(o, depth)
+    if o.length == 2 then
+        return o[0]
+    else
+        local str = o[0] .. "(";
+        for i = 2, (o.length-1) do
+            if i ~= 2 then
+                str = str .. "," .. _hx_tostring(o[i], depth+1);
+            else
+                str = str .. _hx_tostring(o[i], depth+1);
+            end
+        end
+        return str .. ")";
+    end
+end
+
+function _hx_tostring(obj, depth)
+    if depth == nil then
+        depth = 0
+    elseif depth > 5 then
+        return "<...>"
+    end
+
+    local tstr = type(obj)
+    if tstr == "string" then return obj
+    elseif tstr == "nil" then return "null";
+    elseif tstr == "number" then
+        if obj == _G.math.POSITIVE_INFINITY then return "Infinity";
+        elseif obj == _G.math.NEGATIVE_INFINITY then return "-Infinity";
+        elseif obj == 0 then return "0";
+        elseif obj ~= obj then return "NaN";
+        else return _G.tostring(obj);
+        end
+    elseif tstr == "boolean" then return _G.tostring(obj);
+    elseif tstr == "userdata" then
+        local mt = _G.getmetatable(obj);
+        if mt ~= nil and mt.__tostring ~= nil then
+            return _G.tostring(obj);
+        else
+            return "<userdata>";
+        end
+    elseif tstr == "function" then return "<function>";
+    elseif tstr == "thread" then return "<thread>";
+    elseif tstr == "table" then
+        if obj.__enum__ ~= nil then
+            return _hx_print_enum(obj, depth)
+        elseif obj.toString ~= nil and not _hx_is_array(obj) then return obj:toString()
+        elseif _hx_is_array(obj) then
+            if obj.length > 5 then
+                return "[...]"
+            else
+                str = ""
+                for i=0, (obj.length-1) do
+                    if i == 0 then
+                        str = str .. _hx_tostring(obj[i])
+                    else
+                        str = str .. "," .. _hx_tostring(obj[i])
+                    end
+                end
+                return "[" .. str .. "]"
+            end
+        elseif obj.__class__ ~= nil then
+            return _hx_print_class(obj, depth)
+        else
+            first = true
+            buffer = {}
+            for k,v in pairs(obj) do
+                _G.table.insert(buffer, _hx_tostring(k, depth) .. ' : ' .. _hx_tostring(obj[k], depth))
+            end
+            return "{ " .. table.concat(buffer, ", ") .. " }"
+        end
+    else
+        _G.error("Unknown Lua type", 0)
+        return ""
+    end
+end

+ 2 - 2
std/lua/_std/Std.hx

@@ -43,8 +43,8 @@ import lua.NativeStringTools;
 	}
 	}
 
 
 	@:keep
 	@:keep
-	public static function string(s:Dynamic):String {
-		return untyped lua.Boot.__string_rec(s);
+	public static function string(s:Dynamic) : String {
+		return untyped _hx_tostring(s, 0);
 	}
 	}
 
 
 	public static function int(x:Float):Int {
 	public static function int(x:Float):Int {