Browse Source

[lua] wip on lua 5.1 support

[lua] missing args for unpack

[lua] move pack/unpack back to table extern with polyfill, more multireturn behavior and fixes

[lua] lua-5.1 support for string escapes (using dec instead of hex encoding)

[lua] use a single _hx_break variable to track breaks in when/continue contexts
Justin Donaldson 9 years ago
parent
commit
947e534d1d
7 changed files with 94 additions and 38 deletions
  1. 78 28
      src/generators/genlua.ml
  2. 1 1
      std/lua/Lib.hx
  3. 6 1
      std/lua/Os.hx
  4. 3 2
      std/lua/Table.hx
  5. 3 3
      std/lua/_std/EReg.hx
  6. 2 2
      std/lua/_std/String.hx
  7. 1 1
      std/lua/_std/Sys.hx

+ 78 - 28
src/generators/genlua.ml

@@ -39,6 +39,7 @@ type ctx = {
 	mutable in_loop : bool;
 	mutable in_loop : bool;
 	mutable iife_assign : bool;
 	mutable iife_assign : bool;
 	mutable handle_break : bool;
 	mutable handle_break : bool;
+	mutable handle_continue : bool;
 	mutable id_counter : int;
 	mutable id_counter : int;
 	mutable type_accessor : module_type -> string;
 	mutable type_accessor : module_type -> string;
 	mutable separator : bool;
 	mutable separator : bool;
@@ -70,6 +71,23 @@ let dot_path = Ast.s_type_path
 
 
 let s_path ctx = dot_path
 let s_path ctx = dot_path
 
 
+(* Lua requires decimal encoding for characters, rather than the hex *)
+(* provided by Ast.s_escape *)
+let s_escape_lua ?(dec=true) s =
+	let b = Buffer.create (String.length s) in
+	for i = 0 to (String.length s) - 1 do
+		match s.[i] with
+		| '\n' -> Buffer.add_string b "\\n"
+		| '\t' -> Buffer.add_string b "\\t"
+		| '\r' -> Buffer.add_string b "\\r"
+		| '"' -> Buffer.add_string b "\\\""
+		| '\\' -> Buffer.add_string b "\\\\"
+		| c when int_of_char c < 32 && dec ->
+			Buffer.add_string b (Printf.sprintf "\\%.3d" (int_of_char c))
+		| c -> Buffer.add_char b c
+	done;
+	Buffer.contents b
+
 (* TODO: are all these kwds necessary for field quotes *and* id escapes? *)
 (* TODO: are all these kwds necessary for field quotes *and* id escapes? *)
 let kwds =
 let kwds =
 	let h = Hashtbl.create 0 in
 	let h = Hashtbl.create 0 in
@@ -97,7 +115,7 @@ let valid_lua_ident s =
 let field s = if Hashtbl.mem kwds s || not (valid_lua_ident s) then "[\"" ^ s ^ "\"]" else "." ^ s
 let field s = if Hashtbl.mem kwds s || not (valid_lua_ident s) then "[\"" ^ s ^ "\"]" else "." ^ s
 let ident s = if Hashtbl.mem kwds s then "_" ^ s else s
 let ident s = if Hashtbl.mem kwds s then "_" ^ s else s
 
 
-let anon_field s = if Hashtbl.mem kwds s || not (valid_lua_ident s) then "['" ^ (Ast.s_escape s) ^ "']" else s
+let anon_field s = if Hashtbl.mem kwds s || not (valid_lua_ident s) then "['" ^ (s_escape_lua s) ^ "']" else s
 let static_field c s =
 let static_field c s =
 	match s with
 	match s with
 	| "length" | "name" when not c.cl_extern || Meta.has Meta.HxGen c.cl_meta-> "._hx" ^ s
 	| "length" | "name" when not c.cl_extern || Meta.has Meta.HxGen c.cl_meta-> "._hx" ^ s
@@ -258,7 +276,7 @@ let mk_mr_box ctx e =
 	in
 	in
 	add_feature ctx "use._hx_box_mr";
 	add_feature ctx "use._hx_box_mr";
 	add_feature ctx "use._hx_tbl_pack";
 	add_feature ctx "use._hx_tbl_pack";
-	let code = Printf.sprintf "_hx_box_mr(_hx_tbl_pack({0}), {%s})" s_fields in
+	let code = Printf.sprintf "_hx_box_mr(_G.table.pack({0}), {%s})" s_fields in
 	mk_lua_code ctx.com code [e] e.etype e.epos
 	mk_lua_code ctx.com code [e] e.etype e.epos
 
 
 (* create a multi-return select call for given expr and field name *)
 (* create a multi-return select call for given expr and field name *)
@@ -313,7 +331,7 @@ let gen_constant ctx p = function
 	| TFloat s -> spr ctx s
 	| TFloat s -> spr ctx s
 	| TString s -> begin
 	| TString s -> begin
 	    add_feature ctx "use.string";
 	    add_feature ctx "use.string";
-	    print ctx "\"%s\"" (Ast.s_escape s)
+	    print ctx "\"%s\"" (s_escape_lua s)
 	end
 	end
 	| TBool b -> spr ctx (if b then "true" else "false")
 	| TBool b -> spr ctx (if b then "true" else "false")
 	| TNull -> spr ctx "nil"
 	| TNull -> spr ctx "nil"
@@ -547,10 +565,15 @@ and gen_expr ?(local=true) ctx e = begin
 	| TReturn eo -> gen_return ctx e eo;
 	| TReturn eo -> gen_return ctx e eo;
 	| TBreak ->
 	| TBreak ->
 		if not ctx.in_loop then unsupported e.epos;
 		if not ctx.in_loop then unsupported e.epos;
-		if ctx.handle_break then spr ctx "_G.error(\"_hx__break__\")" else spr ctx "break" (*todo*)
+		if ctx.handle_break then
+		    spr ctx "_G.error(\"_hx__break__\")"
+		else if ctx.handle_continue then
+		    spr ctx "_hx_break = true; break"
+		else
+		    spr ctx "break" (*todo*)
 	| TContinue ->
 	| TContinue ->
 		if not ctx.in_loop then unsupported e.epos;
 		if not ctx.in_loop then unsupported e.epos;
-		spr ctx "goto _hx_continue";
+		spr ctx "break";
 	| TBlock el ->
 	| TBlock el ->
 		let bend = open_block ctx in
 		let bend = open_block ctx in
 		List.iter (gen_block_element ctx) el;
 		List.iter (gen_block_element ctx) el;
@@ -643,7 +666,8 @@ and gen_expr ?(local=true) ctx e = begin
 		end
 		end
 	| TNew (c,_,el) ->
 	| TNew (c,_,el) ->
 		(match c.cl_constructor with
 		(match c.cl_constructor with
-		| Some cf when Meta.has Meta.SelfCall cf.cf_meta -> ()
+		| Some cf when Meta.has Meta.SelfCall cf.cf_meta ->
+			print ctx "%s" (ctx.type_accessor (TClassDecl c));
 		| _ -> print ctx "%s.new" (ctx.type_accessor (TClassDecl c)));
 		| _ -> print ctx "%s.new" (ctx.type_accessor (TClassDecl c)));
 		spr ctx "(";
 		spr ctx "(";
 		concat ctx "," (gen_value ctx) el;
 		concat ctx "," (gen_value ctx) el;
@@ -744,38 +768,58 @@ and gen_expr ?(local=true) ctx e = begin
 		spr ctx (Ast.s_unop op)
 		spr ctx (Ast.s_unop op)
 	| TWhile (cond,e,Ast.NormalWhile) ->
 	| TWhile (cond,e,Ast.NormalWhile) ->
 		let handle_break = handle_break ctx e in
 		let handle_break = handle_break ctx e in
+		let has_continue = has_continue e in
+		let old_ctx_continue = ctx.handle_continue in
+		ctx.handle_continue <- has_continue;
 		spr ctx "while ";
 		spr ctx "while ";
 		gen_cond ctx cond;
 		gen_cond ctx cond;
-		spr ctx " do ";
 		let b = open_block ctx in
 		let b = open_block ctx in
-		gen_block_element ctx e;
-		b();
-		if has_continue e then begin
-		    newline ctx;
-		    spr ctx "::_hx_continue::";
+		println ctx " do ";
+		let b2 = open_block ctx in
+		if has_continue then begin
+		    spr ctx "repeat "
 		end;
 		end;
+		gen_block_element ctx e;
 		newline ctx;
 		newline ctx;
 		handle_break();
 		handle_break();
+		if has_continue then begin
+		    b2();
+		    newline ctx;
+		    println ctx "until true";
+		    print ctx "if _hx_break then _hx_break = false; break; end";
+		end;
+		b();
 		newline ctx;
 		newline ctx;
 		spr ctx "end";
 		spr ctx "end";
+		ctx.handle_continue <- old_ctx_continue;
 	| TWhile (cond,e,Ast.DoWhile) ->
 	| TWhile (cond,e,Ast.DoWhile) ->
 		let handle_break = handle_break ctx e in
 		let handle_break = handle_break ctx e in
-		spr ctx "while true do ";
+		let has_continue = has_continue e in
+		let old_ctx_continue = ctx.handle_continue in
+		ctx.handle_continue <- has_continue;
+		println ctx "while true do ";
 		gen_block_element ctx e;
 		gen_block_element ctx e;
 		newline ctx;
 		newline ctx;
 		spr ctx " while ";
 		spr ctx " while ";
 		gen_cond ctx cond;
 		gen_cond ctx cond;
-		spr ctx " do ";
+		let b = open_block ctx in
+		println ctx " do ";
+		let b2 = open_block ctx in
+		if has_continue then begin
+		    spr ctx "repeat "
+		end;
 		gen_block_element ctx e;
 		gen_block_element ctx e;
 		handle_break();
 		handle_break();
-		newline ctx;
-		if has_continue e then begin
+		if has_continue then begin
+		    b2();
 		    newline ctx;
 		    newline ctx;
-		    spr ctx "::_hx_continue::";
+		    println ctx "until true";
+		    print ctx "if _hx_break then _hx_break = false; break; end";
 		end;
 		end;
+		b();
 		newline ctx;
 		newline ctx;
-		println ctx "end";
-		spr ctx "break end";
+		spr ctx "end";
+		ctx.handle_continue <- old_ctx_continue;
 	| TObjectDecl [] ->
 	| TObjectDecl [] ->
 		spr ctx "_hx_e()";
 		spr ctx "_hx_e()";
 		ctx.separator <- true
 		ctx.separator <- true
@@ -1456,7 +1500,7 @@ let generate_class___name__ ctx c =
 		let p = s_path ctx c.cl_path in
 		let p = s_path ctx c.cl_path in
 		print ctx "%s.__name__ = " p;
 		print ctx "%s.__name__ = " p;
 		if has_feature ctx "Type.getClassName" then
 		if has_feature ctx "Type.getClassName" then
-			println ctx "{%s}" (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst c.cl_path @ [snd c.cl_path])))
+			println ctx "{%s}" (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" (s_escape_lua s)) (fst c.cl_path @ [snd c.cl_path])))
 		else
 		else
 			println ctx "true";
 			println ctx "true";
 	end
 	end
@@ -1576,7 +1620,7 @@ let generate_class ctx c =
 
 
 let generate_enum ctx e =
 let generate_enum ctx e =
 	let p = s_path ctx e.e_path in
 	let p = s_path ctx e.e_path in
-	let ename = List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst e.e_path @ [snd e.e_path]) in
+	let ename = List.map (fun s -> Printf.sprintf "\"%s\"" (s_escape_lua s)) (fst e.e_path @ [snd e.e_path]) in
 
 
 	(* TODO: Unify the _hxClasses declaration *)
 	(* TODO: Unify the _hxClasses declaration *)
 	if has_feature ctx "Type.resolveEnum" then begin
 	if has_feature ctx "Type.resolveEnum" then begin
