Prechádzať zdrojové kódy

[lua] use _hx_string_wrapper helper function instead of modifying string prototype

Justin Donaldson 8 rokov pred
rodič
commit
12d58a843d
3 zmenil súbory, kde vykonal 93 pridanie a 28 odobranie
  1. 71 13
      src/generators/genlua.ml
  2. 8 2
      std/lua/_std/Reflect.hx
  3. 14 13
      std/lua/_std/String.hx

+ 71 - 13
src/generators/genlua.ml

@@ -288,6 +288,13 @@ let rec is_string_type t =
 let is_string_expr e = is_string_type e.etype
 (* /from genphp *)
 
+let is_structural_type t =
+    match follow t with
+    | TDynamic _ -> true
+    | TAnon a -> true
+    | TType ({t_type = TAnon _},_) -> true
+    | _ -> false
+
 let rec is_int_type ctx t =
     match follow t with
     | TInst ({cl_path = ([], "Int")}, _) -> true
@@ -431,6 +438,15 @@ let rec gen_call ctx e el =
      | TField (_, FStatic( { cl_path = ([],"Std") }, { cf_name = "string" })),[{eexpr = TCall({eexpr=TField (_, FStatic( { cl_path = ([],"Std") }, { cf_name = "string" }))}, _)} as el] ->
          (* unwrap recursive Std.string(Std.string(...)) declarations to Std.string(...) *)
          gen_value ctx el;
+     | TField ({eexpr = TLocal _} as e, ef), el when is_possible_string_field e (field_name ef)  ->
+         add_feature ctx "use._hx_wrap_if_string_field";
+         add_feature ctx "use.string";
+         spr ctx "_hx_wrap_if_string_field(";
+         gen_value ctx e;
+         print ctx ",'%s'" (field_name ef);
+         spr ctx ")(";
+         concat ctx "," (gen_value ctx) (e::el);
+         spr ctx ")";
      | TField (e, ((FInstance _ | FAnon _ | FDynamic _) as ef)), el ->
          let s = (field_name ef) in
          if Hashtbl.mem kwds s || not (valid_lua_ident s) then begin
@@ -511,6 +527,29 @@ and gen_loop ctx label cond e =
     ctx.break_depth <- ctx.break_depth-1;
     ctx.handle_continue <- old_handle_continue;
 
+
+and is_possible_string_field e field_name=
+    (* Special case for String fields *)
+    let structural_type = is_structural_type e.etype in
+    if not structural_type then
+        false
+    else match field_name with
+        | "length"
+        | "toUpperCase"
+        | "toLowerCase"
+        | "charAt"
+        | "indexOf"
+        | "lastIndexOf"
+        | "split"
+        | "toString"
+        | "substring"
+        | "substr"
+        | "charCodeAt" ->
+            true
+        | _ ->
+            false
+
+
 and gen_expr ?(local=true) ctx e = begin
     match e.eexpr with
       TConst c ->
@@ -533,10 +572,6 @@ and gen_expr ?(local=true) ctx e = begin
         print ctx "_iterator(";
         gen_value ctx x;
         print ctx ")";
