rtl.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. var pas = {};
  2. var rtl = {
  3. quiet: false,
  4. debug_load_units: false,
  5. debug_rtti: false,
  6. debug: function(){
  7. if (rtl.quiet || !console || !console.log) return;
  8. console.log(arguments);
  9. },
  10. error: function(s){
  11. rtl.debug('Error: ',s);
  12. throw s;
  13. },
  14. warn: function(s){
  15. rtl.debug('Warn: ',s);
  16. },
  17. hasString: function(s){
  18. return rtl.isString(s) && (s.length>0);
  19. },
  20. isArray: function(a) {
  21. return Array.isArray(a);
  22. },
  23. isFunction: function(f){
  24. return typeof(f)==="function";
  25. },
  26. isModule: function(m){
  27. return rtl.isObject(m) && rtl.hasString(m.$name) && (pas[m.$name]===m);
  28. },
  29. isImplementation: function(m){
  30. return rtl.isObject(m) && rtl.isModule(m.$module) && (m.$module.$impl===m);
  31. },
  32. isNumber: function(n){
  33. return typeof(n)==="number";
  34. },
  35. isObject: function(o){
  36. var s=typeof(o);
  37. return (typeof(o)==="object") && (o!=null);
  38. },
  39. isString: function(s){
  40. return typeof(s)==="string";
  41. },
  42. getNumber: function(n){
  43. return typeof(n)==="number"?n:NaN;
  44. },
  45. getChar: function(c){
  46. return ((typeof(c)==="string") && (c.length===1)) ? c : "";
  47. },
  48. getObject: function(o){
  49. return ((typeof(o)==="object") || (typeof(o)==='function')) ? o : null;
  50. },
  51. m_loading: 0,
  52. m_loading_intf: 1,
  53. m_intf_loaded: 2,
  54. m_loading_impl: 3, // loading all used unit
  55. m_initializing: 4, // running initialization
  56. m_initialized: 5,
  57. module: function(module_name, intfuseslist, intfcode, impluseslist, implcode){
  58. if (rtl.debug_load_units) rtl.debug('rtl.module name="'+module_name+'" intfuses='+intfuseslist+' impluses='+impluseslist+' hasimplcode='+rtl.isFunction(implcode));
  59. if (!rtl.hasString(module_name)) rtl.error('invalid module name "'+module_name+'"');
  60. if (!rtl.isArray(intfuseslist)) rtl.error('invalid interface useslist of "'+module_name+'"');
  61. if (!rtl.isFunction(intfcode)) rtl.error('invalid interface code of "'+module_name+'"');
  62. if (!(impluseslist==undefined) && !rtl.isArray(impluseslist)) rtl.error('invalid implementation useslist of "'+module_name+'"');
  63. if (!(implcode==undefined) && !rtl.isFunction(implcode)) rtl.error('invalid implementation code of "'+module_name+'"');
  64. if (pas[module_name])
  65. rtl.error('module "'+module_name+'" is already registered');
  66. var module = pas[module_name] = {
  67. $name: module_name,
  68. $intfuseslist: intfuseslist,
  69. $impluseslist: impluseslist,
  70. $state: rtl.m_loading,
  71. $intfcode: intfcode,
  72. $implcode: implcode,
  73. $impl: null,
  74. $rtti: Object.create(rtl.tSectionRTTI),
  75. };
  76. module.$rtti.$module = module;
  77. if (implcode) module.$impl = {
  78. $module: module,
  79. $rtti: module.$rtti,
  80. };
  81. },
  82. exitcode: 0,
  83. run: function(module_name){
  84. function doRun(){
  85. if (!rtl.hasString(module_name)) module_name='program';
  86. if (rtl.debug_load_units) rtl.debug('rtl.run module="'+module_name+'"');
  87. rtl.initRTTI();
  88. var module = pas[module_name];
  89. if (!module) rtl.error('rtl.run module "'+module_name+'" missing');
  90. rtl.loadintf(module);
  91. rtl.loadimpl(module);
  92. if (module_name=='program'){
  93. if (rtl.debug_load_units) rtl.debug('running $main');
  94. var r = pas.program.$main();
  95. if (rtl.isNumber(r)) rtl.exitcode = r;
  96. }
  97. }
  98. if (rtl.showUncaughtExceptions) {
  99. try{
  100. doRun();
  101. } catch(re) {
  102. var errMsg = re.hasOwnProperty('$class') ? re.$class.$classname : '';
  103. errMsg += ((errMsg) ? ': ' : '') + (re.hasOwnProperty('fMessage') ? re.fMessage : re);
  104. alert('Uncaught Exception : '+errMsg);
  105. rtl.exitCode = 216;
  106. }
  107. } else {
  108. doRun();
  109. }
  110. return rtl.exitcode;
  111. },
  112. loadintf: function(module){
  113. if (module.$state>rtl.m_loading_intf) return; // already finished
  114. if (rtl.debug_load_units) rtl.debug('loadintf: "'+module.$name+'"');
  115. if (module.$state===rtl.m_loading_intf)
  116. rtl.error('unit cycle detected "'+module.$name+'"');
  117. module.$state=rtl.m_loading_intf;
  118. // load interfaces of interface useslist
  119. rtl.loaduseslist(module,module.$intfuseslist,rtl.loadintf);
  120. // run interface
  121. if (rtl.debug_load_units) rtl.debug('loadintf: run intf of "'+module.$name+'"');
  122. module.$intfcode(module.$intfuseslist);
  123. // success
  124. module.$state=rtl.m_intf_loaded;
  125. // Note: units only used in implementations are not yet loaded (not even their interfaces)
  126. },
  127. loaduseslist: function(module,useslist,f){
  128. if (useslist==undefined) return;
  129. for (var i in useslist){
  130. var unitname=useslist[i];
  131. if (rtl.debug_load_units) rtl.debug('loaduseslist of "'+module.$name+'" uses="'+unitname+'"');
  132. if (pas[unitname]==undefined)
  133. rtl.error('module "'+module.$name+'" misses "'+unitname+'"');
  134. f(pas[unitname]);
  135. }
  136. },
  137. loadimpl: function(module){
  138. if (module.$state>=rtl.m_loading_impl) return; // already processing
  139. if (module.$state<rtl.m_intf_loaded) rtl.error('loadimpl: interface not loaded of "'+module.$name+'"');
  140. if (rtl.debug_load_units) rtl.debug('loadimpl: load uses of "'+module.$name+'"');
  141. module.$state=rtl.m_loading_impl;
  142. // load interfaces of implementation useslist
  143. rtl.loaduseslist(module,module.$impluseslist,rtl.loadintf);
  144. // load implementation of interfaces useslist
  145. rtl.loaduseslist(module,module.$intfuseslist,rtl.loadimpl);
  146. // load implementation of implementation useslist
  147. rtl.loaduseslist(module,module.$impluseslist,rtl.loadimpl);
  148. // Note: At this point all interfaces used by this unit are loaded. If
  149. // there are implementation uses cycles some used units might not yet be
  150. // initialized. This is by design.
  151. // run implementation
  152. if (rtl.debug_load_units) rtl.debug('loadimpl: run impl of "'+module.$name+'"');
  153. if (rtl.isFunction(module.$implcode)) module.$implcode(module.$impluseslist);
  154. // run initialization
  155. if (rtl.debug_load_units) rtl.debug('loadimpl: run init of "'+module.$name+'"');
  156. module.$state=rtl.m_initializing;
  157. if (rtl.isFunction(module.$init)) module.$init();
  158. // unit initialized
  159. module.$state=rtl.m_initialized;
  160. },
  161. createCallback: function(scope, fn){
  162. var cb;
  163. if (typeof(fn)==='string'){
  164. cb = function(){
  165. return scope[fn].apply(scope,arguments);
  166. };
  167. } else {
  168. cb = function(){
  169. return fn.apply(scope,arguments);
  170. };
  171. };
  172. cb.scope = scope;
  173. cb.fn = fn;
  174. return cb;
  175. },
  176. cloneCallback: function(cb){
  177. return rtl.createCallback(cb.scope,cb.fn);
  178. },
  179. eqCallback: function(a,b){
  180. // can be a function or a function wrapper
  181. if (a==b){
  182. return true;
  183. } else {
  184. return (a!=null) && (b!=null) && (a.fn) && (a.scope===b.scope) && (a.fn==b.fn);
  185. }
  186. },
  187. initClass: function(c,parent,name,initfn){
  188. parent[name] = c;
  189. c.$classname = name;
  190. if ((parent.$module) && (parent.$module.$impl===parent)) parent=parent.$module;
  191. c.$parent = parent;
  192. c.$fullname = parent.$name+'.'+name;
  193. if (rtl.isModule(parent)){
  194. c.$module = parent;
  195. c.$name = name;
  196. } else {
  197. c.$module = parent.$module;
  198. c.$name = parent.name+'.'+name;
  199. };
  200. // rtti
  201. if (rtl.debug_rtti) rtl.debug('initClass '+c.$fullname);
  202. var t = c.$module.$rtti.$Class(c.$name,{ "class": c, module: parent });
  203. c.$rtti = t;
  204. if (rtl.isObject(c.$ancestor)) t.ancestor = c.$ancestor.$rtti;
  205. if (!t.ancestor) t.ancestor = null;
  206. // init members
  207. initfn.call(c);
  208. },
  209. createClass: function(parent,name,ancestor,initfn){
  210. // create a normal class,
  211. // ancestor must be null or a normal class,
  212. // the root ancestor can be an external class
  213. var c = null;
  214. if (ancestor != null){
  215. c = Object.create(ancestor);
  216. c.$ancestor = ancestor;
  217. // Note:
  218. // if root is an "object" then c.$ancestor === Object.getPrototypeOf(c)
  219. // if root is a "function" then c.$ancestor === c.__proto__, Object.getPrototypeOf(c) returns the root
  220. } else {
  221. c = {};
  222. c.$create = function(fnname,args){
  223. if (args == undefined) args = [];
  224. var o = Object.create(this);
  225. o.$class = this; // Note: o.$class === Object.getPrototypeOf(o)
  226. o.$init();
  227. try{
  228. o[fnname].apply(o,args);
  229. o.AfterConstruction();
  230. } catch($e){
  231. o.$destroy;
  232. throw $e;
  233. }
  234. return o;
  235. };
  236. c.$destroy = function(fnname){
  237. this.BeforeDestruction();
  238. this[fnname]();
  239. this.$final;
  240. };
  241. };
  242. rtl.initClass(c,parent,name,initfn);
  243. },
  244. createClassExt: function(parent,name,ancestor,newinstancefnname,initfn){
  245. // Create a class using an external ancestor.
  246. // If newinstancefnname is given, use that function to create the new object.
  247. // If exist call BeforeDestruction and AfterConstruction.
  248. var c = null;
  249. c = Object.create(ancestor);
  250. c.$create = function(fnname,args){
  251. if (args == undefined) args = [];
  252. var o = null;
  253. if (newinstancefnname.length>0){
  254. o = this[newinstancefnname](fnname,args);
  255. } else {
  256. o = Object.create(this);
  257. }
  258. o.$class = this; // Note: o.$class === Object.getPrototypeOf(o)
  259. o.$init();
  260. try{
  261. o[fnname].apply(o,args);
  262. if (o.AfterConstruction) o.AfterConstruction();
  263. } catch($e){
  264. o.$destroy;
  265. throw $e;
  266. }
  267. return o;
  268. };
  269. c.$destroy = function(fnname){
  270. if (this.BeforeDestruction) this.BeforeDestruction();
  271. this[fnname]();
  272. this.$final;
  273. };
  274. rtl.initClass(c,parent,name,initfn);
  275. },
  276. tObjectDestroy: "Destroy",
  277. free: function(obj,name){
  278. if (obj[name]==null) return;
  279. obj[name].$destroy(rtl.tObjectDestroy);
  280. obj[name]=null;
  281. },
  282. freeLoc: function(obj){
  283. if (obj==null) return;
  284. obj.$destroy(rtl.tObjectDestroy);
  285. return null;
  286. },
  287. is: function(descendant,type){
  288. return type.isPrototypeOf(descendant) || (descendant===type);
  289. },
  290. isExt: function(instance,type){
  291. // Notes:
  292. // isPrototypeOf and instanceof return false on equal
  293. // isPrototypeOf does not work for Date.isPrototypeOf(new Date())
  294. // so if isPrototypeOf is false test with instanceof
  295. // instanceof needs a function on right side
  296. if (instance == null) return false; // Note: ==null checks for undefined
  297. if ((typeof(type) !== 'object') && (typeof(type) !== 'function')) return false;
  298. if (instance === type) return true;
  299. if (type.isPrototypeOf && type.isPrototypeOf(instance)) return true;
  300. if ((typeof type == 'function') && (instance instanceof type)) return true;
  301. return false;
  302. },
  303. EInvalidCast: null,
  304. as: function(instance,type){
  305. if(rtl.is(instance,type)) return instance;
  306. throw rtl.EInvalidCast.$create("create");
  307. },
  308. asExt: function(instance,type){
  309. if(rtl.isExt(instance,type)) return instance;
  310. throw rtl.EInvalidCast.$create("create");
  311. },
  312. length: function(arr){
  313. return (arr == null) ? 0 : arr.length;
  314. },
  315. arraySetLength: function(arr,defaultvalue,newlength){
  316. // multi dim: (arr,defaultvalue,dim1,dim2,...)
  317. if (arr == null) arr = [];
  318. var p = arguments;
  319. function setLength(a,argNo){
  320. var oldlen = a.length;
  321. var newlen = p[argNo];
  322. if (oldlen!==newlength){
  323. a.length = newlength;
  324. if (argNo === p.length-1){
  325. if (rtl.isArray(defaultvalue)){
  326. for (var i=oldlen; i<newlen; i++) a[i]=[]; // nested array
  327. } else if (rtl.isFunction(defaultvalue)){
  328. for (var i=oldlen; i<newlen; i++) a[i]=new defaultvalue(); // e.g. record
  329. } else if (rtl.isObject(defaultvalue)) {
  330. for (var i=oldlen; i<newlen; i++) a[i]={}; // e.g. set
  331. } else {
  332. for (var i=oldlen; i<newlen; i++) a[i]=defaultvalue;
  333. }
  334. } else {
  335. for (var i=oldlen; i<newlen; i++) a[i]=[]; // nested array
  336. }
  337. }
  338. if (argNo < p.length-1){
  339. // multi argNo
  340. for (var i=0; i<newlen; i++) a[i]=setLength(a[i],argNo+1);
  341. }
  342. return a;
  343. }
  344. return setLength(arr,2);
  345. },
  346. arrayClone: function(type,src,srcpos,end,dst,dstpos){
  347. // type: 0 for references, "refset" for calling refSet(), a function for new type()
  348. // src must not be null
  349. // This function does not range check.
  350. if (rtl.isFunction(type)){
  351. for (; srcpos<end; srcpos++) dst[dstpos++] = new type(src[srcpos]); // clone record
  352. } else if(isString(type) && (type === 'refSet')) {
  353. for (; srcpos<end; srcpos++) dst[dstpos++] = refSet(src[srcpos]); // ref set
  354. } else {
  355. for (; srcpos<end; srcpos++) dst[dstpos++] = src[srcpos]; // reference
  356. };
  357. },
  358. arrayConcat: function(type){
  359. // type: see rtl.arrayClone
  360. var a = [];
  361. var l = 0;
  362. for (var i=1; i<arguments.length; i++) l+=arguments[i].length;
  363. a.length = l;
  364. l=0;
  365. for (var i=1; i<arguments.length; i++){
  366. var src = arguments[i];
  367. if (src == null) continue;
  368. rtl.arrayClone(type,src,0,src.length,a,l);
  369. l+=src.length;
  370. };
  371. return a;
  372. },
  373. arrayCopy: function(type, srcarray, index, count){
  374. // type: see rtl.arrayClone
  375. // if count is missing, use srcarray.length
  376. if (srcarray == null) return [];
  377. if (index < 0) index = 0;
  378. if (count === undefined) count=srcarray.length;
  379. var end = index+count;
  380. if (end>scrarray.length) end = scrarray.length;
  381. if (index>=end) return [];
  382. if (type===0){
  383. return srcarray.slice(index,end);
  384. } else {
  385. var a = [];
  386. a.length = end-index;
  387. rtl.arrayClone(type,srcarray,index,end,a,0);
  388. return a;
  389. }
  390. },
  391. setCharAt: function(s,index,c){
  392. return s.substr(0,index)+c+s.substr(index+1);
  393. },
  394. getResStr: function(mod,name){
  395. var rs = mod.$resourcestrings[name];
  396. return rs.current?rs.current:rs.org;
  397. },
  398. createSet: function(){
  399. var s = {};
  400. for (var i=0; i<arguments.length; i++){
  401. if (arguments[i]!=null){
  402. s[arguments[i]]=true;
  403. } else {
  404. var first=arguments[i+=1];
  405. var last=arguments[i+=1];
  406. for(var j=first; j<=last; j++) s[j]=true;
  407. }
  408. }
  409. return s;
  410. },
  411. cloneSet: function(s){
  412. var r = {};
  413. for (var key in s) if (s.hasOwnProperty(key)) r[key]=true;
  414. return r;
  415. },
  416. refSet: function(s){
  417. s.$shared = true;
  418. return s;
  419. },
  420. includeSet: function(s,enumvalue){
  421. if (s.$shared) s = cloneSet(s);
  422. s[enumvalue] = true;
  423. return s;
  424. },
  425. excludeSet: function(s,enumvalue){
  426. if (s.$shared) s = cloneSet(s);
  427. delete s[enumvalue];
  428. return s;
  429. },
  430. diffSet: function(s,t){
  431. var r = {};
  432. for (var key in s) if (s.hasOwnProperty(key) && !t[key]) r[key]=true;
  433. delete r.$shared;
  434. return r;
  435. },
  436. unionSet: function(s,t){
  437. var r = {};
  438. for (var key in s) if (s.hasOwnProperty(key)) r[key]=true;
  439. for (var key in t) if (t.hasOwnProperty(key)) r[key]=true;
  440. delete r.$shared;
  441. return r;
  442. },
  443. intersectSet: function(s,t){
  444. var r = {};
  445. for (var key in s) if (s.hasOwnProperty(key) && t[key]) r[key]=true;
  446. delete r.$shared;
  447. return r;
  448. },
  449. symDiffSet: function(s,t){
  450. var r = {};
  451. for (var key in s) if (s.hasOwnProperty(key) && !t[key]) r[key]=true;
  452. for (var key in t) if (t.hasOwnProperty(key) && !s[key]) r[key]=true;
  453. delete r.$shared;
  454. return r;
  455. },
  456. eqSet: function(s,t){
  457. for (var key in s) if (s.hasOwnProperty(key) && !t[key] && (key!='$shared')) return false;
  458. for (var key in t) if (t.hasOwnProperty(key) && !s[key] && (key!='$shared')) return false;
  459. return true;
  460. },
  461. neSet: function(s,t){
  462. return !rtl.eqSet(s,t);
  463. },
  464. leSet: function(s,t){
  465. for (var key in s) if (s.hasOwnProperty(key) && !t[key] && (key!='$shared')) return false;
  466. return true;
  467. },
  468. geSet: function(s,t){
  469. for (var key in t) if (t.hasOwnProperty(key) && !s[key] && (key!='$shared')) return false;
  470. return true;
  471. },
  472. strSetLength: function(s,newlen){
  473. var oldlen = s.length;
  474. if (oldlen > newlen){
  475. return s.substring(0,newlen);
  476. } else if (s.repeat){
  477. // Note: repeat needs ECMAScript6!
  478. return s+' '.repeat(newlen-oldlen);
  479. } else {
  480. while (oldlen<newlen){
  481. s+=' ';
  482. oldlen++;
  483. };
  484. return s;
  485. }
  486. },
  487. spaceLeft: function(s,width){
  488. var l=s.length;
  489. if (l>=width) return s;
  490. if (s.repeat){
  491. // Note: repeat needs ECMAScript6!
  492. return ' '.repeat(width-l) + s;
  493. } else {
  494. while (l<width){
  495. s=' '+s;
  496. l++;
  497. };
  498. };
  499. },
  500. floatToStr : function(d,w,p){
  501. // input 1-3 arguments: double, width, precision
  502. if (arguments.length>2){
  503. return rtl.spaceLeft(d.toFixed(p),w);
  504. } else {
  505. // exponent width
  506. var pad = "";
  507. var ad = Math.abs(d);
  508. if (ad<1.0e+10) {
  509. pad='00';
  510. } else if (ad<1.0e+100) {
  511. pad='0';
  512. }
  513. if (arguments.length<2) {
  514. w=9;
  515. } else if (w<9) {
  516. w=9;
  517. }
  518. var p = w-8;
  519. var s=(d>0 ? " " : "" ) + d.toExponential(p);
  520. s=s.replace(/e(.)/,'E$1'+pad);
  521. return rtl.spaceLeft(s,w);
  522. }
  523. },
  524. initRTTI: function(){
  525. if (rtl.debug_rtti) rtl.debug('initRTTI');
  526. // base types
  527. rtl.tTypeInfo = { name: "tTypeInfo" };
  528. function newBaseTI(name,kind,ancestor){
  529. if (!ancestor) ancestor = rtl.tTypeInfo;
  530. if (rtl.debug_rtti) rtl.debug('initRTTI.newBaseTI "'+name+'" '+kind+' ("'+ancestor.name+'")');
  531. var t = Object.create(ancestor);
  532. t.name = name;
  533. t.kind = kind;
  534. rtl[name] = t;
  535. return t;
  536. };
  537. function newBaseInt(name,minvalue,maxvalue,ordtype){
  538. var t = newBaseTI(name,1 /* tkInteger */,rtl.tTypeInfoInteger);
  539. t.minvalue = minvalue;
  540. t.maxvalue = maxvalue;
  541. t.ordtype = ordtype;
  542. return t;
  543. };
  544. newBaseTI("tTypeInfoInteger",1 /* tkInteger */);
  545. newBaseInt("shortint",-0x80,0x7f,0);
  546. newBaseInt("byte",0,0xff,1);
  547. newBaseInt("smallint",-0x8000,0x7fff,2);
  548. newBaseInt("word",0,0xffff,3);
  549. newBaseInt("longint",-0x80000000,0x7fffffff,4);
  550. newBaseInt("longword",0,0xffffffff,5);
  551. newBaseInt("nativeint",-0x10000000000000,0xfffffffffffff,6);
  552. newBaseInt("nativeuint",0,0xfffffffffffff,7);
  553. newBaseTI("char",2 /* tkChar */);
  554. newBaseTI("string",3 /* tkString */);
  555. newBaseTI("tTypeInfoEnum",4 /* tkEnumeration */,rtl.tTypeInfoInteger);
  556. newBaseTI("tTypeInfoSet",5 /* tkSet */);
  557. newBaseTI("double",6 /* tkDouble */);
  558. newBaseTI("boolean",7 /* tkBool */);
  559. newBaseTI("tTypeInfoProcVar",8 /* tkProcVar */);
  560. newBaseTI("tTypeInfoMethodVar",9 /* tkMethod */,rtl.tTypeInfoProcVar);
  561. newBaseTI("tTypeInfoArray",10 /* tkArray */);
  562. newBaseTI("tTypeInfoDynArray",11 /* tkDynArray */);
  563. newBaseTI("tTypeInfoPointer",15 /* tkPointer */);
  564. var t = newBaseTI("pointer",15 /* tkPointer */,rtl.tTypeInfoPointer);
  565. t.reftype = null;
  566. newBaseTI("jsvalue",16 /* tkJSValue */);
  567. newBaseTI("tTypeInfoRefToProcVar",17 /* tkRefToProcVar */,rtl.tTypeInfoProcVar);
  568. // member kinds
  569. rtl.tTypeMember = {};
  570. function newMember(name,kind){
  571. var m = Object.create(rtl.tTypeMember);
  572. m.name = name;
  573. m.kind = kind;
  574. rtl[name] = m;
  575. };
  576. newMember("tTypeMemberField",1); // tmkField
  577. newMember("tTypeMemberMethod",2); // tmkMethod
  578. newMember("tTypeMemberProperty",3); // tmkProperty
  579. // base object for storing members: a simple object
  580. rtl.tTypeMembers = {};
  581. // tTypeInfoStruct - base object for tTypeInfoClass and tTypeInfoRecord
  582. var tis = newBaseTI("tTypeInfoStruct",0);
  583. tis.$addMember = function(name,ancestor,options){
  584. if (rtl.debug_rtti){
  585. if (!rtl.hasString(name) || (name.charAt()==='$')) throw 'invalid member "'+name+'", this="'+this.name+'"';
  586. if (!rtl.is(ancestor,rtl.tTypeMember)) throw 'invalid ancestor "'+ancestor+':'+ancestor.name+'", "'+this.name+'.'+name+'"';
  587. if ((options!=undefined) && (typeof(options)!='object')) throw 'invalid options "'+options+'", "'+this.name+'.'+name+'"';
  588. };
  589. var t = Object.create(ancestor);
  590. t.name = name;
  591. this.members[name] = t;
  592. this.names.push(name);
  593. if (rtl.isObject(options)){
  594. for (var key in options) if (options.hasOwnProperty(key)) t[key] = options[key];
  595. };
  596. return t;
  597. };
  598. tis.addField = function(name,type,options){
  599. var t = this.$addMember(name,rtl.tTypeMemberField,options);
  600. if (rtl.debug_rtti){
  601. if (!rtl.is(type,rtl.tTypeInfo)) throw 'invalid type "'+type+'", "'+this.name+'.'+name+'"';
  602. };
  603. t.typeinfo = type;
  604. this.fields.push(name);
  605. return t;
  606. };
  607. tis.addFields = function(){
  608. var i=0;
  609. while(i<arguments.length){
  610. var name = arguments[i++];
  611. var type = arguments[i++];
  612. if ((i<arguments.length) && (typeof(arguments[i])==='object')){
  613. this.addField(name,type,arguments[i++]);
  614. } else {
  615. this.addField(name,type);
  616. };
  617. };
  618. };
  619. tis.addMethod = function(name,methodkind,params,result,options){
  620. var t = this.$addMember(name,rtl.tTypeMemberMethod,options);
  621. t.methodkind = methodkind;
  622. t.procsig = rtl.newTIProcSig(params);
  623. t.procsig.resulttype = result?result:null;
  624. this.methods.push(name);
  625. return t;
  626. };
  627. tis.addProperty = function(name,flags,result,getter,setter,options){
  628. var t = this.$addMember(name,rtl.tTypeMemberProperty,options);
  629. t.flags = flags;
  630. t.typeinfo = result;
  631. t.getter = getter;
  632. t.setter = setter;
  633. // Note: in options: params, stored, defaultvalue
  634. if (rtl.isArray(t.params)) t.params = rtl.newTIParams(t.params);
  635. this.properties.push(name);
  636. if (!rtl.isString(t.stored)) t.stored = "";
  637. return t;
  638. };
  639. tis.getField = function(index){
  640. return this.members[this.fields[index]];
  641. };
  642. tis.getMethod = function(index){
  643. return this.members[this.methods[index]];
  644. };
  645. tis.getProperty = function(index){
  646. return this.members[this.properties[index]];
  647. };
  648. newBaseTI("tTypeInfoRecord",12 /* tkRecord */,rtl.tTypeInfoStruct);
  649. newBaseTI("tTypeInfoClass",13 /* tkClass */,rtl.tTypeInfoStruct);
  650. newBaseTI("tTypeInfoClassRef",14 /* tkClassRef */);
  651. },
  652. tSectionRTTI: {
  653. $module: null,
  654. $inherited: function(name,ancestor,o){
  655. if (rtl.debug_rtti){
  656. rtl.debug('tSectionRTTI.newTI "'+(this.$module?this.$module.$name:"(no module)")
  657. +'"."'+name+'" ('+ancestor.name+') '+(o?'init':'forward'));
  658. };
  659. var t = this[name];
  660. if (t){
  661. if (!t.$forward) throw 'duplicate type "'+name+'"';
  662. if (!ancestor.isPrototypeOf(t)) throw 'typeinfo ancestor mismatch "'+name+'" ancestor="'+ancestor.name+'" t.name="'+t.name+'"';
  663. } else {
  664. t = Object.create(ancestor);
  665. t.name = name;
  666. t.module = this.module;
  667. this[name] = t;
  668. }
  669. if (o){
  670. delete t.$forward;
  671. for (var key in o) if (o.hasOwnProperty(key)) t[key]=o[key];
  672. } else {
  673. t.$forward = true;
  674. }
  675. return t;
  676. },
  677. $Scope: function(name,ancestor,o){
  678. var t=this.$inherited(name,ancestor,o);
  679. t.members = {};
  680. t.names = [];
  681. t.fields = [];
  682. t.methods = [];
  683. t.properties = [];
  684. return t;
  685. },
  686. $TI: function(name,kind,o){ var t=this.$inherited(name,rtl.tTypeInfo,o); t.kind = kind; return t; },
  687. $Int: function(name,o){ return this.$inherited(name,rtl.tTypeInfoInteger,o); },
  688. $Enum: function(name,o){ return this.$inherited(name,rtl.tTypeInfoEnum,o); },
  689. $Set: function(name,o){ return this.$inherited(name,rtl.tTypeInfoSet,o); },
  690. $StaticArray: function(name,o){ return this.$inherited(name,rtl.tTypeInfoArray,o); },
  691. $DynArray: function(name,o){ return this.$inherited(name,rtl.tTypeInfoDynArray,o); },
  692. $ProcVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoProcVar,o); },
  693. $RefToProcVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoRefToProcVar,o); },
  694. $MethodVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoMethodVar,o); },
  695. $Record: function(name,o){ return this.$Scope(name,rtl.tTypeInfoRecord,o); },
  696. $Class: function(name,o){ return this.$Scope(name,rtl.tTypeInfoClass,o); },
  697. $ClassRef: function(name,o){ return this.$inherited(name,rtl.tTypeInfoClassRef,o); },
  698. $Pointer: function(name,o){ return this.$inherited(name,rtl.tTypeInfoPointer,o); },
  699. },
  700. newTIParam: function(param){
  701. // param is an array, 0=name, 1=type, 2=optional flags
  702. var t = {
  703. name: param[0],
  704. typeinfo: param[1],
  705. flags: (rtl.isNumber(param[2]) ? param[2] : 0),
  706. };
  707. return t;
  708. },
  709. newTIParams: function(list){
  710. // list: optional array of [paramname,typeinfo,optional flags]
  711. var params = [];
  712. if (rtl.isArray(list)){
  713. for (var i=0; i<list.length; i++) params.push(rtl.newTIParam(list[i]));
  714. };
  715. return params;
  716. },
  717. newTIProcSig: function(params,result,flags){
  718. var s = {
  719. params: rtl.newTIParams(params),
  720. resulttype: result,
  721. flags: flags
  722. };
  723. return s;
  724. },
  725. }