@@ -1734,6 +1778,7 @@ let alloc_ctx com =
 		iife_assign = false;
 		iife_assign = false;
 		in_loop = false;
 		in_loop = false;
 		handle_break = false;
 		handle_break = false;
+		handle_continue = false;
 		id_counter = 0;
 		id_counter = 0;
 		type_accessor = (fun _ -> assert false);
 		type_accessor = (fun _ -> assert false);
 		separator = false;
 		separator = false;
@@ -1914,11 +1959,10 @@ let generate com =
 	List.iter (generate_type_forward ctx) com.types; newline ctx;
 	List.iter (generate_type_forward ctx) com.types; newline ctx;
 
 
 	(* Generate some dummy placeholders for utility libs that may be required*)
 	(* Generate some dummy placeholders for utility libs that may be required*)
-	println ctx "local _hx_bind, _hx_bit, _hx_staticToInstance, _hx_funcToField, _hx_maxn, _hx_print, _hx_apply_self, _hx_box_mr, _hx_tbl_pack";
+	println ctx "local _hx_bind, _hx_bit, _hx_staticToInstance, _hx_funcToField, _hx_maxn, _hx_print, _hx_apply_self, _hx_box_mr, _hx_break = false";
 
 
 	if has_feature ctx "use._bitop" || has_feature ctx "lua.Boot.clamp" then begin
 	if has_feature ctx "use._bitop" || has_feature ctx "lua.Boot.clamp" then begin
