rtl.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. This file is part of the Free Pascal pas2js tool.
  3. Copyright (c) 2017 Mattias Gaertner
  4. Basic RTL for pas2js programs.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. */
  11. var pas = {};
  12. var rtl = {
  13. quiet: false,
  14. debug_load_units: true,
  15. m_loading: 0,
  16. m_loading_intf: 1,
  17. m_intf_loaded: 2,
  18. m_loading_impl: 3, // loading all used unit
  19. m_initializing: 4, // running initialization
  20. m_initialized: 5,
  21. debug: function(){
  22. if (!window.console || rtl.quiet) return;
  23. console.log(arguments);
  24. },
  25. error: function(s){
  26. rtl.debug('Error: ',s);
  27. throw s;
  28. },
  29. warn: function(s){
  30. rtl.debug('Warn: ',s);
  31. },
  32. isArray: function isArray(a) {
  33. return a instanceof Array;
  34. },
  35. isNumber: function isNumber(n){
  36. return typeof(n)=="number";
  37. },
  38. isInteger: function isInteger(A){
  39. return Math.floor(A)===A;
  40. },
  41. isBoolean: function isBoolean(b){
  42. return typeof(b)=="boolean";
  43. },
  44. isString: function isString(s){
  45. return typeof(s)=="string";
  46. },
  47. isObject: function isObject(o){
  48. return typeof(o)=="object";
  49. },
  50. isFunction: function isFunction(f){
  51. return typeof(f)=="function";
  52. },
  53. isNull: function isNull(o){
  54. return (o==null && typeof(o)=='object') || o==undefined;
  55. },
  56. hasString: function(s){
  57. return rtl.isString(s) && (s.length>0);
  58. },
  59. module: function(module_name, intfuseslist, code, impluseslist){
  60. if (rtl.debug_load_units) rtl.debug('rtl.module name="'+module_name+'" intfuses='+intfuseslist+' impluses='+impluseslist);
  61. if (!rtl.hasString(module_name)) rtl.error('invalid module name "'+module_name+'"');
  62. if (!rtl.isArray(intfuseslist)) rtl.error('invalid interface useslist of "'+module_name+'"');
  63. if (!rtl.isFunction(code)) rtl.error('invalid module code of "'+module_name+'"');
  64. if ((impluseslist!=undefined) && !rtl.isArray(impluseslist)) rtl.error('invalid implementation useslist of "'+module_name+'"');
  65. if (pas[module_name])
  66. rtl.error('module "'+module_name+'" already registered');
  67. var module = pas[module_name] = {
  68. $name: module_name,
  69. $intfuseslist: intfuseslist,
  70. $impluseslist: impluseslist,
  71. $state: rtl.m_loading,
  72. $code: code
  73. };
  74. },
  75. run: function(module_name){
  76. if (module_name==undefined) module_name='program';
  77. var module = pas[module_name];
  78. rtl.loadintf(module);
  79. rtl.loadimpl(module);
  80. if (module_name=='program'){
  81. rtl.debug('running $main');
  82. pas.program.$main();
  83. }
  84. return pas.System.ExitCode;
  85. },
  86. loadintf: function(module){
  87. if (module.state>rtl.m_loading_intf) return; // already finished
  88. rtl.debug('loadintf: '+module.$name);
  89. if (module.$state==rtl.m_loading_intf)
  90. rtl.error('unit cycle detected "'+module.$name+'"');
  91. module.$state=rtl.m_loading_intf;
  92. // load interfaces of interface useslist
  93. rtl.loaduseslist(module,module.$intfuseslist,rtl.loadintf);
  94. // run interface
  95. rtl.debug('loadintf: run intf of '+module.$name);
  96. module.$code(module.$intfuseslist,module);
  97. // success
  98. module.$state=rtl.m_intf_loaded;
  99. // Note: units only used in implementations are not yet loaded (not even their interfaces)
  100. },
  101. loaduseslist: function(module,useslist,f){
  102. if (useslist==undefined) return;
  103. for (var i in useslist){
  104. var unitname=useslist[i];
  105. //rtl.debug('loaduseslist of "'+module.name+'" uses="'+unitname+'"');
  106. if (pas[unitname]==undefined)
  107. rtl.error('module "'+module.$name+'" misses "'+unitname+'"');
  108. f(pas[unitname]);
  109. }
  110. },
  111. loadimpl: function(module){
  112. if (module.$state>=rtl.m_loading_impl) return; // already processing
  113. if (module.$state<rtl.m_loading_intf) rtl.loadintf(module);
  114. rtl.debug('loadimpl: '+module.$name+' load uses');
  115. module.$state=rtl.m_loading_impl;
  116. // load implementation of interfaces useslist
  117. rtl.loaduseslist(module,module.$intfuseslist,rtl.loadimpl);
  118. // load implementation of implementation useslist
  119. rtl.loaduseslist(module,module.$impluseslist,rtl.loadimpl);
  120. // Note: At this point all interfaces used by this unit are loaded. If
  121. // there are implementation uses cycles some used units might not yet be
  122. // initialized. This is by design.
  123. // run initialization
  124. rtl.debug('loadimpl: '+module.$name+' run init');
  125. module.$state=rtl.m_initializing;
  126. if (rtl.isFunction(module.$init))
  127. module.$init();
  128. // unit initialized
  129. module.$state=rtl.m_initialized;
  130. },
  131. createCallback: function(scope, fn){
  132. var wrapper = function(){
  133. return fn.apply(scope,arguments);
  134. };
  135. wrapper.fn = fn;
  136. return wrapper;
  137. },
  138. createClass: function(owner,name,ancestor,initfn){
  139. var c = null;
  140. if (ancestor != null){
  141. c = Object.create(ancestor);
  142. c.$ancestor = ancestor; // c.$ancestor == Object.getPrototypeOf(c)
  143. } else {
  144. c = {};
  145. c.$create = function(fnname,args){
  146. var o = Object.create(this);
  147. o.$class = this; // Note: o.$class == Object.getPrototypeOf(o)
  148. if (args == undefined) args = [];
  149. o[fnname].apply(o,args);
  150. o.$init();
  151. o.AfterConstruction();
  152. return o;
  153. };
  154. c.$destroy = function(fnname){
  155. this.BeforeDestruction();
  156. this[fnname].apply(obj,[]);
  157. };
  158. };
  159. c.$classname = name;
  160. c.$name = owner.$name+'.'+name;
  161. c.$unitname = rtl.isString(owner.$unitname) ? owner.$unitname : owner.$name;
  162. owner[name] = c;
  163. initfn.call(c);
  164. },
  165. as: function(instance,typ){
  166. if(typ.isPrototypeOf(instance)) return instance;
  167. throw pas.System.EInvalidCast.$create("create");
  168. },
  169. setArrayLength: function(arr,newlength,defaultvalue){
  170. if (newlength == 0) return null;
  171. if (arr == null) arr = [];
  172. var oldlen = arr.length;
  173. if (oldlen==newlength) return;
  174. arr.length = newlength;
  175. if (rtl.isArray(defaultvalue)){
  176. for (var i=oldlen; i<newlength; i++) arr[i]=[]; // new array
  177. } else {
  178. for (var i=oldlen; i<newlength; i++) arr[i]=defaultvalue;
  179. }
  180. return arr;
  181. },
  182. setStringLength: function(s,newlength){
  183. s.length = newlength;
  184. },
  185. length: function(a){
  186. return (a!=null) ? a.length : 0;
  187. },
  188. setCharAt: function(s,index,c){
  189. return s.substr(0,index)+c+s.substr(index+1);
  190. },
  191. createSet: function(){
  192. var s = {};
  193. for (var i=0; i<arguments.length; i++){
  194. if (arguments[i]!=null){
  195. s[arguments[i]]=true;
  196. } else {
  197. var first=arguments[i+=1];
  198. var last=arguments[i+=1];
  199. for(var j=first; j<=last; j++) s[j]=true;
  200. }
  201. }
  202. return s;
  203. },
  204. cloneSet: function(s){
  205. var r = {};
  206. for (var key in s) if (s.hasOwnProperty(key)) r[key]=true;
  207. return r;
  208. },
  209. diffSet: function(s,t){
  210. var r = {};
  211. for (var key in s) if (s.hasOwnProperty(key) && !t[key]) r[key]=true;
  212. return r;
  213. },
  214. unionSet: function(s,t){
  215. var r = {};
  216. for (var key in s) if (s.hasOwnProperty(key)) r[key]=true;
  217. for (var key in t) if (t.hasOwnProperty(key)) r[key]=true;
  218. return r;
  219. },
  220. intersectSet: function(s,t){
  221. var r = {};
  222. for (var key in s) if (s.hasOwnProperty(key) && t[key]) r[key]=true;
  223. return r;
  224. },
  225. symDiffSet: function(s,t){
  226. var r = {};
  227. for (var key in s) if (s.hasOwnProperty(key) && !t[key]) r[key]=true;
  228. for (var key in t) if (t.hasOwnProperty(key) && !s[key]) r[key]=true;
  229. return r;
  230. },
  231. eqSet: function(s,t){
  232. for (var key in s) if (s.hasOwnProperty(key) && !t[key]) return false;
  233. for (var key in t) if (t.hasOwnProperty(key) && !s[key]) return false;
  234. return true;
  235. },
  236. neSet: function(s,t){
  237. return !rtl.eqSet(s,t);
  238. },
  239. leSet: function(s,t){
  240. for (var key in s) if (s.hasOwnProperty(key) && !t[key]) return false;
  241. return true;
  242. },
  243. geSet: function(s,t){
  244. for (var key in t) if (t.hasOwnProperty(key) && !s[key]) return false;
  245. return true;
  246. },
  247. }