Boot.hx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright (C)2005-2012 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package lua;
  23. import lua.Table;
  24. import haxe.Constraints.Function;
  25. using lua.PairTools;
  26. class Boot {
  27. // Used temporarily for bind()
  28. static var _;
  29. static var _fid = 0;
  30. static function __unhtml(s : String)
  31. return s.split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;");
  32. public static function patternQuote(str:String)
  33. return lua.StringTools.gsub(str, "[%(%)%.%%%+%-%*%?%[%]%^%$]", function(c:String){ return "%" + c; });
  34. public inline static function tableToArray<T>(t:Table<Int,T>, ?length:Int) : Array<T> {
  35. if (length == null) length = Table.maxn(t);
  36. return cast defArray(t,length);
  37. }
  38. public static function luaIteratorToArray<T>(itr:Void->T) : Array<T> {
  39. var i: T = null;
  40. var ret : Array<T> = [];
  41. while({i = itr(); i != null;}){
  42. ret.push(i);
  43. }
  44. return ret;
  45. }
  46. @:keep
  47. public static function bind(o:Dynamic, m: Function) : Function{
  48. if (m == null) return null;
  49. // if (m.__id.__ == nil) m.__id__ = _fid + 1;
  50. var f: Function = null;
  51. if ( o.hx__closures__ == null ) o.hx__closures__ = {};
  52. else untyped f = o.hx__closures__[m];
  53. if (f == null){
  54. f = untyped __lua__("function(...) return m(o, ...) end");
  55. untyped o.hx__closures__[m] = f;
  56. }
  57. return f;
  58. }
  59. static inline public function isClass(o:Dynamic) : Bool {
  60. if (Lua.type(o) != "table") return false;
  61. else return untyped __define_feature__("lua.Boot.isClass", o.__name__);
  62. }
  63. static inline public function isEnum(e:Dynamic) : Bool {
  64. if (Lua.type(e) != "table") return false;
  65. else return untyped __define_feature__("lua.Boot.isEnum", e.__ename__);
  66. }
  67. static inline public function getClass(o:Dynamic) : Dynamic {
  68. if (Std.is(o, Array)) return Array;
  69. else {
  70. var cl = untyped __define_feature__("lua.Boot.getClass", o.__class__);
  71. if (cl != null) return cl;
  72. else return null;
  73. }
  74. }
  75. @:ifFeature("typed_catch")
  76. private static function __instanceof(o : Dynamic,cl : Dynamic) {
  77. if( cl == null ) return false;
  78. switch( cl ) {
  79. case Int:
  80. // TODO: matching js behavior here, but js behavior clamps. Is that correct?
  81. return (untyped __type__(o) == "number" && clamp(o) == o);
  82. case Float:
  83. return untyped __type__(o) == "number";
  84. case Bool:
  85. return untyped __type__(o) == "boolean";
  86. case String:
  87. return untyped __type__(o) == "string";
  88. case Array:
  89. return untyped __type__(o) == "table"
  90. && lua.Lua.getmetatable(o) != null
  91. && lua.Lua.getmetatable(o).__index == Array.prototype;
  92. case Table:
  93. return untyped __type__(o) == "table";
  94. case Dynamic:
  95. return true;
  96. default: {
  97. if ( untyped o.__enum__ != null ){
  98. return o.__enum__ == cl;
  99. } else if ( untyped __type__(o) == "table"
  100. && untyped __type__(cl) == "table"){
  101. while (Lua.getmetatable(o) != null && Lua.getmetatable(o).__index != null){
  102. if (Lua.getmetatable(o).__index == cl.prototype) return true;
  103. o = Lua.getmetatable(o).__index;
  104. }
  105. return false;
  106. }
  107. return false;
  108. }
  109. }
  110. }
  111. @:ifFeature("typed_cast")
  112. private static function __cast(o : Dynamic, t : Dynamic) {
  113. if (__instanceof(o, t)) return o;
  114. else throw "Cannot cast " +Std.string(o) + " to " +Std.string(t);
  115. }
  116. @:keep
  117. public static function arrayNewIndex(tab:Dynamic, key:Dynamic, value:Dynamic){
  118. untyped rawset(tab, key, value);
  119. if (Std.is(key,Int) && key+1 > tab.length){
  120. tab.length = key + 1;
  121. }
  122. }
  123. @:keep
  124. public static function defArray(tabobj: Dynamic, length : Int) : Array<Dynamic> untyped {
  125. tabobj.length = length;
  126. setmetatable(tabobj, {
  127. __index : __lua__("Array.prototype"),
  128. __newindex : lua.Boot.arrayNewIndex
  129. });
  130. return tabobj;
  131. }
  132. public static function urlDecode(str:String){
  133. str = lua.StringTools.gsub (str, "+", " ");
  134. str = lua.StringTools.gsub (str, "%%(%x%x)",
  135. function(h) {return lua.StringTools.char(lua.Lua.tonumber(h,16));});
  136. str = lua.StringTools.gsub (str, "\r\n", "\n");
  137. return str;
  138. }
  139. public static function urlEncode(str:String){
  140. str = lua.StringTools.gsub(str, "\n", "\r\n");
  141. str = lua.StringTools.gsub(str, "([^%w %-%_%.%~])", function (c) {
  142. return lua.StringTools.format("%%%02X", lua.StringTools.byte(c) + '');
  143. });
  144. str = lua.StringTools.gsub(str, " ", "+");
  145. return str;
  146. }
  147. static function printEnum(e:Table<String,Dynamic>){
  148. var params = new Array<Dynamic>();
  149. var first = '';
  150. lua.PairTools.ipairsEach(e, function(i,x){
  151. if (i == 1) first = e[0];
  152. else params.push(x);
  153. });
  154. return '$first(${params.join(",")})';
  155. }
  156. static function printClass(c:Table<String,Dynamic>, s : Int) : String {
  157. return '{${printClassRec(c,'',s)}}';
  158. }
  159. static function printClassRec(c:Table<String,Dynamic>, result='', s : Int) : String {
  160. c.pairsEach(function(k,v){
  161. if (result != "")
  162. result += ", ";
  163. result += '$k: ${__string_rec(v, s + 1)}';
  164. });
  165. return result;
  166. }
  167. @:ifFeature("has_enum")
  168. static function __string_rec(o : Dynamic, s = 0) {
  169. return switch(untyped __type__(o)){
  170. case "nil": "null";
  171. case "number" : {
  172. if (o == std.Math.POSITIVE_INFINITY) "Infinity";
  173. else if (o == std.Math.NEGATIVE_INFINITY) "-Infinity";
  174. else if (o != o) "NaN";
  175. else untyped tostring(o);
  176. }
  177. case "boolean" : untyped tostring(o);
  178. case "string" : o;
  179. case "userdata": "<userdata>";
  180. case "function": "<function>";
  181. case "thread" : "<thread>";
  182. case "table": {
  183. if (Reflect.hasField(o,"__enum__")) printEnum(o);
  184. else if (o.toString != null && !__instanceof(o,Array)) o.toString();
  185. else if (__instanceof(o, Array)) {
  186. if (s > 5) "[...]"
  187. else '[${[for (i in cast(o,Array<Dynamic>)) __string_rec(i,s+1)].join(",")}]';
  188. } else if (s > 5){
  189. "{...}";
  190. }
  191. else if (Reflect.hasField(o,"__tostring")) Lua.tostring(o);
  192. else if (Reflect.hasField(o,"__class__")) printClass(o,s+1);
  193. else if (Lua.next(o) == null) "{}";
  194. else {
  195. var fields = Reflect.fields(o);
  196. var buffer = new StringBuf();
  197. for (f in fields){
  198. buffer.add('${Std.string(f)} : ${untyped Std.string(o[f])}');
  199. }
  200. buffer.toString();
  201. }
  202. };
  203. default : {
  204. throw "Unknown Lua type";
  205. null;
  206. }
  207. }
  208. }
  209. public static function dateStr( date : std.Date ) : String {
  210. var m = date.getMonth() + 1;
  211. var d = date.getDate();
  212. var h = date.getHours();
  213. var mi = date.getMinutes();
  214. var s = date.getSeconds();
  215. return date.getFullYear()
  216. +"-"+(if( m < 10 ) "0"+m else ""+m)
  217. +"-"+(if( d < 10 ) "0"+d else ""+d)
  218. +" "+(if( h < 10 ) "0"+h else ""+h)
  219. +":"+(if( mi < 10 ) "0"+mi else ""+mi)
  220. +":"+(if( s < 10 ) "0"+s else ""+s);
  221. }
  222. public static function clamp(x:Int){
  223. return (x & 2147483647) - (x & cast 2147483648);
  224. }
  225. public static function strDate( s : String ) : std.Date {
  226. switch( s.length ) {
  227. case 8: // hh:mm:ss
  228. var k = s.split(":");
  229. var t = lua.Os.time({
  230. year : 0,
  231. month : 1,
  232. day : 1,
  233. hour : Std.parseInt(k[0]),
  234. min : Std.parseInt(k[1]),
  235. sec : Std.parseInt(k[2])
  236. });
  237. return std.Date.fromTime(t);
  238. case 10: // YYYY-MM-DD
  239. var k = s.split("-");
  240. return new std.Date(Std.parseInt(k[0]), Std.parseInt(k[1]) - 1, Std.parseInt(k[2]),0,0,0);
  241. case 19: // YYYY-MM-DD hh:mm:ss
  242. var k = s.split(" ");
  243. var y = k[0].split("-");
  244. var t = k[1].split(":");
  245. return new std.Date(cast y[0],Std.parseInt(y[1]) - 1, Std.parseInt(y[2]),Std.parseInt(t[0]),Std.parseInt(t[1]),Std.parseInt(t[2]));
  246. default:
  247. throw "Invalid date format : " + s;
  248. }
  249. }
  250. }