-	    println ctx "pcall(require, 'bit32') pcall(require, 'bit')";
-	    println ctx "local _hx_bit_raw = bit or bit32";
+	    println ctx "local _hx_bit_raw = require 'bit32'";
 	    println ctx "local function _hx_bit_clamp(v) return _hx_bit_raw.band(v, 2147483647 ) - _hx_bit_raw.band(v, 2147483648) end";
 	    println ctx "local function _hx_bit_clamp(v) return _hx_bit_raw.band(v, 2147483647 ) - _hx_bit_raw.band(v, 2147483648) end";
 	    println ctx "if type(jit) == 'table' then";
 	    println ctx "if type(jit) == 'table' then";
 	    println ctx "_hx_bit = setmetatable({},{__index = function(t,k) return function(...) return _hx_bit_clamp(rawget(_hx_bit_raw,k)(...)) end end})";
 	    println ctx "_hx_bit = setmetatable({},{__index = function(t,k) return function(...) return _hx_bit_clamp(rawget(_hx_bit_raw,k)(...)) end end})";
@@ -2049,11 +2093,16 @@ let generate com =
 	    println ctx "end";
 	    println ctx "end";
 	end;
 	end;
 
 
-	if has_feature ctx "use._hx_tbl_pack" then begin
-	    println ctx "_hx_tbl_pack = function(...)";
-	    println ctx "  return {n=select('#',...),...}";
+	(* if has_feature ctx "use.table" then begin *)
+	    println ctx "if not _G.table.pack then";
+	    println ctx "  _G.table.pack = function(...)";
+	    println ctx "    return {...}";
+	    println ctx "  end";
 	    println ctx "end";
 	    println ctx "end";