-    | TField (e, f) when is_string_expr e ->
-        spr ctx "(";
-        gen_value ctx e;
-        print ctx ").%s" (field_name f);
     | TField (x,FClosure (_,f)) ->
         add_feature ctx "use._hx_bind";
         (match x.eexpr with
@@ -556,6 +591,15 @@ and gen_expr ?(local=true) ctx e = begin
     | TEnumIndex x ->
         gen_value ctx x;
         print ctx "[1]"
+    | TField (e, ef) when is_string_expr e && field_name ef = "length"->
+        spr ctx "#";
+        gen_value ctx e;
+    | TField (e, ef) when is_possible_string_field e (field_name ef)  ->
+        add_feature ctx "use._hx_wrap_if_string_field";
+        add_feature ctx "use.string";
+        spr ctx "_hx_wrap_if_string_field(";
+        gen_value ctx e;
+        print ctx ",'%s')" (field_name ef)
     | TField (x, (FInstance(_,_,f) | FStatic(_,f) | FAnon(f))) when Meta.has Meta.SelfCall f.cf_meta ->
         gen_value ctx x;
     | TField ({ eexpr = TConst(TInt _ | TFloat _| TString _| TBool _) } as e , ((FInstance _ | FAnon _) as ef)) ->
@@ -679,8 +723,8 @@ and gen_expr ?(local=true) ctx e = begin
                     spr ctx (ident v.v_name);
                     spr ctx " = ";
 
-        (* if it was a multi-return var but it was used as a value itself, *)
-        (* we have to box it in an object conforming to a multi-return extern class *)
+                    (* if it was a multi-return var but it was used as a value itself, *)
+                    (* we have to box it in an object conforming to a multi-return extern class *)
                     let is_boxed_multireturn = Meta.has (Meta.Custom ":lua_mr_box") v.v_meta in
                     let e = if is_boxed_multireturn then mk_mr_box ctx e else e in
                     gen_value ctx e;
@@ -942,7 +986,7 @@ and gen_block_element ctx e  =
             gen_block_element ctx e2;
         | TArrayDecl el | TBlock el ->
             List.iter (gen_block_element ctx) el;
-        (* For plain lua table instantiations, just capture argument operations *)
+            (* For plain lua table instantiations, just capture argument operations *)
         | TCall({ eexpr = TIdent "__lua_table__"} , el) ->
             List.iter(fun x -> gen_block_element ctx x) el
         (* make a no-op __define_feature__ expression possible *)
@@ -985,9 +1029,9 @@ and gen_block_element ctx e  =
             semicolon ctx;
     end;
 
-(* values generated in anon structures can get modified.  Functions are bind-ed *)
-(* and include a dummy "self" leading variable so they can be called like normal *)
-(* instance methods *)
+    (* values generated in anon structures can get modified.  Functions are bind-ed *)
+    (* and include a dummy "self" leading variable so they can be called like normal *)
+    (* instance methods *)
 and gen_anon_value ctx e =
     match e with
     | { eexpr = TFunction f} ->
@@ -1956,9 +2000,9 @@ let generate com =
     (* If we use haxe Strings, patch Lua's string *)
     if has_feature ctx "use.string" then begin
         println ctx "local _hx_string_mt = _G.getmetatable('');";
-        println ctx "String.__oldindex = _hx_string_mt.__index;";
-        println ctx "_hx_string_mt.__index = String.__index;";
-        println ctx "_hx_string_mt.__add = function(a,b) return Std.string(a)..Std.string(b) end;";
+        (* println ctx "String.__oldindex = _hx_string_mt.__index;"; *)
+        (* println ctx "_hx_string_mt.__index = String.__index;"; *)
+        println ctx "_hx_string_mt.__add = function(a,b) return _G.table.concat({Std.string(a),Std.string(b)}) end;";
         println ctx "_hx_string_mt.__concat = _hx_string_mt.__add";
     end;
 
@@ -2067,6 +2111,20 @@ let generate com =
         println ctx "end;";
     end;
 
+    if has_feature ctx "use._hx_wrap_if_string_field" then begin
+        println ctx "_hx_wrap_if_string_field = function(o, fld)";
+        println ctx "  if _G.type(o) == 'string' then";
+        println ctx "    if fld == 'length' then";
+        println ctx "      return _G.string.len(o)";
+        println ctx "    else";
+        println ctx "      return String.prototype[fld]";
+        println ctx "    end";
+        println ctx "  else";
+        println ctx "    return o[fld]";
+        println ctx "  end";
+        println ctx "end";
+    end;
+
     println ctx "_hx_static_init();";
 
     List.iter (generate_enumMeta_fields ctx) com.types;

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

@@ -25,11 +25,17 @@ import lua.Boot;
 @:coreApi class Reflect {
 
 	public inline static function hasField( o : Dynamic, field : String ) : Bool {
-		return untyped o.__fields__ != null ? o.__fields__[field] != null :  o[field] != null;
+		if (Lua.type(o) == "string" && (untyped String.prototype[field] != null || field == "length")){
+			return true;
+		} else return untyped o.__fields__ != null ? o.__fields__[field] != null :  o[field] != null;
 	}
 
 	public static function field( o : Dynamic, field : String ) : Dynamic untyped {
-		return try o[field] catch( e : Dynamic ) null;
+		if (Lua.type(o) == "string"){
+			if (field == "length"){
+				return lua.NativeStringTools.len(o);
+			} else return untyped String.prototype[field];
+		} else return try o[field] catch( e : Dynamic ) null;
 	}
 
 	public inline static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped {

+ 14 - 13
std/lua/_std/String.hx

@@ -26,12 +26,12 @@ import lua.Boot;
 import lua.NativeStringTools;
 
 @:coreApi
+@:extern
 class String {
 	static var __oldindex : String->String->Dynamic;
 	public var length(default,null) : Int;
 
-
-	public function new(string:String) untyped {}
+	public inline function new(string:String) untyped {}
 
 	@:keep
 	static function __index(s:Dynamic, k:Dynamic) : Dynamic {
@@ -48,9 +48,9 @@ class String {
 		else return null;
 	}
 
-	public function toUpperCase() : String return NativeStringTools.upper(this);
-	public function toLowerCase() : String return NativeStringTools.lower(this);
-	public function indexOf( str : String, ?startIndex : Int ) : Int {
+	public inline function toUpperCase() : String return NativeStringTools.upper(this);
+	public inline function toLowerCase() : String return NativeStringTools.lower(this);
+	public inline function indexOf( str : String, ?startIndex : Int ) : Int {
 		if (startIndex == null) startIndex = 1;
 		else startIndex += 1;
 		var r = NativeStringTools.find(this, str, startIndex, true).begin;
@@ -58,18 +58,19 @@ class String {
 		else return -1;
 	}
 
-	public function lastIndexOf( str : String, ?startIndex : Int ) : Int {
+	public inline function lastIndexOf( str : String, ?startIndex : Int ) : Int {
 		var i = 0;
 		var ret = -1;
 		if( startIndex == null ) startIndex = length;
 		while( true ) {
 			var p = indexOf(str, ret+1);
-			if( p == -1 || p > startIndex ) return ret;
+			if( p == -1 || p > startIndex ) break;
 			ret = p;
 		}
+		return ret;
 	}
 
-	public function split( delimiter : String ) : Array<String> {
+	public inline function split( delimiter : String ) : Array<String> {
 		var idx = 1;
 		var ret = [];
 		var delim_offset = delimiter.length > 0 ? delimiter.length : 1;
@@ -95,10 +96,10 @@ class String {
 		return ret;
 	}
 
-	public function toString() : String {
+	public inline function toString() : String {
 		return this;
 	}
-	public function substring( startIndex : Int, ?endIndex : Int ) : String {
+	public inline function substring( startIndex : Int, ?endIndex : Int ) : String {
 		if (endIndex == null) endIndex = this.length;
 		if (endIndex < 0) endIndex = 0;
 		if (startIndex < 0) startIndex = 0;
@@ -113,14 +114,14 @@ class String {
 	function get_length() : Int {
 		return NativeStringTools.len(this);
 	}
-	public function charAt( index : Int) : String {
+	public inline function charAt( index : Int) : String {
 		return NativeStringTools.sub(this,index+1, index+1).match;
 	}
-	public function charCodeAt( index : Int) : Null<Int> {
+	public inline function charCodeAt( index : Int) : Null<Int> {
 		return NativeStringTools.byte(this,index+1);
 	}
 
-	public function substr( pos : Int, ?len : Int ) : String {
+	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;
 		if (pos < 0) pos = length + pos;