rtl.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  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. raiseEInvalidCast: function(){
  305. if (rtl.EInvalidCast){
  306. if (rtl.EInvalidCast.Create){
  307. throw rtl.EInvalidCast.$create("Create");
  308. } else {
  309. throw rtl.EInvalidCast.$create("create");
  310. }
  311. } else {
  312. throw "invalid type cast";
  313. }
  314. },
  315. as: function(instance,type){
  316. if((instance === null) || rtl.is(instance,type)) return instance;
  317. rtl.raiseEInvalidCast();
  318. },
  319. asExt: function(instance,type){
  320. if((instance === null) || rtl.isExt(instance,type)) return instance;
  321. rtl.raiseEInvalidCast();
  322. },
  323. checkMethodCall: function(obj,type){
  324. if (rtl.isObject(obj) && rtl.is(obj,type)) return;
  325. rtl.raiseEInvalidCast();
  326. },
  327. length: function(arr){
  328. return (arr == null) ? 0 : arr.length;
  329. },
  330. arraySetLength: function(arr,defaultvalue,newlength){
  331. // multi dim: (arr,defaultvalue,dim1,dim2,...)
  332. if (arr == null) arr = [];
  333. var p = arguments;
  334. function setLength(a,argNo){
  335. var oldlen = a.length;
  336. var newlen = p[argNo];
  337. if (oldlen!==newlength){
  338. a.length = newlength;
  339. if (argNo === p.length-1){
  340. if (rtl.isArray(defaultvalue)){
  341. for (var i=oldlen; i<newlen; i++) a[i]=[]; // nested array
  342. } else if (rtl.isFunction(defaultvalue)){
  343. for (var i=oldlen; i<newlen; i++) a[i]=new defaultvalue(); // e.g. record
  344. } else if (rtl.isObject(defaultvalue)) {
  345. for (var i=oldlen; i<newlen; i++) a[i]={}; // e.g. set
  346. } else {
  347. for (var i=oldlen; i<newlen; i++) a[i]=defaultvalue;
  348. }
  349. } else {
  350. for (var i=oldlen; i<newlen; i++) a[i]=[]; // nested array
  351. }
  352. }
  353. if (argNo < p.length-1){
  354. // multi argNo
  355. for (var i=0; i<newlen; i++) a[i]=setLength(a[i],argNo+1);
  356. }
  357. return a;
  358. }
  359. return setLength(arr,2);
  360. },
  361. arrayClone: function(type,src,srcpos,end,dst,dstpos){
  362. // type: 0 for references, "refset" for calling refSet(), a function for new type()
  363. // src must not be null
  364. // This function does not range check.
  365. if (rtl.isFunction(type)){
  366. for (; srcpos<end; srcpos++) dst[dstpos++] = new type(src[srcpos]); // clone record
  367. } else if(isString(type) && (type === 'refSet')) {
  368. for (; srcpos<end; srcpos++) dst[dstpos++] = refSet(src[srcpos]); // ref set
  369. } else {
  370. for (; srcpos<end; srcpos++) dst[dstpos++] = src[srcpos]; // reference
  371. };
  372. },
  373. arrayConcat: function(type){
  374. // type: see rtl.arrayClone
  375. var a = [];
  376. var l = 0;
  377. for (var i=1; i<arguments.length; i++) l+=arguments[i].length;
  378. a.length = l;
  379. l=0;
  380. for (var i=1; i<arguments.length; i++){
  381. var src = arguments[i];
  382. if (src == null) continue;
  383. rtl.arrayClone(type,src,0,src.length,a,l);
  384. l+=src.length;
  385. };
  386. return a;
  387. },
  388. arrayCopy: function(type, srcarray, index, count){
  389. // type: see rtl.arrayClone
  390. // if count is missing, use srcarray.length
  391. if (srcarray == null) return [];
  392. if (index < 0) index = 0;
  393. if (count === undefined) count=srcarray.length;
  394. var end = index+count;
  395. if (end>scrarray.length) end = scrarray.length;
  396. if (index>=end) return [];
  397. if (type===0){
  398. return srcarray.slice(index,end);
  399. } else {
  400. var a = [];
  401. a.length = end-index;
  402. rtl.arrayClone(type,srcarray,index,end,a,0);
  403. return a;
  404. }
  405. },
  406. setCharAt: function(s,index,c){
  407. return s.substr(0,index)+c+s.substr(index+1);
  408. },
  409. getResStr: function(mod,name){
  410. var rs = mod.$resourcestrings[name];
  411. return rs.current?rs.current:rs.org;
  412. },
  413. createSet: function(){
  414. var s = {};
  415. for (var i=0; i<arguments.length; i++){
  416. if (arguments[i]!=null){
  417. s[arguments[i]]=true;
  418. } else {
  419. var first=arguments[i+=1];
  420. var last=arguments[i+=1];
  421. for(var j=first; j<=last; j++) s[j]=true;
  422. }
  423. }
  424. return s;
  425. },
  426. cloneSet: function(s){
  427. var r = {};
  428. for (var key in s) r[key]=true;
  429. return r;
  430. },
  431. refSet: function(s){
  432. s.$shared = true;
  433. return s;
  434. },
  435. includeSet: function(s,enumvalue){
  436. if (s.$shared) s = cloneSet(s);
  437. s[enumvalue] = true;
  438. return s;
  439. },
  440. excludeSet: function(s,enumvalue){
  441. if (s.$shared) s = cloneSet(s);
  442. delete s[enumvalue];
  443. return s;
  444. },
  445. diffSet: function(s,t){
  446. var r = {};
  447. for (var key in s) if (!t[key]) r[key]=true;
  448. delete r.$shared;
  449. return r;
  450. },
  451. unionSet: function(s,t){
  452. var r = {};
  453. for (var key in s) r[key]=true;
  454. for (var key in t) r[key]=true;
  455. delete r.$shared;
  456. return r;
  457. },
  458. intersectSet: function(s,t){
  459. var r = {};
  460. for (var key in s) if (t[key]) r[key]=true;
  461. delete r.$shared;
  462. return r;
  463. },
  464. symDiffSet: function(s,t){
  465. var r = {};
  466. for (var key in s) if (!t[key]) r[key]=true;
  467. for (var key in t) if (!s[key]) r[key]=true;
  468. delete r.$shared;
  469. return r;
  470. },
  471. eqSet: function(s,t){
  472. for (var key in s) if (!t[key] && (key!='$shared')) return false;
  473. for (var key in t) if (!s[key] && (key!='$shared')) return false;
  474. return true;
  475. },
  476. neSet: function(s,t){
  477. return !rtl.eqSet(s,t);
  478. },
  479. leSet: function(s,t){
  480. for (var key in s) if (!t[key] && (key!='$shared')) return false;
  481. return true;
  482. },
  483. geSet: function(s,t){
  484. for (var key in t) if (!s[key] && (key!='$shared')) return false;
  485. return true;
  486. },
  487. strSetLength: function(s,newlen){
  488. var oldlen = s.length;
  489. if (oldlen > newlen){
  490. return s.substring(0,newlen);
  491. } else if (s.repeat){
  492. // Note: repeat needs ECMAScript6!
  493. return s+' '.repeat(newlen-oldlen);
  494. } else {
  495. while (oldlen<newlen){
  496. s+=' ';
  497. oldlen++;
  498. };
  499. return s;
  500. }
  501. },
  502. spaceLeft: function(s,width){
  503. var l=s.length;
  504. if (l>=width) return s;
  505. if (s.repeat){
  506. // Note: repeat needs ECMAScript6!
  507. return ' '.repeat(width-l) + s;
  508. } else {
  509. while (l<width){
  510. s=' '+s;
  511. l++;
  512. };
  513. };
  514. },
  515. floatToStr : function(d,w,p){
  516. // input 1-3 arguments: double, width, precision
  517. if (arguments.length>2){
  518. return rtl.spaceLeft(d.toFixed(p),w);
  519. } else {
  520. // exponent width
  521. var pad = "";
  522. var ad = Math.abs(d);
  523. if (ad<1.0e+10) {
  524. pad='00';
  525. } else if (ad<1.0e+100) {
  526. pad='0';
  527. }
  528. if (arguments.length<2) {
  529. w=9;
  530. } else if (w<9) {
  531. w=9;
  532. }
  533. var p = w-8;
  534. var s=(d>0 ? " " : "" ) + d.toExponential(p);
  535. s=s.replace(/e(.)/,'E$1'+pad);
  536. return rtl.spaceLeft(s,w);
  537. }
  538. },
  539. initRTTI: function(){
  540. if (rtl.debug_rtti) rtl.debug('initRTTI');
  541. // base types
  542. rtl.tTypeInfo = { name: "tTypeInfo" };
  543. function newBaseTI(name,kind,ancestor){
  544. if (!ancestor) ancestor = rtl.tTypeInfo;
  545. if (rtl.debug_rtti) rtl.debug('initRTTI.newBaseTI "'+name+'" '+kind+' ("'+ancestor.name+'")');
  546. var t = Object.create(ancestor);
  547. t.name = name;
  548. t.kind = kind;
  549. rtl[name] = t;
  550. return t;
  551. };
  552. function newBaseInt(name,minvalue,maxvalue,ordtype){
  553. var t = newBaseTI(name,1 /* tkInteger */,rtl.tTypeInfoInteger);
  554. t.minvalue = minvalue;
  555. t.maxvalue = maxvalue;
  556. t.ordtype = ordtype;
  557. return t;
  558. };
  559. newBaseTI("tTypeInfoInteger",1 /* tkInteger */);
  560. newBaseInt("shortint",-0x80,0x7f,0);
  561. newBaseInt("byte",0,0xff,1);
  562. newBaseInt("smallint",-0x8000,0x7fff,2);
  563. newBaseInt("word",0,0xffff,3);
  564. newBaseInt("longint",-0x80000000,0x7fffffff,4);
  565. newBaseInt("longword",0,0xffffffff,5);
  566. newBaseInt("nativeint",-0x10000000000000,0xfffffffffffff,6);
  567. newBaseInt("nativeuint",0,0xfffffffffffff,7);
  568. newBaseTI("char",2 /* tkChar */);
  569. newBaseTI("string",3 /* tkString */);
  570. newBaseTI("tTypeInfoEnum",4 /* tkEnumeration */,rtl.tTypeInfoInteger);
  571. newBaseTI("tTypeInfoSet",5 /* tkSet */);
  572. newBaseTI("double",6 /* tkDouble */);
  573. newBaseTI("boolean",7 /* tkBool */);
  574. newBaseTI("tTypeInfoProcVar",8 /* tkProcVar */);
  575. newBaseTI("tTypeInfoMethodVar",9 /* tkMethod */,rtl.tTypeInfoProcVar);
  576. newBaseTI("tTypeInfoArray",10 /* tkArray */);
  577. newBaseTI("tTypeInfoDynArray",11 /* tkDynArray */);
  578. newBaseTI("tTypeInfoPointer",15 /* tkPointer */);
  579. var t = newBaseTI("pointer",15 /* tkPointer */,rtl.tTypeInfoPointer);
  580. t.reftype = null;
  581. newBaseTI("jsvalue",16 /* tkJSValue */);
  582. newBaseTI("tTypeInfoRefToProcVar",17 /* tkRefToProcVar */,rtl.tTypeInfoProcVar);
  583. // member kinds
  584. rtl.tTypeMember = {};
  585. function newMember(name,kind){
  586. var m = Object.create(rtl.tTypeMember);
  587. m.name = name;
  588. m.kind = kind;
  589. rtl[name] = m;
  590. };
  591. newMember("tTypeMemberField",1); // tmkField
  592. newMember("tTypeMemberMethod",2); // tmkMethod
  593. newMember("tTypeMemberProperty",3); // tmkProperty
  594. // base object for storing members: a simple object
  595. rtl.tTypeMembers = {};
  596. // tTypeInfoStruct - base object for tTypeInfoClass and tTypeInfoRecord
  597. var tis = newBaseTI("tTypeInfoStruct",0);
  598. tis.$addMember = function(name,ancestor,options){
  599. if (rtl.debug_rtti){
  600. if (!rtl.hasString(name) || (name.charAt()==='$')) throw 'invalid member "'+name+'", this="'+this.name+'"';
  601. if (!rtl.is(ancestor,rtl.tTypeMember)) throw 'invalid ancestor "'+ancestor+':'+ancestor.name+'", "'+this.name+'.'+name+'"';
  602. if ((options!=undefined) && (typeof(options)!='object')) throw 'invalid options "'+options+'", "'+this.name+'.'+name+'"';
  603. };
  604. var t = Object.create(ancestor);
  605. t.name = name;
  606. this.members[name] = t;
  607. this.names.push(name);
  608. if (rtl.isObject(options)){
  609. for (var key in options) if (options.hasOwnProperty(key)) t[key] = options[key];
  610. };
  611. return t;
  612. };
  613. tis.addField = function(name,type,options){
  614. var t = this.$addMember(name,rtl.tTypeMemberField,options);
  615. if (rtl.debug_rtti){
  616. if (!rtl.is(type,rtl.tTypeInfo)) throw 'invalid type "'+type+'", "'+this.name+'.'+name+'"';
  617. };
  618. t.typeinfo = type;
  619. this.fields.push(name);
  620. return t;
  621. };
  622. tis.addFields = function(){
  623. var i=0;
  624. while(i<arguments.length){
  625. var name = arguments[i++];
  626. var type = arguments[i++];
  627. if ((i<arguments.length) && (typeof(arguments[i])==='object')){
  628. this.addField(name,type,arguments[i++]);
  629. } else {
  630. this.addField(name,type);
  631. };
  632. };
  633. };
  634. tis.addMethod = function(name,methodkind,params,result,options){
  635. var t = this.$addMember(name,rtl.tTypeMemberMethod,options);
  636. t.methodkind = methodkind;
  637. t.procsig = rtl.newTIProcSig(params);
  638. t.procsig.resulttype = result?result:null;
  639. this.methods.push(name);
  640. return t;
  641. };
  642. tis.addProperty = function(name,flags,result,getter,setter,options){
  643. var t = this.$addMember(name,rtl.tTypeMemberProperty,options);
  644. t.flags = flags;
  645. t.typeinfo = result;
  646. t.getter = getter;
  647. t.setter = setter;
  648. // Note: in options: params, stored, defaultvalue
  649. if (rtl.isArray(t.params)) t.params = rtl.newTIParams(t.params);
  650. this.properties.push(name);
  651. if (!rtl.isString(t.stored)) t.stored = "";
  652. return t;
  653. };
  654. tis.getField = function(index){
  655. return this.members[this.fields[index]];
  656. };
  657. tis.getMethod = function(index){
  658. return this.members[this.methods[index]];
  659. };
  660. tis.getProperty = function(index){
  661. return this.members[this.properties[index]];
  662. };
  663. newBaseTI("tTypeInfoRecord",12 /* tkRecord */,rtl.tTypeInfoStruct);
  664. newBaseTI("tTypeInfoClass",13 /* tkClass */,rtl.tTypeInfoStruct);
  665. newBaseTI("tTypeInfoClassRef",14 /* tkClassRef */);
  666. },
  667. tSectionRTTI: {
  668. $module: null,
  669. $inherited: function(name,ancestor,o){
  670. if (rtl.debug_rtti){
  671. rtl.debug('tSectionRTTI.newTI "'+(this.$module?this.$module.$name:"(no module)")
  672. +'"."'+name+'" ('+ancestor.name+') '+(o?'init':'forward'));
  673. };
  674. var t = this[name];
  675. if (t){
  676. if (!t.$forward) throw 'duplicate type "'+name+'"';
  677. if (!ancestor.isPrototypeOf(t)) throw 'typeinfo ancestor mismatch "'+name+'" ancestor="'+ancestor.name+'" t.name="'+t.name+'"';
  678. } else {
  679. t = Object.create(ancestor);
  680. t.name = name;
  681. t.module = this.module;
  682. this[name] = t;
  683. }
  684. if (o){
  685. delete t.$forward;
  686. for (var key in o) if (o.hasOwnProperty(key)) t[key]=o[key];
  687. } else {
  688. t.$forward = true;
  689. }
  690. return t;
  691. },
  692. $Scope: function(name,ancestor,o){
  693. var t=this.$inherited(name,ancestor,o);
  694. t.members = {};
  695. t.names = [];
  696. t.fields = [];
  697. t.methods = [];
  698. t.properties = [];
  699. return t;
  700. },
  701. $TI: function(name,kind,o){ var t=this.$inherited(name,rtl.tTypeInfo,o); t.kind = kind; return t; },
  702. $Int: function(name,o){ return this.$inherited(name,rtl.tTypeInfoInteger,o); },
  703. $Enum: function(name,o){ return this.$inherited(name,rtl.tTypeInfoEnum,o); },
  704. $Set: function(name,o){ return this.$inherited(name,rtl.tTypeInfoSet,o); },
  705. $StaticArray: function(name,o){ return this.$inherited(name,rtl.tTypeInfoArray,o); },
  706. $DynArray: function(name,o){ return this.$inherited(name,rtl.tTypeInfoDynArray,o); },
  707. $ProcVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoProcVar,o); },
  708. $RefToProcVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoRefToProcVar,o); },
  709. $MethodVar: function(name,o){ return this.$inherited(name,rtl.tTypeInfoMethodVar,o); },
  710. $Record: function(name,o){ return this.$Scope(name,rtl.tTypeInfoRecord,o); },
  711. $Class: function(name,o){ return this.$Scope(name,rtl.tTypeInfoClass,o); },
  712. $ClassRef: function(name,o){ return this.$inherited(name,rtl.tTypeInfoClassRef,o); },
  713. $Pointer: function(name,o){ return this.$inherited(name,rtl.tTypeInfoPointer,o); },
  714. },
  715. newTIParam: function(param){
  716. // param is an array, 0=name, 1=type, 2=optional flags
  717. var t = {
  718. name: param[0],
  719. typeinfo: param[1],
  720. flags: (rtl.isNumber(param[2]) ? param[2] : 0),
  721. };
  722. return t;
  723. },
  724. newTIParams: function(list){
  725. // list: optional array of [paramname,typeinfo,optional flags]
  726. var params = [];
  727. if (rtl.isArray(list)){
  728. for (var i=0; i<list.length; i++) params.push(rtl.newTIParam(list[i]));
  729. };
  730. return params;
  731. },
  732. newTIProcSig: function(params,result,flags){
  733. var s = {
  734. params: rtl.newTIParams(params),
  735. resulttype: result,
  736. flags: flags
  737. };
  738. return s;
  739. },
  740. }