-	end;
+	    println ctx "if not _G.table.unpack then";
+	    println ctx " _G.table.unpack = _G.unpack";
+	    println ctx "end";
+	(* end; *)
 
 
 
 
 	List.iter (generate_enumMeta_fields ctx) com.types;
 	List.iter (generate_enumMeta_fields ctx) com.types;
@@ -2069,3 +2118,4 @@ let generate com =
 	close_out ch;
 	close_out ch;
 	t()
 	t()
 
 
+

+ 1 - 1
std/lua/Lib.hx

@@ -71,6 +71,6 @@ class Lib {
 	}
 	}
 
 
 	public inline static function isShellAvailable() : Bool {
 	public inline static function isShellAvailable() : Bool {
-		return Os.execute();
+		return Os.execute().status > 0;
 	}
 	}
 }
 }

+ 6 - 1
std/lua/Os.hx

@@ -28,7 +28,7 @@ extern class Os {
 		which is system-dependent. If command is absent, then it returns 
 		which is system-dependent. If command is absent, then it returns 
 		nonzero if a shell is available and zero otherwise.
 		nonzero if a shell is available and zero otherwise.
 	**/
 	**/
-	public static function execute(?command:String) : Bool;
+	public static function execute(?command:String) : OsExecute;
 
 
 	/**
 	/**
 		Calls the C function exit, with an optional code, to terminate the host program. 
 		Calls the C function exit, with an optional code, to terminate the host program. 
@@ -108,3 +108,8 @@ typedef DateType = {
 	yday  : Int,
 	yday  : Int,
 	day   : Int,
 	day   : Int,
 }
 }
+
+@:multiReturn extern class OsExecute {
+	var output : String;
+	var status : Int;
+}

+ 3 - 2
std/lua/Table.hx

@@ -23,8 +23,9 @@ extern class Table<A,B> implements ArrayAccess<B> implements Dynamic<B> {
 	@:overload(function<B>(table:Table<Int,B>):Void{})
 	@:overload(function<B>(table:Table<Int,B>):Void{})
 	public static function remove<B>(table:Table<Int,B>, ?pos:Int) : Void;
 	public static function remove<B>(table:Table<Int,B>, ?pos:Int) : Void;
 
 
-	public static function pack<T>(args:T) : Table<Int,T>;
-	public static function unpack(arg:Table<Dynamic,Dynamic>, ?min:Int, ?max:Int) : Dynamic;
+	public static function pack<T>(args:haxe.extern.Rest<T>) : Table<Int,T>;
+	public static function unpack<Int,V>(args:lua.Table<Int,V>, ?min : Int, ?max : Int) : Dynamic;
+
 }
 }
 
 
 typedef AnyTable = Table<Dynamic, Dynamic>;
 typedef AnyTable = Table<Dynamic, Dynamic>;

+ 3 - 3
std/lua/_std/EReg.hx

@@ -51,7 +51,7 @@ class EReg {
 	}
 	}
 
 
 	public function match( s : String ) : Bool {
 	public function match( s : String ) : Bool {
-		this.m = Table.pack(r.exec(s));
+		this.m = lua.Table.pack(r.exec(s));
 		this.s = s;
 		this.s = s;
 		return  m[1] != null;
 		return  m[1] != null;
 	}
 	}
@@ -93,14 +93,14 @@ class EReg {
 		var ss = s.substr(0, len < 0 ? s.length : pos + len);
 		var ss = s.substr(0, len < 0 ? s.length : pos + len);
 
 
 		if (global){
 		if (global){
-			m = Table.pack(r.exec(ss, pos + 1));
+			m = lua.Table.pack(r.exec(ss, pos + 1));
 			var b = m[1] != null;
 			var b = m[1] != null;
 			if (b){
 			if (b){
 				this.s = s;
 				this.s = s;
 			}
 			}
 			return b;
 			return b;
 		} else {
 		} else {
-			m = Table.pack(r.exec(ss, pos + 1));
+			m = lua.Table.pack(r.exec(ss, pos + 1));
 			var b = m[1] != null;
 			var b = m[1] != null;
 			if (b){
 			if (b){
 				this.s = s;
 				this.s = s;

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

@@ -35,13 +35,12 @@ class String {
 
 
 	@:keep
 	@:keep
 	static function __index(s:Dynamic, k:Dynamic) : Dynamic {
 	static function __index(s:Dynamic, k:Dynamic) : Dynamic {
-		if (k == "length") return untyped __lua__("#s");
+		if (k == "length") return NativeStringTools.len(s);
 		else if (Reflect.hasField(untyped String.prototype, k)) return untyped String.prototype[k];
 		else if (Reflect.hasField(untyped String.prototype, k)) return untyped String.prototype[k];
 		else if (__oldindex != null) return  __oldindex[k];
 		else if (__oldindex != null) return  __oldindex[k];
 		else return null;
 		else return null;
 	}
 	}
 
 
-
 	public function toUpperCase() : String return NativeStringTools.upper(this);
 	public function toUpperCase() : String return NativeStringTools.upper(this);
 	public function toLowerCase() : String return NativeStringTools.lower(this);
 	public function toLowerCase() : String return NativeStringTools.lower(this);
 	public function indexOf( str : String, ?startIndex : Int ) : Int {
 	public function indexOf( str : String, ?startIndex : Int ) : Int {
@@ -125,5 +124,6 @@ class String {
 	public inline static function fromCharCode( code : Int ) : String {
 	public inline static function fromCharCode( code : Int ) : String {
 		return NativeStringTools.char(code);
 		return NativeStringTools.char(code);
 	}
 	}
+
 }
 }
 
 

+ 1 - 1
std/lua/_std/Sys.hx

@@ -48,7 +48,7 @@ class Sys {
 	}
 	}
 	public static function command( cmd : String, ?args : Array<String> ) : Int  {
 	public static function command( cmd : String, ?args : Array<String> ) : Int  {
 		cmd = Boot.shellEscapeCmd(cmd, args);
 		cmd = Boot.shellEscapeCmd(cmd, args);
-		return cast Table.pack(Os.execute(cmd))[3];
+		return Os.execute(cmd).status;
 	}
 	}